diff --git a/jmp-cloud-bank-impl/module-info.java b/jmp-cloud-bank-impl/module-info.java
new file mode 100644
index 0000000..de5b4bd
--- /dev/null
+++ b/jmp-cloud-bank-impl/module-info.java
@@ -0,0 +1,5 @@
+module application {
+ uses org.x.service.BankService;
+ requires jmp.cloud.bank.impl;
+ requires jmp.dto;
+}
\ No newline at end of file
diff --git a/jmp-cloud-bank-impl/pom.xml b/jmp-cloud-bank-impl/pom.xml
new file mode 100644
index 0000000..dadccd5
--- /dev/null
+++ b/jmp-cloud-bank-impl/pom.xml
@@ -0,0 +1,28 @@
+
+
+ 4.0.0
+
+ org.x
+ java-backend
+ 1.0-SNAPSHOT
+
+
+ jmp-cloud-bank-impl
+
+
+ 17
+ 17
+ UTF-8
+
+
+
+
+ org.projectlombok
+ lombok
+ 1.18.24
+ provided
+
+
+
\ No newline at end of file
diff --git a/jmp-cloud-bank-impl/src/main/java/org/x/Main.java b/jmp-cloud-bank-impl/src/main/java/org/x/Main.java
new file mode 100644
index 0000000..76e1204
--- /dev/null
+++ b/jmp-cloud-bank-impl/src/main/java/org/x/Main.java
@@ -0,0 +1,26 @@
+package org.x;
+
+import org.x.dto.BankCard;
+import org.x.dto.BankCardType;
+import org.x.dto.User;
+import org.x.service.BankService;
+import org.x.service.BankServiceImpl;
+
+public class Main {
+ public static void main(String[] args) {
+ BankService bankService = new BankServiceImpl();
+ User user = new User();
+ user.setName("John");
+ user.setSurname("Doe");
+
+ BankCard creditCard = bankService.createCard(user, BankCardType.CREDIT);
+ BankCard debitCard = bankService.createCard(user, BankCardType.DEBIT);
+
+ System.out.println("Credit Card: " + creditCard);
+ System.out.println("Debit Card: " + debitCard);
+
+ System.out.println("All subscriptions: " + bankService.getAllSubscriptions());
+ System.out.println("Subscriptions by condition: " + bankService
+ .getAllSubscriptionsByCondition(subscription -> subscription.getPrice() > 5));
+ }
+}
\ No newline at end of file
diff --git a/jmp-cloud-bank-impl/src/main/java/org/x/dto/BankCard.java b/jmp-cloud-bank-impl/src/main/java/org/x/dto/BankCard.java
new file mode 100644
index 0000000..28e39b9
--- /dev/null
+++ b/jmp-cloud-bank-impl/src/main/java/org/x/dto/BankCard.java
@@ -0,0 +1,17 @@
+package org.x.dto;
+
+import lombok.Data;
+
+@Data
+public class BankCard {
+ private User user;
+ private BankCardType bankCardType;
+ private String cardNumber;
+ private String cvv;
+ private String expirationDate;
+
+ public BankCard(User user, BankCardType bankCardType) {
+ this.user = user;
+ this.bankCardType = bankCardType;
+ }
+}
diff --git a/jmp-cloud-bank-impl/src/main/java/org/x/dto/BankCardType.java b/jmp-cloud-bank-impl/src/main/java/org/x/dto/BankCardType.java
new file mode 100644
index 0000000..0d2633c
--- /dev/null
+++ b/jmp-cloud-bank-impl/src/main/java/org/x/dto/BankCardType.java
@@ -0,0 +1,6 @@
+package org.x.dto;
+
+public enum BankCardType {
+ CREDIT,
+ DEBIT
+}
diff --git a/jmp-cloud-bank-impl/src/main/java/org/x/dto/CreditBankCard.java b/jmp-cloud-bank-impl/src/main/java/org/x/dto/CreditBankCard.java
new file mode 100644
index 0000000..7865c10
--- /dev/null
+++ b/jmp-cloud-bank-impl/src/main/java/org/x/dto/CreditBankCard.java
@@ -0,0 +1,8 @@
+package org.x.dto;
+
+public class CreditBankCard extends BankCard {
+ public CreditBankCard(User user) {
+ super(user, BankCardType.CREDIT);
+ }
+
+}
diff --git a/jmp-cloud-bank-impl/src/main/java/org/x/dto/DebitBankCard.java b/jmp-cloud-bank-impl/src/main/java/org/x/dto/DebitBankCard.java
new file mode 100644
index 0000000..fee024c
--- /dev/null
+++ b/jmp-cloud-bank-impl/src/main/java/org/x/dto/DebitBankCard.java
@@ -0,0 +1,8 @@
+package org.x.dto;
+
+public class DebitBankCard extends BankCard {
+ public DebitBankCard(User user) {
+ super(user, BankCardType.DEBIT);
+ }
+
+}
diff --git a/jmp-cloud-bank-impl/src/main/java/org/x/dto/Subscription.java b/jmp-cloud-bank-impl/src/main/java/org/x/dto/Subscription.java
new file mode 100644
index 0000000..351929e
--- /dev/null
+++ b/jmp-cloud-bank-impl/src/main/java/org/x/dto/Subscription.java
@@ -0,0 +1,18 @@
+package org.x.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.With;
+
+@Data
+@With
+@AllArgsConstructor
+@NoArgsConstructor
+public class Subscription {
+ private Long id;
+ private String name;
+ private String description;
+ private Double price;
+ private Boolean active;
+}
diff --git a/jmp-cloud-bank-impl/src/main/java/org/x/dto/User.java b/jmp-cloud-bank-impl/src/main/java/org/x/dto/User.java
new file mode 100644
index 0000000..c1b96e3
--- /dev/null
+++ b/jmp-cloud-bank-impl/src/main/java/org/x/dto/User.java
@@ -0,0 +1,18 @@
+package org.x.dto;
+
+import java.time.LocalDate;
+
+import lombok.Data;
+
+@Data
+public class User {
+ private String name;
+ private String surname;
+ private String email;
+ private String password;
+ private String phone;
+ private String address;
+ private String passport;
+ private String role;
+ private LocalDate birthDate;
+}
diff --git a/jmp-cloud-bank-impl/src/main/java/org/x/exception/SubscriptionNotFoundException.java b/jmp-cloud-bank-impl/src/main/java/org/x/exception/SubscriptionNotFoundException.java
new file mode 100644
index 0000000..2817ccd
--- /dev/null
+++ b/jmp-cloud-bank-impl/src/main/java/org/x/exception/SubscriptionNotFoundException.java
@@ -0,0 +1,7 @@
+package org.x.exception;
+
+public class SubscriptionNotFoundException extends RuntimeException {
+ public SubscriptionNotFoundException(String message) {
+ super(message);
+ }
+}
diff --git a/jmp-cloud-bank-impl/src/main/java/org/x/service/BankService.java b/jmp-cloud-bank-impl/src/main/java/org/x/service/BankService.java
new file mode 100644
index 0000000..d9566ac
--- /dev/null
+++ b/jmp-cloud-bank-impl/src/main/java/org/x/service/BankService.java
@@ -0,0 +1,23 @@
+package org.x.service;
+
+import java.time.LocalDate;
+import java.time.temporal.ChronoUnit;
+import java.util.List;
+import java.util.function.Predicate;
+
+import org.x.dto.BankCard;
+import org.x.dto.BankCardType;
+import org.x.dto.Subscription;
+import org.x.dto.User;
+
+public interface BankService {
+ BankCard createCard(User user, BankCardType bankCardType);
+
+ List getAllSubscriptions();
+
+ List getAllSubscriptionsByCondition(Predicate condition);
+
+ static boolean isPayableUser(User user) {
+ return ChronoUnit.YEARS.between(user.getBirthDate(), LocalDate.now()) >= 18;
+ }
+}
diff --git a/jmp-cloud-bank-impl/src/main/java/org/x/service/BankServiceImpl.java b/jmp-cloud-bank-impl/src/main/java/org/x/service/BankServiceImpl.java
new file mode 100644
index 0000000..3bb2fd2
--- /dev/null
+++ b/jmp-cloud-bank-impl/src/main/java/org/x/service/BankServiceImpl.java
@@ -0,0 +1,42 @@
+package org.x.service;
+
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+import org.x.dto.BankCard;
+import org.x.dto.BankCardType;
+import org.x.dto.CreditBankCard;
+import org.x.dto.DebitBankCard;
+import org.x.dto.Subscription;
+import org.x.dto.User;
+
+public class BankServiceImpl implements BankService {
+
+ private static final Map> cardCreators = Map.of(
+ BankCardType.CREDIT, CreditBankCard::new,
+ BankCardType.DEBIT, DebitBankCard::new
+ );
+
+ @Override
+ public BankCard createCard(User user, BankCardType bankCardType) {
+ return cardCreators.get(bankCardType).apply(user);
+ }
+
+ @Override
+ public List getAllSubscriptions() {
+ return List.of(
+ new Subscription().withId(1L).withPrice(4.99),
+ new Subscription().withId(3L).withPrice(9.99),
+ new Subscription().withId(2L).withPrice(7.99),
+ new Subscription().withId(4L).withPrice(5.99));
+ }
+
+ @Override
+ public List getAllSubscriptionsByCondition(Predicate condition) {
+ return getAllSubscriptions()
+ .stream().filter(condition)
+ .toList();
+ }
+}
diff --git a/jmp-cloud-bank-impl/src/main/java/org/x/service/UserService.java b/jmp-cloud-bank-impl/src/main/java/org/x/service/UserService.java
new file mode 100644
index 0000000..592a9f1
--- /dev/null
+++ b/jmp-cloud-bank-impl/src/main/java/org/x/service/UserService.java
@@ -0,0 +1,18 @@
+package org.x.service;
+
+import java.time.LocalDate;
+import java.time.temporal.ChronoUnit;
+import java.util.List;
+
+import org.x.dto.User;
+
+public interface UserService {
+ List getAllUsers();
+
+ default double getAverageUsersAge() {
+ return getAllUsers().stream()
+ .mapToDouble(user -> ChronoUnit.YEARS.between(user.getBirthDate(), LocalDate.now()))
+ .average()
+ .orElse(0);
+ }
+}
diff --git a/jmp-cloud-bank-impl/src/main/java/org/x/service/UserServiceImpl.java b/jmp-cloud-bank-impl/src/main/java/org/x/service/UserServiceImpl.java
new file mode 100644
index 0000000..b69048c
--- /dev/null
+++ b/jmp-cloud-bank-impl/src/main/java/org/x/service/UserServiceImpl.java
@@ -0,0 +1,12 @@
+package org.x.service;
+
+import java.util.List;
+
+import org.x.dto.User;
+
+public class UserServiceImpl implements UserService {
+ @Override
+ public List getAllUsers() {
+ return List.of();
+ }
+}
diff --git a/modules/54. Redis/Code Examples/bin/main/ratelimitRules.yaml b/modules/54. Redis/Code Examples/bin/main/ratelimitRules.yaml
new file mode 100644
index 0000000..6ba63fc
--- /dev/null
+++ b/modules/54. Redis/Code Examples/bin/main/ratelimitRules.yaml
@@ -0,0 +1,17 @@
+# 2 requests per minute per account Id
+- accountId: ""
+ allowedNumberOfRequests: 2
+ timeInterval: MINUTE
+# 1 Slow request per account per minute
+- accountId: ""
+ allowedNumberOfRequests: 1
+ timeInterval: MINUTE
+ requestType: SLOW
+# 1 request for 192.168.100.150 per HOUR
+- clientIp: 192.168.100.150
+ allowedNumberOfRequests: 1
+ timeInterval: HOUR
+# 10 requests for important customer per minute
+- accountId: ImportantCustomerId
+ allowedNumberOfRequests: 10
+ timeInterval: MINUTE
\ No newline at end of file
diff --git a/modules/54. Redis/Code Examples/bin/test/redis/docker-compose.yaml b/modules/54. Redis/Code Examples/bin/test/redis/docker-compose.yaml
new file mode 100644
index 0000000..4e953ed
--- /dev/null
+++ b/modules/54. Redis/Code Examples/bin/test/redis/docker-compose.yaml
@@ -0,0 +1,37 @@
+# On windows host network mode doesn't work (expect wsl 2 backend)
+# We use --cluster-announce-ip + different ports for each instance + DNS-based nodes access to make cluster accessible from localhost
+version: "3.9"
+
+services:
+ redis-master-0:
+ image: redis:7.0.5-alpine
+ command: redis-server --cluster-enabled yes --port 30000 --cluster-port 40000 --cluster-announce-ip redis-master-0
+ ports:
+ - "30000:30000"
+ - "40000:40000"
+
+ redis-master-1:
+ image: redis:7.0.5-alpine
+ command: redis-server --cluster-enabled yes --port 30001 --cluster-port 40001 --cluster-announce-ip redis-master-1
+ ports:
+ - "30001:30001"
+ - "40001:40001"
+
+
+ redis-master-2:
+ image: redis:7.0.5-alpine
+ command: redis-server --cluster-enabled yes --port 30002 --cluster-port 40002 --cluster-announce-ip redis-master-2
+ ports:
+ - "30002:30002"
+ - "40002:40002"
+
+
+ redis-init-cluster:
+ image: redis:7.0.5-alpine
+ command: redis-cli --cluster create redis-master-0:30000 redis-master-1:30001 redis-master-2:30002 --cluster-replicas 0 --cluster-yes
+ restart: "no"
+ depends_on:
+ - redis-master-0
+ - redis-master-1
+ - redis-master-2
+
diff --git a/pom.xml b/pom.xml
index b0ec456..24bcd09 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,6 +7,10 @@
org.x
java-backend
1.0-SNAPSHOT
+ pom
+
+ jmp-cloud-bank-impl
+
17