diff --git a/account-query/README.md b/account-query/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..7c8bd539abd083ec98cbae1526e1436d327c8ed9
--- /dev/null
+++ b/account-query/README.md
@@ -0,0 +1,6 @@
+# PA165 Balance Service
+
+<p>The Balance Service, allows to view transaction history, provides a dashboard for bank employees to monitor all customers bank transactions. The system also provides a statistical module for employees, which can report total and average (per account) transactions (deposits, withdrawals, outgoing and incoming payments) in a selected date range.</p>
+
+![diagram](diagram.png)
+
diff --git a/account-query/diagram.png b/account-query/diagram.png
new file mode 100644
index 0000000000000000000000000000000000000000..fb05707fb91b8e4d27d85cb443b10541edf1bb35
Binary files /dev/null and b/account-query/diagram.png differ
diff --git a/account-query/pom.xml b/account-query/pom.xml
index f7ef897cf77074da1db38d9bf40e84cd0e818542..77e9c70e69d3f7b410d7dcb46d92fafee15c9fd1 100644
--- a/account-query/pom.xml
+++ b/account-query/pom.xml
@@ -4,6 +4,13 @@
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
 
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>3.2.4</version>
+        <relativePath/>
+    </parent>
+
     <groupId>cz.muni.pa165.banking</groupId>
     <artifactId>account-query</artifactId>
     <version>1.0-SNAPSHOT</version>
@@ -12,6 +19,120 @@
         <maven.compiler.source>21</maven.compiler.source>
         <maven.compiler.target>21</maven.compiler.target>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+
+        <spring.version>3.2.4</spring.version>
+        <org.mapstruct.version>1.5.5.Final</org.mapstruct.version>
     </properties>
 
+    <build>
+        <finalName>server_generated</finalName>
+
+        <plugins>
+            <plugin>
+                <groupId>org.openapitools</groupId>
+                <artifactId>openapi-generator-maven-plugin</artifactId>
+                <version>7.4.0</version>
+                <executions>
+                    <execution>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>generate</goal>
+                        </goals>
+                        <configuration>
+                            <inputSpec>${project.basedir}/src/main/resources/openapi.yaml</inputSpec>
+                            <generatorName>spring</generatorName>
+                            <apiPackage>cz.muni.pa165.banking.account.query</apiPackage>
+                            <modelPackage>cz.muni.pa165.banking.account.query.dto</modelPackage>
+                            <library>spring-boot</library>
+                            <configOptions>
+                                <useTags>true</useTags>
+                                <interfaceOnly>true</interfaceOnly>
+                                <skipDefaultInterface>true</skipDefaultInterface>
+                                <openApiNullable>false</openApiNullable>
+                                <documentationProvider>none</documentationProvider>
+                                <useSpringBoot3>true</useSpringBoot3>
+                            </configOptions>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.springdoc</groupId>
+                <artifactId>springdoc-openapi-maven-plugin</artifactId>
+                <version>1.4</version>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>${maven-compiler-plugin.version}</version>
+                <configuration>
+                    <annotationProcessorPaths>
+                        <path>
+                            <groupId>org.mapstruct</groupId>
+                            <artifactId>mapstruct-processor</artifactId>
+                            <version>${org.mapstruct.version}</version>
+                        </path>
+                    </annotationProcessorPaths>
+                    <showWarnings>true</showWarnings>
+                    <compilerArgs>
+                        <arg>-Amapstruct.unmappedTargetPolicy=ERROR</arg>
+                        <arg>-Amapstruct.unmappedSourcePolicy=ERROR</arg>
+                        <arg>-Amapstruct.verbose=true</arg>
+                    </compilerArgs>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                    <executable>true</executable>
+                </configuration>
+            </plugin>
+            <!-- run integration tests in "mvn verify" phase -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-failsafe-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-quartz</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.mapstruct</groupId>
+            <artifactId>mapstruct</artifactId>
+            <version>${org.mapstruct.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springdoc</groupId>
+            <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
+            <version>2.3.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.openapitools</groupId>
+            <artifactId>jackson-databind-nullable</artifactId>
+            <version>0.2.6</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-beans</artifactId>
+            <version>6.1.5</version>
+        </dependency>
+    </dependencies>
+
 </project>
\ No newline at end of file
diff --git a/account-query/src/main/java/cz/muni/pa165/banking/Main.java b/account-query/src/main/java/cz/muni/pa165/banking/Main.java
index f1b42c431db95159a9954acf5512dca812a6186a..b64e4d22b453938005cbd4402862d932ec2c4167 100644
--- a/account-query/src/main/java/cz/muni/pa165/banking/Main.java
+++ b/account-query/src/main/java/cz/muni/pa165/banking/Main.java
@@ -1,7 +1,11 @@
 package cz.muni.pa165.banking;
 
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
 public class Main {
     public static void main(String[] args) {
-        System.out.println("Hello world!");
+        SpringApplication.run(Main.class, args);
     }
 }
\ No newline at end of file
diff --git a/account-query/src/main/java/cz/muni/pa165/banking/application/controller/BalanceController.java b/account-query/src/main/java/cz/muni/pa165/banking/application/controller/BalanceController.java
new file mode 100644
index 0000000000000000000000000000000000000000..1541bee756261982f3ab0f66b318c43059d4162f
--- /dev/null
+++ b/account-query/src/main/java/cz/muni/pa165/banking/application/controller/BalanceController.java
@@ -0,0 +1,52 @@
+package cz.muni.pa165.banking.application.controller;
+
+import cz.muni.pa165.banking.account.query.CustomerServiceApi;
+import cz.muni.pa165.banking.account.query.SystemServiceApi;
+import cz.muni.pa165.banking.account.query.dto.Transaction;
+import cz.muni.pa165.banking.account.query.dto.TransactionType;
+import cz.muni.pa165.banking.application.facade.BalanceFacade;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.util.List;
+import java.util.UUID;
+
+/**
+ * @author Martin Mojzis
+ */
+@RestController
+public class BalanceController implements CustomerServiceApi, SystemServiceApi {
+
+    private final BalanceFacade balanceFacade;
+
+    public BalanceController(BalanceFacade balanceFacade) {
+        this.balanceFacade = balanceFacade;
+    }
+
+    @Override
+    public ResponseEntity<BigDecimal> getBalance(String id) {
+        BigDecimal result = balanceFacade.getBalance(id);
+        return ResponseEntity.ok(result);
+    }
+
+    @Override
+    public ResponseEntity<List<Transaction>> getTransactions(String id, LocalDate beginning, LocalDate end, BigDecimal minAmount, BigDecimal maxAmount, TransactionType type) {
+        List<Transaction> toReturn = balanceFacade.getTransactions(id, beginning, end, minAmount, maxAmount, type);
+        return ResponseEntity.ok(toReturn);
+    }
+
+    @Override
+    public ResponseEntity<Void> addTransactionToBalance(String id, BigDecimal amount, UUID processId, TransactionType type) {
+        balanceFacade.addToBalance(id, processId, amount, type);
+        return ResponseEntity.ok().build();
+    }
+
+    @Override
+    public ResponseEntity<Void> createBalance(String id) {
+        balanceFacade.createNewBalance(id);
+        return new ResponseEntity<>(HttpStatus.CREATED);
+    }
+}
diff --git a/account-query/src/main/java/cz/muni/pa165/banking/application/controller/BalanceControllerEmployee.java b/account-query/src/main/java/cz/muni/pa165/banking/application/controller/BalanceControllerEmployee.java
new file mode 100644
index 0000000000000000000000000000000000000000..8d4cf49b9e2debce13e46b7a5c7f83ea75c2e332
--- /dev/null
+++ b/account-query/src/main/java/cz/muni/pa165/banking/application/controller/BalanceControllerEmployee.java
@@ -0,0 +1,39 @@
+package cz.muni.pa165.banking.application.controller;
+
+import cz.muni.pa165.banking.account.query.EmployeeServiceApi;
+import cz.muni.pa165.banking.account.query.dto.Transaction;
+import cz.muni.pa165.banking.account.query.dto.TransactionType;
+import cz.muni.pa165.banking.account.query.dto.TransactionsReport;
+import cz.muni.pa165.banking.application.facade.BalanceFacade;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.util.List;
+
+/**
+ * @author Martin Mojzis
+ */
+@RestController
+public class BalanceControllerEmployee implements EmployeeServiceApi {
+
+    private final BalanceFacade balanceFacade;
+
+    public BalanceControllerEmployee(BalanceFacade balanceFacade) {
+        this.balanceFacade = balanceFacade;
+    }
+
+    @Override
+    public ResponseEntity<TransactionsReport> createReport(String id, LocalDate beginning, LocalDate end) {
+        TransactionsReport result = balanceFacade.getReport(id, beginning, end);
+        return ResponseEntity.ok(result);
+    }
+
+    @Override
+    public ResponseEntity<List<Transaction>> getAllTransactions(LocalDate beginning, LocalDate end,
+                                                                BigDecimal minAmount, BigDecimal maxAmount, TransactionType type) {
+        List<Transaction> result = balanceFacade.getAllTransactions(beginning, end, minAmount, maxAmount, type);
+        return ResponseEntity.ok(result);
+    }
+}
diff --git a/account-query/src/main/java/cz/muni/pa165/banking/application/exception/NotFoundAccountException.java b/account-query/src/main/java/cz/muni/pa165/banking/application/exception/NotFoundAccountException.java
new file mode 100644
index 0000000000000000000000000000000000000000..f82452ba924c491cf3279094104c787bac666e4a
--- /dev/null
+++ b/account-query/src/main/java/cz/muni/pa165/banking/application/exception/NotFoundAccountException.java
@@ -0,0 +1,11 @@
+package cz.muni.pa165.banking.application.exception;
+
+/**
+ * @author Martin Mojzis
+ */
+public class NotFoundAccountException extends RuntimeException{
+    public NotFoundAccountException(String message) {
+        super(message);
+    }
+
+}
diff --git a/account-query/src/main/java/cz/muni/pa165/banking/application/exception/RestApiExceptionHandler.java b/account-query/src/main/java/cz/muni/pa165/banking/application/exception/RestApiExceptionHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..a2b6023472a40b9feb804a3a79c2661054b437de
--- /dev/null
+++ b/account-query/src/main/java/cz/muni/pa165/banking/application/exception/RestApiExceptionHandler.java
@@ -0,0 +1,19 @@
+package cz.muni.pa165.banking.application.exception;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.context.request.WebRequest;
+
+/**
+ * @author Martin Mojzis
+ */
+@ControllerAdvice
+public class RestApiExceptionHandler {
+    @ExceptionHandler(NotFoundAccountException.class)
+    public ResponseEntity<Object> handleNotFoundAccount(Exception e, WebRequest request){
+        return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);
+    }
+}
diff --git a/account-query/src/main/java/cz/muni/pa165/banking/application/facade/BalanceFacade.java b/account-query/src/main/java/cz/muni/pa165/banking/application/facade/BalanceFacade.java
new file mode 100644
index 0000000000000000000000000000000000000000..b89d717c93695ce038e443d9074139c606191177
--- /dev/null
+++ b/account-query/src/main/java/cz/muni/pa165/banking/application/facade/BalanceFacade.java
@@ -0,0 +1,68 @@
+package cz.muni.pa165.banking.application.facade;
+
+import cz.muni.pa165.banking.account.query.dto.Transaction;
+import cz.muni.pa165.banking.account.query.dto.TransactionType;
+import cz.muni.pa165.banking.account.query.dto.TransactionsReport;
+import cz.muni.pa165.banking.application.exception.NotFoundAccountException;
+import cz.muni.pa165.banking.application.mapper.BalanceMapper;
+import cz.muni.pa165.banking.domain.balance.service.BalanceService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.OffsetDateTime;
+import java.time.ZoneOffset;
+import java.util.List;
+import java.util.UUID;
+
+/**
+ * @author Martin Mojzis
+ */
+@Service
+public class BalanceFacade {
+
+    private final BalanceService balanceService;
+    private final BalanceMapper balanceMapper;
+
+    public BalanceFacade(BalanceService balanceService, BalanceMapper balanceMapper) {
+        this.balanceService = balanceService;
+        this.balanceMapper = balanceMapper;
+    }
+
+    public void createNewBalance(String id) throws NotFoundAccountException {
+        balanceService.addNewBalance(id);
+    }
+
+    public void addToBalance(String id, UUID processId, BigDecimal value, TransactionType type) {
+        balanceService.addToBalance(id, value, processId, balanceMapper.mapTypeOut(type));
+    }
+
+    public BigDecimal getBalance(String id) throws NotFoundAccountException {
+        return balanceService.getBalance(id);
+    }
+
+    public List<Transaction> getTransactions(String id, LocalDate beginning, LocalDate end, BigDecimal minAmount,
+                                             BigDecimal maxAmount, TransactionType type) {
+        List<cz.muni.pa165.banking.domain.transaction.Transaction> toReturn;
+        toReturn = balanceService.getTransactions(id, OffsetDateTime.of(beginning, LocalTime.MIDNIGHT, ZoneOffset.UTC), OffsetDateTime.of(end, LocalTime.MIDNIGHT, ZoneOffset.UTC),
+                minAmount, maxAmount, balanceMapper.mapTypeOut(type));
+        return toReturn.stream().map(balanceMapper::mapTransactionIn).toList();
+    }
+
+    public TransactionsReport getReport(String id, LocalDate beginning, LocalDate end) {
+        return balanceMapper.mapReportOut(balanceService.getReport(id,
+                OffsetDateTime.of(beginning, LocalTime.MIDNIGHT, ZoneOffset.UTC),
+                OffsetDateTime.of(end, LocalTime.MIDNIGHT, ZoneOffset.UTC)));
+    }
+
+    public List<Transaction> getAllTransactions(LocalDate beginning, LocalDate end, BigDecimal minAmount,
+                                                BigDecimal maxAmount, TransactionType type) {
+        List<cz.muni.pa165.banking.domain.transaction.Transaction> toReturn =
+                balanceService.getAllTransactions(OffsetDateTime.of(beginning, LocalTime.MIDNIGHT, ZoneOffset.UTC), OffsetDateTime.of(end, LocalTime.MIDNIGHT, ZoneOffset.UTC), minAmount, maxAmount,
+                        balanceMapper.mapTypeOut(type));
+        return toReturn.stream().map(balanceMapper::mapTransactionIn).toList();
+    }
+
+}
diff --git a/account-query/src/main/java/cz/muni/pa165/banking/application/mapper/BalanceMapper.java b/account-query/src/main/java/cz/muni/pa165/banking/application/mapper/BalanceMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..be5214fe6dd63625c321ffa0b7b5d3451cb99f1f
--- /dev/null
+++ b/account-query/src/main/java/cz/muni/pa165/banking/application/mapper/BalanceMapper.java
@@ -0,0 +1,76 @@
+package cz.muni.pa165.banking.application.mapper;
+
+import cz.muni.pa165.banking.account.query.dto.Transaction;
+import cz.muni.pa165.banking.account.query.dto.TransactionStatistics;
+import cz.muni.pa165.banking.account.query.dto.TransactionsReport;
+import cz.muni.pa165.banking.domain.report.StatisticalReport;
+import cz.muni.pa165.banking.domain.transaction.TransactionType;
+import org.mapstruct.InjectionStrategy;
+import org.mapstruct.Mapper;
+import org.mapstruct.MappingConstants;
+import org.mapstruct.NullValuePropertyMappingStrategy;
+
+import java.math.BigDecimal;
+import java.time.ZoneOffset;
+import java.util.Date;
+
+/**
+ * @author Martin Mojzis
+ */
+@Mapper(componentModel = MappingConstants.ComponentModel.SPRING, injectionStrategy = InjectionStrategy.CONSTRUCTOR,
+        nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
+public interface BalanceMapper {
+    TransactionType mapTypeOut(cz.muni.pa165.banking.account.query.dto.TransactionType type);
+    cz.muni.pa165.banking.account.query.dto.TransactionType mapTypeIn(TransactionType type);
+    default java.util.Date mapDateIn(java.time.@jakarta.validation.Valid OffsetDateTime value) {
+        return new Date(value.toInstant().toEpochMilli());
+    }
+
+    default java.time.OffsetDateTime mapDate(java.util.Date date) {
+        return date.toInstant().atOffset(ZoneOffset.UTC);
+    }
+
+    default cz.muni.pa165.banking.domain.transaction.Transaction mapTransactionOut(Transaction transaction) {
+        return new
+                cz.muni.pa165.banking.domain.transaction.Transaction(mapTypeOut(transaction.getTransactionType()),
+                transaction.getAmount(), transaction.getDate(), transaction.getProcessId());
+    }
+    default Transaction mapTransactionIn(cz.muni.pa165.banking.domain.transaction.Transaction transaction){
+        Transaction result = new Transaction();
+        result.setAmount(transaction.getAmount());
+        result.setDate(transaction.getDate());
+        result.setProcessId(transaction.getProcessId());
+        result.setTransactionType(mapTypeIn(transaction.getType()));
+        return result;
+    }
+    default TransactionStatistics mapStatisticsOut(cz.muni.pa165.banking.domain.report.TransactionStatistics statistics){
+        TransactionStatistics result = new TransactionStatistics();
+        result.setTransactionType(mapTypeIn(statistics.getType()));
+        result.setAmountOut(statistics.getAmountOut());
+        result.setTimesOut(BigDecimal.valueOf(statistics.getTimesOut()));
+        result.setAmountIn(statistics.getAmountIn());
+        result.setTimesIn(BigDecimal.valueOf(statistics.getTimesIn()));
+        if(statistics.getTimesOut() != 0) {
+            result.setAvgOut(statistics.getAmountOut().divide(new BigDecimal(statistics.getTimesOut())));
+        }
+        else{
+            result.setAvgOut(BigDecimal.ZERO);
+        }
+        if(statistics.getTimesIn() != 0) {
+            result.setAvgIn(statistics.getAmountIn().divide(new BigDecimal(statistics.getTimesIn())));
+        }
+        else{
+            result.setAvgIn(BigDecimal.ZERO);
+        }
+        return result;
+    }
+    default TransactionsReport mapReportOut(StatisticalReport report){
+        TransactionsReport result = new TransactionsReport();
+        result.setCreditAmount(mapStatisticsOut(report.getCreditAmount()));
+        result.setDepositAmount(mapStatisticsOut(report.getDepositAmount()));
+        result.setTotalAmount(mapStatisticsOut(report.getTotalAmount()));
+        result.setWithdrawalAmount(mapStatisticsOut(report.getWithdrawalAmount()));
+        result.setCrossAccountAmount(mapStatisticsOut(report.getCrossAccountAmount()));
+        return result;
+    }
+}
diff --git a/account-query/src/main/java/cz/muni/pa165/banking/application/repository/BalancesRepositoryImpl.java b/account-query/src/main/java/cz/muni/pa165/banking/application/repository/BalancesRepositoryImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..23bbcdddd01f709dc9bfdfcd32b38d26efb33e3c
--- /dev/null
+++ b/account-query/src/main/java/cz/muni/pa165/banking/application/repository/BalancesRepositoryImpl.java
@@ -0,0 +1,45 @@
+package cz.muni.pa165.banking.application.repository;
+
+import cz.muni.pa165.banking.domain.balance.Balance;
+import cz.muni.pa165.banking.domain.balance.repository.BalancesRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * @author Martin Mojzis
+ */
+@Repository
+public class BalancesRepositoryImpl implements BalancesRepository {
+
+    private final Map<String, Balance> mockData = new HashMap<>();
+
+    public BalancesRepositoryImpl() {
+        mockData.put("id1", new Balance("id1"));
+        mockData.put("id2", new Balance("id2"));
+    }
+
+    //@Transactional
+    @Override
+    public Optional<Balance> findById(String id) {
+        if (mockData.containsKey(id)) {
+            return Optional.of(mockData.get(id));
+        }
+        return Optional.empty();
+    }
+
+    @Override
+    public List<String> getAllIds() {
+        return mockData.keySet().stream().toList();
+    }
+
+
+    //@Transactional
+    @Override
+    public void addBalance(String id) {
+        mockData.put(id, new Balance(id));
+    }
+}
diff --git a/account-query/src/main/java/cz/muni/pa165/banking/application/service/BalanceServiceImpl.java b/account-query/src/main/java/cz/muni/pa165/banking/application/service/BalanceServiceImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..b8437551ccca8cbcc81fdd53ba4d765ed9966ef5
--- /dev/null
+++ b/account-query/src/main/java/cz/muni/pa165/banking/application/service/BalanceServiceImpl.java
@@ -0,0 +1,85 @@
+package cz.muni.pa165.banking.application.service;
+
+import cz.muni.pa165.banking.application.exception.NotFoundAccountException;
+import cz.muni.pa165.banking.domain.balance.Balance;
+import cz.muni.pa165.banking.domain.balance.repository.BalancesRepository;
+import cz.muni.pa165.banking.domain.balance.service.BalanceService;
+import cz.muni.pa165.banking.domain.report.StatisticalReport;
+import cz.muni.pa165.banking.domain.transaction.Transaction;
+import cz.muni.pa165.banking.domain.transaction.TransactionType;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.time.OffsetDateTime;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Objects;
+import java.util.UUID;
+
+/**
+ * @author Martin Mojzis
+ */
+@Service
+public class BalanceServiceImpl implements BalanceService {
+
+    private final BalancesRepository balanceRepository;
+
+    public BalanceServiceImpl(BalancesRepository balanceRepository) {
+        this.balanceRepository = balanceRepository;
+    }
+
+    public Balance findById(String id) throws NotFoundAccountException {
+        return balanceRepository.findById(id)
+                .orElseThrow(() -> new NotFoundAccountException("Balance  of person with id: " + id + " was not found."));
+    }
+
+    @Override
+    public void addNewBalance(String id) {
+        balanceRepository.addBalance(id);
+    }
+
+    @Override
+    public BigDecimal getBalance(String id) throws NotFoundAccountException {
+        Balance balance = findById(id);
+        return balance.getAmount();
+    }
+
+    @Override
+    public List<Transaction> getTransactions(String id, OffsetDateTime from, OffsetDateTime to, BigDecimal minAmount,
+                                             BigDecimal maxAmount, TransactionType type)
+            throws NotFoundAccountException {
+        Balance balance = findById(id);
+        if (minAmount == null && maxAmount == null && type == null)
+            return balance.getData(from, to);
+        if (minAmount == null && maxAmount == null)
+            return balance.getData(from, to, type);
+        BigDecimal amountMax = Objects.requireNonNullElse(maxAmount, BigDecimal.valueOf(Integer.MAX_VALUE));
+        BigDecimal amountMin = Objects.requireNonNullElse(minAmount, BigDecimal.valueOf(Integer.MIN_VALUE));
+        if (type == null)
+            return balance.getData(from, to, amountMin, amountMax);
+        return balance.getData(from, to, amountMin, amountMax, type);
+    }
+
+    @Override
+    public void addToBalance(String id, BigDecimal amount, UUID processID, TransactionType type)
+            throws NotFoundAccountException {
+        Balance balance = findById(id);
+        balance.addTransaction(amount, type, processID);
+    }
+
+    @Override
+    public StatisticalReport getReport(String id, OffsetDateTime beginning, OffsetDateTime end) {
+        Balance balance = findById(id);
+        return balance.getReport(beginning, end);
+    }
+
+    @Override
+    public List<Transaction> getAllTransactions(OffsetDateTime from, OffsetDateTime to, BigDecimal minAmount,
+                                                BigDecimal maxAmount, TransactionType transactionType) {
+        List<Transaction> result = new LinkedList<>();
+        for (String id : balanceRepository.getAllIds()) {
+            result.addAll(getTransactions(id, from, to, minAmount, maxAmount, transactionType));
+        }
+        return result;
+    }
+}
diff --git a/account-query/src/main/java/cz/muni/pa165/banking/domain/balance/Balance.java b/account-query/src/main/java/cz/muni/pa165/banking/domain/balance/Balance.java
new file mode 100644
index 0000000000000000000000000000000000000000..ed99c1f827a09fae852ec85ed06c31262125643a
--- /dev/null
+++ b/account-query/src/main/java/cz/muni/pa165/banking/domain/balance/Balance.java
@@ -0,0 +1,89 @@
+package cz.muni.pa165.banking.domain.balance;
+
+import cz.muni.pa165.banking.domain.report.StatisticalReport;
+import cz.muni.pa165.banking.domain.transaction.Transaction;
+import cz.muni.pa165.banking.domain.transaction.TransactionType;
+
+import java.math.BigDecimal;
+import java.time.OffsetDateTime;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.UUID;
+
+/**
+ * @author Martin Mojzis
+ */
+public class Balance {
+
+    private final String accountId;
+
+    private BigDecimal amount;
+
+    private final List<Transaction> transactionList;
+
+    public Balance(String userId) {
+        this.amount = new BigDecimal(0);
+        this.transactionList = new ArrayList<>();
+        this.accountId = userId;
+    }
+
+    public void addTransaction(BigDecimal amount, TransactionType type, UUID processId) {
+        transactionList.add(new Transaction(type, amount,
+                OffsetDateTime.now(), processId));
+        this.amount = this.amount.add(amount);
+    }
+
+    public BigDecimal getAmount() {
+        return amount;
+    }
+
+    public List<Transaction> getTransactions() {
+        return transactionList;
+    }
+
+    public Transaction getTransaction(UUID pid) throws RuntimeException {
+        List<Transaction> result = transactionList.stream().filter(a -> Objects.equals(a.getProcessId(), pid)).toList();
+        if (result.isEmpty()) {
+            throw new RuntimeException("list has no tranaction with this id");
+        }
+        return result.get(0);
+    }
+
+    public boolean transactionExists(UUID pid) {
+        List<Transaction> result = transactionList.stream().filter(a -> Objects.equals(a.getProcessId(), pid)).toList();
+        return !result.isEmpty();
+    }
+
+    public StatisticalReport getReport(OffsetDateTime after, OffsetDateTime before) {
+        return new StatisticalReport(this.getData(after, before));
+    }
+
+    public List<Transaction> getData(OffsetDateTime after, OffsetDateTime before) {
+        return transactionList.stream().filter(a -> a.getDate().isAfter(after) && a.getDate().isBefore(before)).toList();
+    }
+
+    public List<Transaction> getData(OffsetDateTime after, OffsetDateTime before, BigDecimal amountMin, BigDecimal amountMax, TransactionType type) {
+        List<Transaction> result = this.getData(after, before);
+        return result.stream()
+                .filter(a -> a.getAmount().compareTo(amountMax) < 0 && a.getAmount().compareTo(amountMin) > 0 && a.getType() == type)
+                .toList();
+    }
+
+    public List<Transaction> getData(OffsetDateTime after, OffsetDateTime before, BigDecimal amountMin, BigDecimal amountMax) {
+        List<Transaction> result = this.getData(after, before);
+        return result.stream()
+                .filter(a -> a.getAmount().compareTo(amountMax) < 0 && a.getAmount().compareTo(amountMin) > 0)
+                .toList();
+    }
+    public String getAccountId() {
+        return accountId;
+    }
+
+    public List<Transaction> getData(OffsetDateTime from, OffsetDateTime to, TransactionType type) {
+        List<Transaction> result = this.getData(from, to);
+        return result.stream()
+                .filter(a -> a.getType() == type)
+                .toList();
+    }
+}
diff --git a/account-query/src/main/java/cz/muni/pa165/banking/domain/balance/repository/BalancesRepository.java b/account-query/src/main/java/cz/muni/pa165/banking/domain/balance/repository/BalancesRepository.java
new file mode 100644
index 0000000000000000000000000000000000000000..09a4b51cf7d1c82c0f437be0b70e829722250521
--- /dev/null
+++ b/account-query/src/main/java/cz/muni/pa165/banking/domain/balance/repository/BalancesRepository.java
@@ -0,0 +1,18 @@
+package cz.muni.pa165.banking.domain.balance.repository;
+
+import cz.muni.pa165.banking.domain.balance.Balance;
+
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * @author Martin Mojzis
+ */
+public interface BalancesRepository {
+
+    Optional<Balance> findById(String id);
+
+    void addBalance(String id);
+
+    List<String> getAllIds();
+}
diff --git a/account-query/src/main/java/cz/muni/pa165/banking/domain/balance/service/BalanceService.java b/account-query/src/main/java/cz/muni/pa165/banking/domain/balance/service/BalanceService.java
new file mode 100644
index 0000000000000000000000000000000000000000..c242a56b620bab2c0ce47ccd480578a02a2bf648
--- /dev/null
+++ b/account-query/src/main/java/cz/muni/pa165/banking/domain/balance/service/BalanceService.java
@@ -0,0 +1,31 @@
+package cz.muni.pa165.banking.domain.balance.service;
+
+import cz.muni.pa165.banking.application.exception.NotFoundAccountException;
+import cz.muni.pa165.banking.domain.report.StatisticalReport;
+import cz.muni.pa165.banking.domain.transaction.Transaction;
+import cz.muni.pa165.banking.domain.transaction.TransactionType;
+
+import java.math.BigDecimal;
+import java.time.OffsetDateTime;
+import java.util.List;
+import java.util.UUID;
+
+/**
+ * @author Martin Mojzis
+ */
+public interface BalanceService {
+
+    void addNewBalance(String id) throws NotFoundAccountException;
+
+    BigDecimal getBalance(String id) throws NotFoundAccountException;
+
+    List<Transaction> getTransactions(String id, OffsetDateTime from, OffsetDateTime to, BigDecimal minAmount,
+                                      BigDecimal maxAmount, TransactionType type) throws NotFoundAccountException;
+
+    void addToBalance(String id, BigDecimal amount, UUID processID, TransactionType type) throws NotFoundAccountException;
+
+    StatisticalReport getReport(String id, OffsetDateTime beginning, OffsetDateTime end) throws NotFoundAccountException;
+
+    List<Transaction> getAllTransactions(OffsetDateTime from, OffsetDateTime from1, BigDecimal minAmount,
+                                         BigDecimal maxAmount, TransactionType transactionType);
+}
diff --git a/account-query/src/main/java/cz/muni/pa165/banking/domain/report/StatisticalReport.java b/account-query/src/main/java/cz/muni/pa165/banking/domain/report/StatisticalReport.java
new file mode 100644
index 0000000000000000000000000000000000000000..db2583f8f82810795c30cc36a5499786ed81823f
--- /dev/null
+++ b/account-query/src/main/java/cz/muni/pa165/banking/domain/report/StatisticalReport.java
@@ -0,0 +1,86 @@
+package cz.muni.pa165.banking.domain.report;
+
+import cz.muni.pa165.banking.domain.transaction.Transaction;
+import cz.muni.pa165.banking.domain.transaction.TransactionType;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * @author Martin Mojzis
+ */
+public class StatisticalReport {
+    //report total and average (per account) transactions (deposits, withdrawals, outgoing and incoming payments) in a selected date range
+    
+    private final TransactionStatistics totalAmount = new TransactionStatistics();
+    
+    private final TransactionStatistics depositAmount = new TransactionStatistics(TransactionType.DEPOSIT);
+    
+    private final TransactionStatistics withdrawalAmount = new TransactionStatistics(TransactionType.WITHDRAW);
+    
+    private final TransactionStatistics crossAccountAmount = new TransactionStatistics(TransactionType.CROSS_ACCOUNT_PAYMENT);
+    
+    private final TransactionStatistics creditAmount = new TransactionStatistics(TransactionType.CREDIT);
+    
+    private final TransactionStatistics refundAmount = new TransactionStatistics(TransactionType.REFUND);
+
+    //maybe not needed
+    private BigDecimal amountMin = BigDecimal.valueOf(Double.MAX_VALUE);
+
+    private BigDecimal amountMax = new BigDecimal(0);
+
+    public StatisticalReport(List<Transaction> list) {
+        for (Transaction transaction : list) {
+            if (transaction.getAmount().abs().compareTo(amountMin) < 0) {
+                amountMin = transaction.getAmount().abs();
+            }
+            if (transaction.getAmount().abs().compareTo(amountMax) > 0) {
+                amountMax = transaction.getAmount().abs();
+            }
+            addToAmountStatistics(transaction);
+        }
+    }
+
+    private void addToAmountStatistics(Transaction transaction) {
+        totalAmount.AddAmount(transaction.getAmount());
+        switch (transaction.getType()){
+            case CREDIT -> creditAmount.AddAmount(transaction.getAmount());
+            case REFUND -> refundAmount.AddAmount(transaction.getAmount());
+            case DEPOSIT -> depositAmount.AddAmount(transaction.getAmount());
+            case WITHDRAW -> withdrawalAmount.AddAmount(transaction.getAmount());
+            case CROSS_ACCOUNT_PAYMENT -> crossAccountAmount.AddAmount(transaction.getAmount());
+        }
+    }
+
+    public BigDecimal getAmountMax() {
+        return amountMax;
+    }
+
+    public BigDecimal getAmountMin() {
+        return amountMin;
+    }
+
+    public TransactionStatistics getCreditAmount() {
+        return creditAmount;
+    }
+
+    public TransactionStatistics getCrossAccountAmount() {
+        return crossAccountAmount;
+    }
+
+    public TransactionStatistics getWithdrawalAmount() {
+        return withdrawalAmount;
+    }
+
+    public TransactionStatistics getDepositAmount() {
+        return depositAmount;
+    }
+
+    public TransactionStatistics getTotalAmount() {
+        return totalAmount;
+    }
+
+    public TransactionStatistics getRefundAmount() {
+        return refundAmount;
+    }
+}
diff --git a/account-query/src/main/java/cz/muni/pa165/banking/domain/report/TransactionStatistics.java b/account-query/src/main/java/cz/muni/pa165/banking/domain/report/TransactionStatistics.java
new file mode 100644
index 0000000000000000000000000000000000000000..8514f8f12b91da3ff72c302c2c210e0d267e48a0
--- /dev/null
+++ b/account-query/src/main/java/cz/muni/pa165/banking/domain/report/TransactionStatistics.java
@@ -0,0 +1,58 @@
+package cz.muni.pa165.banking.domain.report;
+
+import cz.muni.pa165.banking.domain.transaction.TransactionType;
+
+import java.math.BigDecimal;
+
+/**
+ * @author Martin Mojzis
+ */
+public class TransactionStatistics {
+
+    private TransactionType type = null;
+
+    private BigDecimal amountIn = new BigDecimal(0);
+
+    private BigDecimal amountOut = new BigDecimal(0);
+
+    private Integer timesIn = 0;
+
+    private Integer timesOut = 0;
+    
+    public TransactionStatistics(TransactionType type){
+        this.type = type;
+    }
+    
+    public TransactionStatistics(){}
+
+    public void AddAmount(BigDecimal amount){
+        if(amount.compareTo(BigDecimal.ZERO) > 0){
+            amountIn = amountIn.add(amount);
+            timesIn += 1;
+        }
+        else{
+            amountOut = amountOut.add(amount);
+            timesOut += 1;
+        }
+    }
+
+    public Integer getTimesOut() {
+        return timesOut;
+    }
+
+    public Integer getTimesIn() {
+        return timesIn;
+    }
+
+    public BigDecimal getAmountOut() {
+        return amountOut;
+    }
+
+    public BigDecimal getAmountIn() {
+        return amountIn;
+    }
+
+    public TransactionType getType() {
+        return type;
+    }
+}
diff --git a/account-query/src/main/java/cz/muni/pa165/banking/domain/transaction/Transaction.java b/account-query/src/main/java/cz/muni/pa165/banking/domain/transaction/Transaction.java
new file mode 100644
index 0000000000000000000000000000000000000000..479ca7981a098d493db35f9277ef2000dec6219e
--- /dev/null
+++ b/account-query/src/main/java/cz/muni/pa165/banking/domain/transaction/Transaction.java
@@ -0,0 +1,42 @@
+package cz.muni.pa165.banking.domain.transaction;
+
+import java.math.BigDecimal;
+import java.time.OffsetDateTime;
+import java.util.UUID;
+
+/**
+ * @author Martin Mojzis
+ */
+public class Transaction {
+    
+    private final TransactionType type;
+    
+    private final BigDecimal amount;
+    
+    private final OffsetDateTime date;
+    
+    private final UUID processId;
+
+    public Transaction(TransactionType type, BigDecimal amount, OffsetDateTime date, UUID processId) {
+        this.type = type;
+        this.amount = amount;
+        this.date = date;
+        this.processId = processId;
+    }
+    
+    public OffsetDateTime getDate() {
+        return date;
+    }
+
+    public BigDecimal getAmount() {
+        return amount;
+    }
+
+    public TransactionType getType() {
+        return type;
+    }
+    
+    public UUID getProcessId() {
+        return processId;
+    }
+}
diff --git a/account-query/src/main/java/cz/muni/pa165/banking/domain/transaction/TransactionType.java b/account-query/src/main/java/cz/muni/pa165/banking/domain/transaction/TransactionType.java
new file mode 100644
index 0000000000000000000000000000000000000000..2a1fb15b87e63a153fb22f837940e0b2bf5b7e6d
--- /dev/null
+++ b/account-query/src/main/java/cz/muni/pa165/banking/domain/transaction/TransactionType.java
@@ -0,0 +1,18 @@
+package cz.muni.pa165.banking.domain.transaction;
+
+/**
+ * @author Martin Mojzis
+ */
+public enum TransactionType {
+
+    WITHDRAW,
+
+    DEPOSIT,
+
+    CREDIT,
+
+    CROSS_ACCOUNT_PAYMENT,
+
+    REFUND
+
+}
diff --git a/account-query/src/main/resources/application.properties b/account-query/src/main/resources/application.properties
new file mode 100644
index 0000000000000000000000000000000000000000..bafddced850ad5cb9c8b100b9daf64dae4e70202
--- /dev/null
+++ b/account-query/src/main/resources/application.properties
@@ -0,0 +1 @@
+server.port=8081
\ No newline at end of file
diff --git a/account-query/src/main/resources/openapi.yaml b/account-query/src/main/resources/openapi.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..dd10e76d9e992ad34dd1d3c8caee7205cb627ffc
--- /dev/null
+++ b/account-query/src/main/resources/openapi.yaml
@@ -0,0 +1,248 @@
+openapi: 3.0.1
+info:
+  title: Pa165 Project Banking Application Account Query
+  description: |
+    Hand-made OpenAPI document.
+  version: 1.0.0
+servers:
+  - url: "http://localhost:8080"
+tags:
+  - name: CustomerService
+    description: Service to be used by customer of bank
+  - name: SystemService
+    description: Service to be used by other services of bank
+  - name: EmployeeService
+    description: Service to be used by employees of bank
+components:
+  schemas:
+    TransactionType:
+      type: string
+      enum: [ WITHDRAW, DEPOSIT, CREDIT, CROSS_ACCOUNT_PAYMENT, REFUND ]
+      description: type of transaction
+    Transaction:
+      title: A transaction
+      description: A object representing one transaction
+      properties:
+        transactionType:
+          $ref: "#/components/schemas/TransactionType"
+        amount:
+          type: number
+          description: amount of money in transaction
+          example: 10
+        date:
+          type: string
+          description: time when the transaction happened
+          format: date-time
+        processId:
+          type: string
+          format: uuid
+          description: id of transaction issued by transaction processor
+
+    Balance:
+      title: A balance
+      description: Balance object keeping balance of ones account as well as all transactions that led to it.
+      required:
+        - id
+      properties:
+        id:
+          type: string
+          description: id of account with this balance
+          example: id1
+        amount:
+          type: number
+          description: balance of account right now
+          example: 10
+        transactions:
+          type: array
+          items:
+            $ref: '#/components/schemas/Transaction'
+          description: all transactions of this account in list
+
+    TransactionStatistics:
+      title: statistics about one type of transaction
+      properties:
+        transactionType:
+          $ref: "#/components/schemas/TransactionType"
+        amountIn:
+          type: number
+          description: amount of money got by this type of transactions
+          example: 1002
+        amountOut:
+          type: number
+          description: amount of money spent by this type of transactions
+          example: 1184
+        timesIn:
+          type: number
+          description: number of times this type of transaction was used to get money
+          example: 12
+        timesOut:
+          type: number
+          description: number of times this type of transaction was used to spend money
+          example: 13
+        avgIn:
+          type: number
+          description: average amount of money regarding charging account
+          example: 120
+        avgOut:
+          type: number
+          description: average amount of money regarding spending money
+          example: 14
+
+    TransactionsReport:
+      title: statistical report about one account
+      properties:
+        totalAmount:
+          $ref: '#/components/schemas/TransactionStatistics'
+        depositAmount:
+          $ref: '#/components/schemas/TransactionStatistics'
+        withdrawalAmount:
+          $ref: '#/components/schemas/TransactionStatistics'
+        crossAccountAmount:
+          $ref: '#/components/schemas/TransactionStatistics'
+        creditAmount:
+          $ref: '#/components/schemas/TransactionStatistics'
+
+paths:
+  /balance/new:
+    post:
+      tags:
+        - SystemService
+      summary: creates a balance
+      operationId: createBalance
+      parameters:
+        - { name: id, in: query, required: true, schema: { type: string }, description: "id of account" }
+      responses:
+        "201":
+          description: OK
+
+  /balance/add:
+    post:
+      tags:
+        - SystemService
+      summary: adds transaction to existing balance
+      operationId: addTransactionToBalance
+      parameters:
+        - { name: id, in: query, required: true, schema: { type: string }, description: "id of account" }
+        - { name: amount, in: query, required: true, schema: { type: number }, description: "amount of money in transaction" }
+        - { name: processId, in: query, required: true, schema: { type: string, format: uuid }, description: "id of process which this transaction is part of" }
+        - { name: type, in: query, required: true, schema: { $ref: "#/components/schemas/TransactionType" }, description: "type  of transaction" }
+      responses:
+        "200":
+          description: OK
+        "400":
+          description: NOK
+          content:
+            application/json:
+              schema:
+                type: string
+                description: reason of failure
+
+  /balance/status:
+    get:
+      tags:
+        - CustomerService
+        - SystemService
+      summary: returns account balance status
+      operationId: getBalance
+      parameters:
+        - { name: id, in: query, required: true, schema: { type: string }, description: "id of account" }
+      responses:
+        "200":
+          description: OK
+          content:
+            application/json:
+              schema:
+                type: number
+                description: accounts balance
+        "400":
+          description: NOK
+          content:
+            application/json:
+              schema:
+                type: string
+                description: reason of failure
+
+  /balance/transactions:
+    get:
+      tags:
+        - CustomerService
+        - SystemService
+      summary: returns transactions of specific account for specific time interval
+      operationId: getTransactions
+      parameters:
+        - { name: id, in: query, required: true, schema: { type: string }, description: "id of account" }
+        - { name: beginning, in: query, required: true, schema: { type: string, format: date }, description: "date from which onwards the transactions happened" }
+        - { name: end, in: query, required: true, schema: { type: string, format: date }, description: "date before which wanted transactions happened" }
+        - { name: minAmount, in: query, required: false, schema: { type: number }, description: "minimal amount of money included in transaction to be reported" }
+        - { name: maxAmount, in: query, required: false, schema: { type: number }, description: "maximal amount of money included in transaction to be reported" }
+        - { name: type, in: query, required: false, schema: { $ref: "#/components/schemas/TransactionType" }, description: "type of transactiops to be included in returned ones" }
+      responses:
+        "200":
+          description: OK
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/Transaction"
+        "400":
+          description: NOK
+          content:
+            application/json:
+              schema:
+                type: string
+                description: reason of failure
+
+  /balance/alltransactions:
+    get:
+      tags:
+        - EmployeeService
+      summary: returns all transactions for specific time interval
+      operationId: getAllTransactions
+      parameters:
+        - { name: beginning, in: query, required: true, schema: { type: string, format: date }, description: "date from which onwards the transactions happened" }
+        - { name: end, in: query, required: true, schema: { type: string, format: date }, description: "date before which wanted transactions happened" }
+        - { name: minAmount, in: query, required: false, schema: { type: number }, description: "minimal amount of money included in transaction to be reported" }
+        - { name: maxAmount, in: query, required: false, schema: { type: number }, description: "maximal amount of money included in transaction to be reported" }
+        - { name: type, in: query, required: false, schema: { $ref: "#/components/schemas/TransactionType" }, description: "type of transactiops to be included in returned ones" }
+      responses:
+        "200":
+          description: OK
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/Transaction"
+        "400":
+          description: NOK
+          content:
+            application/json:
+              schema:
+                type: string
+                description: reason of failure
+
+  /balance/account/report:
+    get:
+      tags:
+        - EmployeeService
+      summary: creates a report of spending statistics for one user
+      operationId: createReport
+      parameters:
+        - { name: id, in: query, required: true, schema: { type: string }, description: "id of account" }
+        - { name: beginning, in: query, required: true, schema: { type: string, format: date }, description: "date from which onwards the transactions wanted in report happened" }
+        - { name: end, in: query, required: true, schema: { type: string, format: date }, description: "date before which wanted transactions wanted in report happened" }
+      responses:
+        "200":
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/TransactionsReport'
+        "400":
+          description: NOK
+          content:
+            application/json:
+              schema:
+                type: string
+                description: reason of failure