A comprehensive microservices-based game system featuring warriors, weapons, coins, enemies, dragons, battles, spells, and arena with role-based access control, gRPC communication, and event-driven architecture using Kafka.
graph TB
subgraph "Client Layer"
WEB[Web Client]
API[API Client]
end
subgraph "API Gateway Layer"
FG["Fiber Gateway\nHTTP gRPC h2c"]
end
subgraph "Microservices Layer"
W["Warrior Service\nHTTP :8080"]
WP["Weapon Service\nHTTP :8081"]
C["Coin Service\ngRPC :50051"]
E["Enemy Service\nHTTP :8083"]
D["Dragon Service\nHTTP :8084"]
B["Battle Service\nHTTP :8085"]
BS["Battlespell Service\nHTTP :8086"]
A["Arena Service\nHTTP :8087"]
AS[Arenaspell Service]
H["Heal Service\ngRPC :50058"]
R["Repair Service\ngRPC :50061"]
end
subgraph "Data Layer"
PG[(PostgreSQL)]
MG[(MongoDB)]
MY[(MySQL)]
RD[(Redis)]
end
subgraph "Event Layer"
K[Kafka]
Z[Zookeeper]
end
WEB --> FG
API --> FG
FG --> W
FG --> WP
FG --> E
FG --> D
FG --> B
FG --> BS
FG --> A
FG --> AS
FG --> H
FG --> R
W -.->|gRPC| C
E -.->|gRPC| W
D -.->|gRPC| W
B -.->|gRPC| W
B -.->|gRPC| C
B -.->|gRPC| BS
B -.->|gRPC| H
BS -.->|gRPC| B
A -.->|gRPC| W
AS -.->|gRPC| A
H -.->|gRPC| W
H -.->|gRPC| C
R -.->|gRPC| WP
R -.->|gRPC| C
W --> PG
WP --> MG
E --> MG
D --> MG
B --> MG
C --> MY
H --> PG
R --> PG
FG --> RD
B --> RD
WP -->|Events| K
E -->|Events| K
D -->|Events| K
B -->|Events| K
A -->|Events| K
R -->|Events| K
C -->|Consume| K
WP -->|Consume| K
W -->|Consume| K
H -->|Consume| K
K --> Z
%% Colors
style WEB fill:#0077cc,stroke:#003a70,stroke-width:3px,color:#ffffff
style API fill:#3399ff,stroke:#003a70,stroke-width:3px,color:#ffffff
style FG fill:#7e57c2,stroke:#4527a0,stroke-width:3px,color:#ffffff
style W fill:#2196f3,stroke:#0d47a1,stroke-width:3px,color:#ffffff
style WP fill:#43a047,stroke:#1b5e20,stroke-width:3px,color:#ffffff
style C fill:#f9a825,stroke:#ff6f00,stroke-width:3px,color:#1f1400
style E fill:#e53935,stroke:#b71c1c,stroke-width:3px,color:#ffffff
style D fill:#fb8c00,stroke:#e65100,stroke-width:3px,color:#1f1400
style B fill:#00897b,stroke:#004d40,stroke-width:3px,color:#ffffff
style BS fill:#5e35b1,stroke:#311b92,stroke-width:3px,color:#ffffff
style A fill:#ec407a,stroke:#ad1457,stroke-width:3px,color:#ffffff
style AS fill:#8e24aa,stroke:#4a148c,stroke-width:3px,color:#ffffff
style H fill:#00acc1,stroke:#006064,stroke-width:3px,color:#ffffff
style R fill:#7cb342,stroke:#33691e,stroke-width:3px,color:#1a220f
style PG fill:#546e7a,stroke:#263238,stroke-width:3px,color:#ffffff
style MG fill:#455a64,stroke:#1c313a,stroke-width:3px,color:#ffffff
style MY fill:#607d8b,stroke:#37474f,stroke-width:3px,color:#ffffff
style RD fill:#d32f2f,stroke:#b71c1c,stroke-width:3px,color:#ffffff
style K fill:#fdd835,stroke:#f9a825,stroke-width:3px,color:#1f1400
style Z fill:#8d6e63,stroke:#5d4037,stroke-width:3px,color:#ffffff
sequenceDiagram
participant Client
participant Warrior as Warrior Service
participant Weapon as Weapon Service
participant Coin as Coin Service
participant Enemy as Enemy Service
participant Dragon as Dragon Service
participant Battle as Battle Service
participant Kafka as Kafka Events
Note over Client,Dragon: Warrior Weapon Purchase Flow
Client->>Warrior: Login & Get Token
Warrior->>Weapon: Validate Token (gRPC)
Weapon->>Coin: Deduct Coins (gRPC)
Coin-->>Weapon: Payment Confirmed
Weapon->>Kafka: Publish Purchase Event
Weapon-->>Client: Weapon Purchased
Note over Client,Dragon: Enemy Attack Flow
Client->>Enemy: Create Goblin (Dark Emperor)
Enemy->>Warrior: Get Warrior Info (gRPC)
Enemy->>Enemy: Attack Warrior
Enemy->>Kafka: Publish Attack Event
Coin->>Kafka: Consume Attack Event
Coin->>Coin: Deduct Warrior Coins
Note over Client,Dragon: Dragon Battle Flow
Client->>Dragon: Create Dragon (Dark Emperor)
Client->>Dragon: Attack Dragon (Light King/Emperor)
Dragon->>Warrior: Get Warrior Info (gRPC)
Dragon->>Dragon: Calculate Damage
Dragon->>Kafka: Publish Death Event (if killed)
Weapon->>Kafka: Consume Death Event
Weapon->>Weapon: Add Loot Weapon
graph TD
subgraph "Light Side"
LK[Light King<br/>Can kill dragons<br/>Can view all balances]
LE[Light Emperor<br/>Can kill dragons<br/>Can view all balances]
LW[Light Warrior<br/>Can buy weapons<br/>Can view own balance]
end
subgraph "Dark Side"
DK[Dark King<br/>Can create enemies<br/>Can view all balances]
DE[Dark Emperor<br/>Can create enemies & dragons<br/>Can view all balances]
DW[Dark Warrior<br/>Can buy weapons<br/>Can view own balance]
end
subgraph "Actions"
A1[Create Warriors]
A2[Buy Weapons]
A3[Create Enemies]
A4[Create Dragons]
A5[Kill Dragons]
A6[View Balances]
end
LK --> A5
LK --> A6
LE --> A5
LE --> A6
LW --> A2
LW --> A6
DK --> A3
DK --> A6
DE --> A3
DE --> A4
DE --> A6
DW --> A2
DW --> A6
style LK fill:#0b3d91,stroke:#001a4d,stroke-width:3px,color:#ffffff
style LE fill:#0b3d91,stroke:#001a4d,stroke-width:3px,color:#ffffff
style LW fill:#0d56b3,stroke:#001a4d,stroke-width:3px,color:#ffffff
style DK fill:#0b3d91,stroke:#001a4d,stroke-width:3px,color:#ffffff
style DE fill:#0b3d91,stroke:#001a4d,stroke-width:3px,color:#ffffff
style DW fill:#0d56b3,stroke:#001a4d,stroke-width:3px,color:#ffffff
style A1 fill:#0d56b3,stroke:#001a4d,stroke-width:3px,color:#ffffff
style A2 fill:#0d56b3,stroke:#001a4d,stroke-width:3px,color:#ffffff
style A3 fill:#0b3d91,stroke:#001a4d,stroke-width:3px,color:#ffffff
style A4 fill:#0b3d91,stroke:#001a4d,stroke-width:3px,color:#ffffff
style A5 fill:#0d56b3,stroke:#001a4d,stroke-width:3px,color:#ffffff
style A6 fill:#0d56b3,stroke:#001a4d,stroke-width:3px,color:#ffffff
erDiagram
WARRIOR {
uint id PK
string username UK
string email UK
string password
string role
int coin_balance
int total_power
int weapon_count
timestamp created_at
timestamp updated_at
}
WEAPON {
string id PK
string name
string type
int attack_power
int price
string created_by
array owned_by
timestamp created_at
timestamp updated_at
}
TRANSACTION {
uint id PK
uint warrior_id FK
int64 amount
string transaction_type
string reason
int64 balance_before
int64 balance_after
timestamp created_at
}
ENEMY {
objectid id PK
string name
string type
int level
int health
int attack_power
string created_by
timestamp created_at
timestamp updated_at
}
DRAGON {
objectid id PK
string name
string type
int level
int health
int max_health
int attack_power
int defense
string created_by
boolean is_alive
string killed_by
timestamp killed_at
timestamp created_at
timestamp updated_at
}
WARRIOR ||--o{ TRANSACTION : "has"
WARRIOR ||--o{ WEAPON : "owns"
graph LR
subgraph "Event Producers"
WP[Weapon Service]
E[Enemy Service]
D[Dragon Service]
B[Battle Service]
A[Arena Service]
end
subgraph "Kafka Topics"
T1[weapon.purchase]
T2[enemy.attack]
T3[dragon.death]
T4[dragon.revival]
T5[battle.started]
T6[battle.completed]
T7[arena.invitation.sent]
T8[arena.invitation.accepted]
T9[arena.invitation.rejected]
T10[arena.invitation.expired]
T11[arena.match.started]
T12[arena.match.completed]
T13[battle.wager.resolved]
end
subgraph "Event Consumers"
C[Coin Service]
WP2[Weapon Service]
W[Warrior Service]
A2[Arena Service]
H[Heal Service]
end
WP -->|WeaponPurchaseEvent| T1
E -->|EnemyAttackEvent| T2
D -->|DragonDeathEvent| T3
D -->|DragonRevivalEvent| T4
B -->|BattleStartedEvent| T5
B -->|BattleCompletedEvent| T6
A -->|ArenaInvitationSentEvent| T7
A -->|ArenaInvitationAcceptedEvent| T8
A -->|ArenaInvitationRejectedEvent| T9
A -->|ArenaInvitationExpiredEvent| T10
A -->|ArenaMatchStartedEvent| T11
A -->|ArenaMatchCompletedEvent| T12
T1 --> C
T2 --> C
T3 --> WP2
T6 --> A2
T6 --> H
T12 --> H
T13 --> C
C -->|Deduct Coins| C
WP2 -->|Add Loot Weapon| WP2
W -->|Update Kill Count| W
H -->|Log Healing Available| H
style WP fill:#0b3d91,stroke:#001a4d,stroke-width:3px,color:#ffffff
style E fill:#0b3d91,stroke:#001a4d,stroke-width:3px,color:#ffffff
style D fill:#0b3d91,stroke:#001a4d,stroke-width:3px,color:#ffffff
style B fill:#0b3d91,stroke:#001a4d,stroke-width:3px,color:#ffffff
style A fill:#0b3d91,stroke:#001a4d,stroke-width:3px,color:#ffffff
style T1 fill:#0d56b3,stroke:#001a4d,stroke-width:3px,color:#ffffff
style T2 fill:#0d56b3,stroke:#001a4d,stroke-width:3px,color:#ffffff
style T3 fill:#0d56b3,stroke:#001a4d,stroke-width:3px,color:#ffffff
style T4 fill:#0d56b3,stroke:#001a4d,stroke-width:3px,color:#ffffff
style T5 fill:#0d56b3,stroke:#001a4d,stroke-width:3px,color:#ffffff
style T6 fill:#0d56b3,stroke:#001a4d,stroke-width:3px,color:#ffffff
style T7 fill:#0d56b3,stroke:#001a4d,stroke-width:3px,color:#ffffff
style T8 fill:#0d56b3,stroke:#001a4d,stroke-width:3px,color:#ffffff
style T9 fill:#0d56b3,stroke:#001a4d,stroke-width:3px,color:#ffffff
style T10 fill:#0d56b3,stroke:#001a4d,stroke-width:3px,color:#ffffff
style T11 fill:#0d56b3,stroke:#001a4d,stroke-width:3px,color:#ffffff
style T12 fill:#0d56b3,stroke:#001a4d,stroke-width:3px,color:#ffffff
style C fill:#133e7c,stroke:#001a4d,stroke-width:3px,color:#ffffff
style WP2 fill:#133e7c,stroke:#001a4d,stroke-width:3px,color:#ffffff
style W fill:#133e7c,stroke:#001a4d,stroke-width:3px,color:#ffffff
style A2 fill:#133e7c,stroke:#001a4d,stroke-width:3px,color:#ffffff
style H fill:#133e7c,stroke:#001a4d,stroke-width:3px,color:#ffffff
style T13 fill:#0d56b3,stroke:#001a4d,stroke-width:3px,color:#ffffff
%%{init: {
"theme": "base",
"themeVariables": {
"primaryColor": "#0b3d91",
"primaryTextColor": "#ffffff",
"primaryBorderColor": "#001a4d",
"lineColor": "#001a4d",
"tertiaryColor": "#0d56b3",
"clusterBkg": "#0b3d91",
"clusterBorder": "#001a4d"
}
}}%%
flowchart LR
subgraph GW["Fiber API Gateway"]
RL[Rate Limiter - Token Bucket/Redis]
CB[Circuit Breaker]
LB[Load Balancer - RR/Least-Conn]
OD[Outlier Detection]
TR[Transforms - headers/query/rewrite]
AGG[Aggregates - fan-out/fan-in]
CACHE[Response Cache - ETag/TTL]
end
C[(Client)] --> RL --> CB --> TR --> LB --> OD -->|HTTP/WS/gRPC h2c| UP[(Upstreams)]
TR --> AGG --> CACHE
style GW fill:#0b3d91,stroke:#001a4d,stroke-width:2px,color:#ffffff
style RL fill:#133e7c,stroke:#001a4d,color:#ffffff
style CB fill:#133e7c,stroke:#001a4d,color:#ffffff
style LB fill:#133e7c,stroke:#001a4d,color:#ffffff
style OD fill:#133e7c,stroke:#001a4d,color:#ffffff
style TR fill:#0d56b3,stroke:#001a4d,color:#ffffff
style AGG fill:#0d56b3,stroke:#001a4d,color:#ffffff
style CACHE fill:#0d56b3,stroke:#001a4d,color:#ffffff
style C fill:#08315c,stroke:#001a4d,color:#ffffff
style UP fill:#08315c,stroke:#001a4d,color:#ffffff
%%{init: {
"theme": "base",
"themeVariables": {
"primaryColor": "#0b3d91",
"primaryTextColor": "#ffffff",
"primaryBorderColor": "#001a4d",
"lineColor": "#001a4d",
"tertiaryColor": "#0d56b3",
"clusterBkg": "#0b3d91",
"clusterBorder": "#001a4d"
}
}}%%
graph TB
subgraph "Docker Compose"
DCGW[Gateway:8090]
DCW[Warrior:8080]
DCWP[Weapon:8081]
DCE[Enemy:8083]
DCD[Dragon:8084]
DCC[Coin:50051]
DCH[Heal:50058]
DCK[Kafka:9092]
DCR[Redis:6379]
DCPG[Postgres]
DCMG[Mongo]
DCMY[MySQL]
end
subgraph "Kubernetes (Helm)"
KSGW[Deployment fiber-gateway]
KSW[Deployment warrior]
KSWP[Deployment weapon]
KSE[Deployment enemy]
KSD[Deployment dragon]
KSC[Deployment coin]
KSH[Deployment heal]
KSR[bitnami/redis]
KSK[bitnami/kafka + zookeeper]
KSPG[bitnami/postgresql]
KSMG[bitnami/mongodb]
KSMY[bitnami/mysql]
ING[Ingress]
end
DCGW --- DCW & DCWP & DCE & DCD & DCH
DCK --- DCWP & DCE & DCD & DCC & DCH
DCR --- DCGW & DCH
DCPG --- DCW & DCH
DCMG --- DCWP & DCE & DCD
DCMY --- DCC
ING --- KSGW
KSGW --- KSW & KSWP & KSE & KSD & KSH
KSK --- KSWP & KSE & KSD & KSC & KSH
KSR --- KSGW
KSPG --- KSW & KSH
KSMG --- KSWP & KSE & KSD
KSMY --- KSC
style DCGW fill:#0b3d91,stroke:#001a4d,color:#ffffff
style DCW fill:#0d56b3,stroke:#001a4d,color:#ffffff
style DCWP fill:#0d56b3,stroke:#001a4d,color:#ffffff
style DCE fill:#0d56b3,stroke:#001a4d,color:#ffffff
style DCD fill:#0d56b3,stroke:#001a4d,color:#ffffff
style DCC fill:#0d56b3,stroke:#001a4d,color:#ffffff
style DCH fill:#0d56b3,stroke:#001a4d,color:#ffffff
style DCK fill:#133e7c,stroke:#001a4d,color:#ffffff
style DCR fill:#133e7c,stroke:#001a4d,color:#ffffff
style DCPG fill:#133e7c,stroke:#001a4d,color:#ffffff
style DCMG fill:#133e7c,stroke:#001a4d,color:#ffffff
style DCMY fill:#133e7c,stroke:#001a4d,color:#ffffff
style KSGW fill:#0b3d91,stroke:#001a4d,color:#ffffff
style KSW fill:#0d56b3,stroke:#001a4d,color:#ffffff
style KSWP fill:#0d56b3,stroke:#001a4d,color:#ffffff
style KSE fill:#0d56b3,stroke:#001a4d,color:#ffffff
style KSD fill:#0d56b3,stroke:#001a4d,color:#ffffff
style KSC fill:#0d56b3,stroke:#001a4d,color:#ffffff
style KSH fill:#0d56b3,stroke:#001a4d,color:#ffffff
style KSK fill:#133e7c,stroke:#001a4d,color:#ffffff
style KSR fill:#133e7c,stroke:#001a4d,color:#ffffff
style KSPG fill:#133e7c,stroke:#001a4d,color:#ffffff
style KSMG fill:#133e7c,stroke:#001a4d,color:#ffffff
style KSMY fill:#133e7c,stroke:#001a4d,color:#ffffff
style ING fill:#08315c,stroke:#001a4d,color:#ffffff
graph LR
subgraph Topics
T1[weapon.purchase]
T2[enemy.attack]
T3[dragon.death]
T4[enemy.destroyed]
T5[dragon.revival]
T6[battle.started]
T7[battle.completed]
T8[arena.invitation.sent]
T9[arena.invitation.accepted]
T10[arena.invitation.rejected]
T11[arena.invitation.expired]
T12[arena.match.started]
T13[arena.match.completed]
T14[battle.wager.resolved]
end
subgraph Producers
P1[Weapon]
P2[Enemy]
P3[Dragon]
P4[Battle]
P5[Arena]
end
subgraph Consumers
C1[Coin]
C2[Weapon]
C3[Warrior]
C4[Arena]
C5[Heal]
end
P1 --> T1
P2 --> T2
P3 --> T3
P2 --> T4
P3 --> T5
P4 --> T6
P4 --> T7
P5 --> T8
P5 --> T9
P5 --> T10
P5 --> T11
P5 --> T12
P5 --> T13
P4 --> T14
T1 --> C1
T2 --> C1
T3 --> C2
T4 --> C3
T6 --> C5
T7 --> C4
T13 --> C5
T14 --> C1
style T1 fill:#0b3d91,stroke:#001a4d,color:#ffffff
style T2 fill:#0b3d91,stroke:#001a4d,color:#ffffff
style T3 fill:#0b3d91,stroke:#001a4d,color:#ffffff
style T4 fill:#0b3d91,stroke:#001a4d,color:#ffffff
style T5 fill:#0b3d91,stroke:#001a4d,color:#ffffff
style T6 fill:#0b3d91,stroke:#001a4d,color:#ffffff
style T7 fill:#0b3d91,stroke:#001a4d,color:#ffffff
style T8 fill:#0d56b3,stroke:#001a4d,color:#ffffff
style T9 fill:#0d56b3,stroke:#001a4d,color:#ffffff
style T10 fill:#0d56b3,stroke:#001a4d,color:#ffffff
style T11 fill:#0d56b3,stroke:#001a4d,color:#ffffff
style T12 fill:#0d56b3,stroke:#001a4d,color:#ffffff
style T13 fill:#0d56b3,stroke:#001a4d,color:#ffffff
style T14 fill:#0d56b3,stroke:#001a4d,color:#ffffff
style P1 fill:#133e7c,stroke:#001a4d,color:#ffffff
style P2 fill:#133e7c,stroke:#001a4d,color:#ffffff
style P3 fill:#133e7c,stroke:#001a4d,color:#ffffff
style P4 fill:#133e7c,stroke:#001a4d,color:#ffffff
style P5 fill:#133e7c,stroke:#001a4d,color:#ffffff
style C1 fill:#08315c,stroke:#001a4d,color:#ffffff
style C2 fill:#08315c,stroke:#001a4d,color:#ffffff
style C3 fill:#08315c,stroke:#001a4d,color:#ffffff
style C4 fill:#08315c,stroke:#001a4d,color:#ffffff
style C5 fill:#08315c,stroke:#001a4d,color:#ffffff
sequenceDiagram
participant Dev as Developer
participant Local as Local (scripts)
participant DC as Docker Compose
participant Helm as Helmfile (Infra)
participant Chart as Helm (App)
Dev->>Local: ./scripts/heal-build.sh
Note right of Local: Build heal service
Local->>Local: make proto
Local->>Local: go build cmd/heal/main.go
Dev->>Local: ./scripts/heal-run.sh
Note right of Local: Run heal service locally
Local->>Local: Set env vars (Postgres, gRPC, Kafka, Redis)
Dev->>DC: ./scripts/docker-build.sh
Note right of DC: Build all Docker images
DC->>DC: docker build -f dockerfiles/heal.dockerfile
DC-->>Dev: heal:latest image
Dev->>DC: docker-compose up -d
Note right of DC: Start all services
DC->>DC: Start heal service (port 50058)
DC->>DC: Connect to Postgres, Warrior, Coin, Kafka, Redis
Dev->>Helm: helm-apply.sh (infra deps)
Note right of Helm: Deploy infrastructure
Helm->>Helm: Deploy Postgres, MongoDB, MySQL, Kafka, Redis
Dev->>Chart: helm-app-apply.sh (app chart)
Note right of Chart: Deploy all services
Chart->>Chart: Deploy heal service (k8s/base/heal.yaml)
Chart->>Chart: Configure gateway with UPSTREAM_HEAL
Chart-->>Dev: Ingress URL (heal service accessible via gateway)
graph TD
subgraph "Core Services"
W[Warrior Service<br/>Authentication & User Management]
end
subgraph "Game Services"
WP[Weapon Service<br/>Weapon Management]
C[Coin Service<br/>Transaction Management]
E[Enemy Service<br/>Enemy Management]
D[Dragon Service<br/>Dragon Management]
end
subgraph "Infrastructure"
K[Kafka<br/>Event Streaming]
PG[PostgreSQL<br/>Warrior Data]
MG[MongoDB<br/>Game Data]
MY[MySQL<br/>Transaction Data]
end
W --> PG
WP --> MG
E --> MG
D --> MG
C --> MY
WP -.->|gRPC| W
E -.->|gRPC| W
D -.->|gRPC| W
WP -.->|gRPC| C
WP -->|Events| K
E -->|Events| K
D -->|Events| K
C -->|Consume| K
WP -->|Consume| K
style W fill:#0d56b3,stroke:#001a4d,stroke-width:3px,color:#ffffff
style WP fill:#0b3d91,stroke:#001a4d,stroke-width:3px,color:#ffffff
style C fill:#0b3d91,stroke:#001a4d,stroke-width:3px,color:#ffffff
style E fill:#0b3d91,stroke:#001a4d,stroke-width:3px,color:#ffffff
style D fill:#0b3d91,stroke:#001a4d,stroke-width:3px,color:#ffffff
style K fill:#0d56b3,stroke:#001a4d,stroke-width:3px,color:#ffffff
style PG fill:#133e7c,stroke:#001a4d,stroke-width:3px,color:#ffffff
style MG fill:#133e7c,stroke:#001a4d,stroke-width:3px,color:#ffffff
style MY fill:#133e7c,stroke:#001a4d,stroke-width:3px,color:#ffffff
graph TB
subgraph "Warrior Service :8080"
W1[POST /api/v1/warriors/register]
W2[POST /api/v1/warriors/login]
W3[GET /api/v1/warriors/profile]
W4[PUT /api/v1/warriors/profile]
end
subgraph "Weapon Service :8081"
WP1[GET /api/v1/weapons]
WP2[POST /api/v1/weapons]
WP3[POST /api/v1/weapons/:id/buy]
WP4[GET /api/v1/weapons/my-weapons]
end
subgraph "Coin Service :50051"
C1[GetBalance]
C2[DeductCoins]
C3[AddCoins]
C4[TransferCoins]
C5[GetTransactionHistory]
end
subgraph "Enemy Service :8083"
E1[POST /api/v1/enemies]
E2[POST /api/v1/enemies/:id/attack]
E3[GET /api/v1/enemies]
E4[GET /api/v1/enemies/type/:type]
end
subgraph "Dragon Service :8084"
D1[POST /api/v1/dragons]
D2[POST /api/v1/dragons/:id/attack]
D3[GET /api/v1/dragons/:id]
D4[GET /api/v1/dragons/type/:type]
end
subgraph "Battle Service :8085"
B1[POST /api/battles]
B2[POST /api/battles/attack]
B3[GET /api/battles/:id]
B4[GET /api/battles/my-battles]
B5[GET /api/battles/stats]
B6[GET /api/battles/:id/turns]
end
subgraph "Arena Service :8087"
A1[POST /api/v1/arena/invitations]
A2[POST /api/v1/arena/invitations/accept]
A3[POST /api/v1/arena/invitations/reject]
A4[POST /api/v1/arena/invitations/cancel]
A5[GET /api/v1/arena/invitations/:id]
A6[GET /api/v1/arena/invitations/my]
A7[GET /api/v1/arena/matches/my]
A8[GET /api/v1/arena/matches/:id]
A9[POST /api/v1/arena/matches/attack]
end
style W1 fill:#0d56b3,stroke:#001a4d,stroke-width:3px,color:#ffffff
style W2 fill:#0d56b3,stroke:#001a4d,stroke-width:3px,color:#ffffff
style W3 fill:#0d56b3,stroke:#001a4d,stroke-width:3px,color:#ffffff
style W4 fill:#0d56b3,stroke:#001a4d,stroke-width:3px,color:#ffffff
style WP1 fill:#0b3d91,stroke:#001a4d,stroke-width:3px,color:#ffffff
style WP2 fill:#0b3d91,stroke:#001a4d,stroke-width:3px,color:#ffffff
style WP3 fill:#0b3d91,stroke:#001a4d,stroke-width:3px,color:#ffffff
style WP4 fill:#0b3d91,stroke:#001a4d,stroke-width:3px,color:#ffffff
style C1 fill:#133e7c,stroke:#001a4d,stroke-width:3px,color:#ffffff
style C2 fill:#133e7c,stroke:#001a4d,stroke-width:3px,color:#ffffff
style C3 fill:#133e7c,stroke:#001a4d,stroke-width:3px,color:#ffffff
style C4 fill:#133e7c,stroke:#001a4d,stroke-width:3px,color:#ffffff
style C5 fill:#133e7c,stroke:#001a4d,stroke-width:3px,color:#ffffff
style E1 fill:#0b3d91,stroke:#001a4d,stroke-width:3px,color:#ffffff
style E2 fill:#0b3d91,stroke:#001a4d,stroke-width:3px,color:#ffffff
style E3 fill:#0b3d91,stroke:#001a4d,stroke-width:3px,color:#ffffff
style E4 fill:#0b3d91,stroke:#001a4d,stroke-width:3px,color:#ffffff
style D1 fill:#0d56b3,stroke:#001a4d,stroke-width:3px,color:#ffffff
style D2 fill:#0d56b3,stroke:#001a4d,stroke-width:3px,color:#ffffff
style D3 fill:#0d56b3,stroke:#001a4d,stroke-width:3px,color:#ffffff
style D4 fill:#0d56b3,stroke:#001a4d,stroke-width:3px,color:#ffffff
style B1 fill:#133e7c,stroke:#001a4d,stroke-width:3px,color:#ffffff
style B2 fill:#133e7c,stroke:#001a4d,stroke-width:3px,color:#ffffff
style B3 fill:#133e7c,stroke:#001a4d,stroke-width:3px,color:#ffffff
style B4 fill:#133e7c,stroke:#001a4d,stroke-width:3px,color:#ffffff
style B5 fill:#133e7c,stroke:#001a4d,stroke-width:3px,color:#ffffff
style B6 fill:#133e7c,stroke:#001a4d,stroke-width:3px,color:#ffffff
style A1 fill:#0b3d91,stroke:#001a4d,stroke-width:3px,color:#ffffff
style A2 fill:#0b3d91,stroke:#001a4d,stroke-width:3px,color:#ffffff
style A3 fill:#0b3d91,stroke:#001a4d,stroke-width:3px,color:#ffffff
style A4 fill:#0b3d91,stroke:#001a4d,stroke-width:3px,color:#ffffff
style A5 fill:#0b3d91,stroke:#001a4d,stroke-width:3px,color:#ffffff
style A6 fill:#0b3d91,stroke:#001a4d,stroke-width:3px,color:#ffffff
style A7 fill:#0b3d91,stroke:#001a4d,stroke-width:3px,color:#ffffff
style A8 fill:#0b3d91,stroke:#001a4d,stroke-width:3px,color:#ffffff
style A9 fill:#0b3d91,stroke:#001a4d,stroke-width:3px,color:#ffffff
sequenceDiagram
participant Client
participant Warrior as Warrior Service
participant Weapon as Weapon Service
participant Coin as Coin Service
participant Dragon as Dragon Service
participant Kafka as Kafka Events
Note over Client,Kafka: Complete Game Flow
Client->>Warrior: Register & Login
Warrior-->>Client: JWT Token
Client->>Weapon: Buy Weapon
Weapon->>Warrior: Validate Token
Weapon->>Coin: Deduct Coins
Coin-->>Weapon: Payment Success
Weapon->>Kafka: Publish Purchase Event
Weapon-->>Client: Weapon Purchased
Client->>Dragon: Create Dragon (Dark Emperor)
Dragon-->>Client: Dragon Created
Client->>Dragon: Attack Dragon (Light King)
Dragon->>Warrior: Get Warrior Info
Dragon->>Dragon: Calculate Damage
Dragon->>Kafka: Publish Death Event
Weapon->>Kafka: Consume Event
Weapon->>Weapon: Add Loot Weapon
Dragon-->>Client: Dragon Defeated
sequenceDiagram
participant Client
participant Warrior as Warrior Service
participant PG as PostgreSQL
participant Kafka
Note over Client,Kafka: Registration & Login Flow
Client->>Warrior: POST /api/login (username, password)
Warrior->>PG: Query warrior by username
PG-->>Warrior: Warrior data
Warrior->>Warrior: Validate password (bcrypt)
Warrior->>Warrior: Generate JWT token
Warrior-->>Client: JWT token + warrior info
Note over Client,Kafka: Warrior Creation (Light Emperor/King only)
Client->>Warrior: POST /api/warriors (RBAC: Light Emperor/King)
Warrior->>PG: Check username/email uniqueness
Warrior->>Warrior: Hash password (bcrypt)
Warrior->>PG: Create warrior record
Warrior-->>Client: Warrior created
Note over Client,Kafka: Profile Management
Client->>Warrior: GET /api/profile (JWT token)
Warrior->>Warrior: Validate JWT token
Warrior->>PG: Get warrior by ID
PG-->>Warrior: Warrior profile
Warrior-->>Client: Profile data
Note over Client,Kafka: Enemy Kill Tracking (Kafka Consumer)
Kafka->>Warrior: enemy.destroyed event
Warrior->>PG: Update warrior.enemy_kill_count
Warrior->>PG: Insert killed_monster record
sequenceDiagram
participant Client
participant Weapon as Weapon Service
participant Warrior as Warrior Service (gRPC)
participant Coin as Coin Service (gRPC)
participant MongoDB
participant Kafka
Note over Client,Kafka: Weapon Purchase Flow
Client->>Weapon: POST /api/v1/weapons/:id/buy (JWT token)
Weapon->>Weapon: Validate JWT token
Weapon->>Warrior: GetWarriorByUsername (gRPC)
Warrior-->>Weapon: Warrior info (ID, balance, role)
Weapon->>MongoDB: Get weapon by ID
MongoDB-->>Weapon: Weapon data (price, type, attack_power)
Weapon->>Coin: DeductCoins (gRPC)
Coin-->>Weapon: Payment confirmed
Weapon->>MongoDB: Add warrior ID to weapon.owned_by array
Weapon->>Kafka: Publish weapon.purchase event
Weapon-->>Client: Weapon purchased successfully
Note over Client,Kafka: Weapon Creation (Light Emperor/King only)
Client->>Weapon: POST /api/v1/weapons (RBAC check)
Weapon->>Warrior: GetWarriorByUsername (gRPC)
Warrior-->>Weapon: Verify role (light_emperor/light_king)
Weapon->>MongoDB: Create weapon document
Weapon-->>Client: Weapon created
Note over Client,Kafka: Loot Weapon from Dragon (Kafka Consumer)
Kafka->>Weapon: dragon.death event
Weapon->>MongoDB: Create loot weapon based on dragon stats
Weapon->>MongoDB: Set owned_by to [] (unowned)
sequenceDiagram
participant Client
participant Coin as Coin Service (gRPC)
participant Warrior as Warrior Service (gRPC)
participant MySQL
participant Kafka
Note over Client,Kafka: Get Balance (gRPC)
Client->>Coin: GetBalance(warrior_id)
Coin->>Warrior: GetWarriorByID (gRPC)
Warrior-->>Coin: Warrior data (current balance)
Coin-->>Client: Balance
Note over Client,Kafka: Deduct Coins (gRPC)
Client->>Coin: DeductCoins(warrior_id, amount, reason)
Coin->>Warrior: GetWarriorByID (gRPC)
Warrior-->>Coin: Current balance
Coin->>Coin: Validate sufficient balance
Coin->>MySQL: Insert transaction (deduct)
Coin->>Warrior: UpdateBalance (gRPC)
Coin-->>Client: New balance
Note over Client,Kafka: Add Coins (gRPC)
Client->>Coin: AddCoins(warrior_id, amount, reason)
Coin->>MySQL: Insert transaction (add)
Coin->>Warrior: UpdateBalance (gRPC)
Coin-->>Client: New balance
Note over Client,Kafka: Kafka Consumer - Weapon Purchase
Kafka->>Coin: weapon.purchase event
Coin->>Coin: DeductCoins (internal call)
Coin->>MySQL: Log transaction
Coin->>Warrior: UpdateBalance (gRPC)
Note over Client,Kafka: Kafka Consumer - Enemy Attack
Kafka->>Coin: enemy.attack event
Coin->>Coin: DeductCoins (penalty)
Coin->>MySQL: Log transaction
Coin->>Warrior: UpdateBalance (gRPC)
sequenceDiagram
participant Client
participant Enemy as Enemy Service
participant Warrior as Warrior Service (gRPC)
participant MongoDB
participant Kafka
Note over Client,Kafka: Create Enemy (Dark Emperor/King only)
Client->>Enemy: POST /api/v1/enemies (RBAC: Dark Emperor/King)
Enemy->>Warrior: GetWarriorByUsername (gRPC)
Warrior-->>Enemy: Verify role (dark_emperor/dark_king)
Enemy->>MongoDB: Create enemy document
Enemy-->>Client: Enemy created
Note over Client,Kafka: Attack Warrior
Client->>Enemy: POST /api/v1/enemies/:id/attack (warrior_name)
Enemy->>Warrior: GetWarriorByUsername (gRPC)
Warrior-->>Enemy: Warrior stats (HP, defense, etc.)
Enemy->>Enemy: Calculate damage (enemy.attack - warrior.defense)
Enemy->>Kafka: Publish enemy.attack event
Coin->>Kafka: Consume enemy.attack event
Coin->>Coin: Deduct coins from warrior (penalty)
Enemy-->>Client: Attack result
Note over Client,Kafka: Enemy Destroyed (Kafka Event)
Enemy->>Kafka: Publish enemy.destroyed event
Warrior->>Kafka: Consume enemy.destroyed event
Warrior->>Warrior: Update warrior.enemy_kill_count
Warrior->>Warrior: Update warrior.title (if threshold reached)
sequenceDiagram
participant Client
participant Dragon as Dragon Service
participant Warrior as Warrior Service (gRPC)
participant MongoDB
participant Kafka
Note over Client,Kafka: Create Dragon (Dark Emperor only)
Client->>Dragon: POST /api/v1/dragons (RBAC: Dark Emperor)
Dragon->>Warrior: GetWarriorByUsername (gRPC)
Warrior-->>Dragon: Verify role (dark_emperor)
Dragon->>MongoDB: Create dragon document (revival_count=0, is_alive=true)
Dragon-->>Client: Dragon created
Note over Client,Kafka: Attack Dragon (Light King/Emperor)
Client->>Dragon: POST /api/v1/dragons/:id/attack (warrior_name)
Dragon->>Warrior: GetWarriorByUsername (gRPC)
Warrior-->>Dragon: Warrior stats (attack_power, role)
Dragon->>Dragon: Validate role (light_king/light_emperor)
Dragon->>Dragon: Calculate damage
Dragon->>MongoDB: Update dragon.health
alt Dragon dies (HP <= 0)
Dragon->>MongoDB: Update dragon (is_alive=false, killed_by, killed_at)
Dragon->>Dragon: Check revival_count < 3
alt Can revive (revival_count < 3)
alt revival_count == 2 (Needs crisis intervention)
Dragon->>MongoDB: Set awaiting_crisis_intervention=true
Dragon->>Kafka: Publish dragon.death event
else revival_count < 2 (Auto-revive possible)
Dragon->>Kafka: Publish dragon.death event
end
else Cannot revive (revival_count >= 3)
Dragon->>Kafka: Publish dragon.death event (permanent death)
end
Weapon->>Kafka: Consume dragon.death event
Weapon->>Weapon: Add loot weapon
end
Dragon-->>Client: Attack result
Note over Client,Kafka: Dragon Revival Flow
Client->>Dragon: POST /api/v1/dragons/:id/revive
Dragon->>MongoDB: Get dragon by ID
Dragon->>Dragon: Check revival_count < 3
Dragon->>Dragon: Check awaiting_crisis_intervention
Dragon->>MongoDB: Update dragon (health=max_health, is_alive=true, revival_count++, awaiting_crisis_intervention=false)
Dragon->>Kafka: Publish dragon.revival event
Dragon-->>Client: Dragon revived
sequenceDiagram
participant Client
participant Battle as Battle Service
participant Warrior as Warrior Service (gRPC)
participant Dragon as Dragon Service (HTTP)
participant Coin as Coin Service (gRPC)
participant Battlespell as Battlespell Service (gRPC)
participant MongoDB
participant Kafka
Note over Client,Kafka: Start Team Battle
Client->>Battle: POST /api/battles (light/dark participants)
Battle->>Warrior: GetWarriorByID (gRPC) for each participant
Warrior-->>Battle: Warrior stats (HP, attack, defense)
Battle->>Battle: Validate team composition (hierarchy rules)
Battle->>MongoDB: Create battle document
Battle->>MongoDB: Create battle_participants documents
Battle->>Battle: Start battle (status=in_progress)
Battle->>Kafka: Publish battle.started event
Battle-->>Client: Battle created
Note over Client,Kafka: Attack in Battle
Client->>Battle: POST /api/battles/attack (attacker_id, target_id)
Battle->>MongoDB: Get battle and participants
Battle->>Battle: Validate attacker and target on different sides
Battle->>Battle: Calculate damage (attacker.attack - target.defense)
Battle->>MongoDB: Update target.HP
alt Target defeated
Battle->>MongoDB: Update target (is_alive=false, is_defeated=true)
alt Target is Dragon
Battle->>Dragon: Check revival status (HTTP GET)
Dragon-->>Battle: revival_count, can_revive, awaiting_crisis_intervention
alt Can auto-revive (revival_count < 2)
Battle->>Battle: Schedule auto-revive (5 seconds)
Battle->>Dragon: POST /revive (HTTP)
Dragon->>MongoDB: Update dragon (revival_count++, health=max_health)
Dragon->>Kafka: Publish dragon.revival event
Battle->>MongoDB: Update participant (HP=max_health, is_alive=true)
else Needs crisis intervention (revival_count == 2)
Battle->>Battle: Log to Redis (crisis intervention required)
end
end
alt Attacker is Dragon and target is Warrior
Battle->>Battlespell: TriggerWraithOfDragon (gRPC)
Battlespell->>Battle: UpdateParticipantStats (gRPC) - destroy random warrior
end
Battle->>Battle: Check if team eliminated
alt Team eliminated
Battle->>Battle: Complete battle
Battle->>Coin: AddCoins (gRPC) for winning team
Battle->>Kafka: Publish battle.completed event
end
end
Battle->>MongoDB: Update battle (current_turn++)
Battle-->>Client: Attack result
Note over Client,Kafka: Dark Emperor Crisis Intervention
Client->>Battle: POST /api/battles/dark-emperor-join (dragon_participant_id)
Battle->>Warrior: GetWarriorByUsername (gRPC)
Warrior-->>Battle: Verify role (dark_emperor)
Battle->>Dragon: Check dragon status (HTTP GET)
Dragon-->>Battle: revival_count == 2, is_alive == true (1 life left)
Battle->>MongoDB: Create participant (dark_emperor)
Battle->>MongoDB: Update battle
Battle-->>Client: Dark Emperor joined
Note over Client,Kafka: Sacrifice Dragon
Client->>Battle: POST /api/battles/sacrifice-dragon (dragon_participant_id)
Battle->>Dragon: Check dragon revival_count (HTTP GET)
Dragon-->>Battle: revival_count value
Battle->>Battle: Calculate multiplier (3x if revival_count=0, 2x if revival_count=1, 1x otherwise)
Battle->>MongoDB: Get all enemies (alive and dead)
Battle->>MongoDB: Duplicate enemies (multiplier - 1 copies)
Battle->>MongoDB: Revive all dead enemies (HP=max_health)
alt revival_count > 0
Battle->>MongoDB: Update dragon participant (is_alive=false, is_defeated=true)
end
Battle-->>Client: Enemies revived and multiplied
sequenceDiagram
participant Client
participant BattleGateway as Battle Service (HTTP)
participant Battlespell as Battlespell Service
participant Battle as Battle Service (gRPC)
participant Warrior as Warrior Service (gRPC)
participant MongoDB
participant Kafka
Note over Client,Kafka: Cast Spell (Light King)
Client->>BattleGateway: POST /api/battles/cast-spell (spell_type: call_of_the_light_king)
BattleGateway->>BattleGateway: RBAC check (light_king/dark_king only)
BattleGateway->>Battlespell: CastSpell (gRPC)
Battlespell->>Warrior: GetWarriorByUsername (gRPC)
Warrior-->>Battlespell: Verify role (light_king)
Battlespell->>Battlespell: Validate spell type (CanBeCastBy role)
Battlespell->>Battle: GetBattleParticipants (gRPC, side=light)
Battle-->>Battlespell: Light side participants
Battlespell->>Battle: UpdateParticipantStats (gRPC, attack_power * 2)
Battle-->>Battlespell: Stats updated
Battlespell->>MongoDB: Create spell document (is_active=true)
Battlespell-->>BattleGateway: Spell cast successfully
BattleGateway-->>Client: Spell cast (affected_count)
Note over Client,Kafka: Cast Spell (Dark King)
Client->>BattleGateway: POST /api/battles/cast-spell (spell_type: destroy_the_light)
BattleGateway->>Battlespell: CastSpell (gRPC)
Battlespell->>Battlespell: Validate spell (dark_king only)
Battlespell->>Battle: GetBattleParticipants (gRPC, side=light)
Battlespell->>MongoDB: Check existing spell (stack_count)
alt stack_count == 0 (first cast)
Battlespell->>Battle: UpdateParticipantStats (gRPC, attack/defense * 0.7)
Battlespell->>MongoDB: Update spell (stack_count=1)
else stack_count == 1 (second cast)
Battlespell->>Battle: UpdateParticipantStats (gRPC, attack/defense * 0.49)
Battlespell->>MongoDB: Update spell (stack_count=2)
else stack_count >= 2
Battlespell-->>BattleGateway: Error: Maximum stack reached
end
Battlespell-->>Client: Spell stacked successfully
Note over Client,Kafka: Wraith of Dragon (Triggered by Battle Service)
Battle->>Battlespell: TriggerWraithOfDragon (gRPC, battle_id)
Battlespell->>MongoDB: Get spell (spell_type=wraith_of_dragon, is_active=true)
MongoDB-->>Battlespell: Spell (wraith_count)
alt wraith_count < 25
Battlespell->>Battle: GetBattleParticipants (gRPC, side=light, is_alive=true)
Battle-->>Battlespell: Alive warriors
Battlespell->>Battlespell: Select random warrior
Battlespell->>Battle: UpdateParticipantStats (gRPC, HP=0, is_alive=false)
Battlespell->>MongoDB: Update spell (wraith_count++)
Battlespell-->>Battle: Triggered (destroyed_warrior_id, wraith_count)
else wraith_count >= 25
Battlespell-->>Battle: Error: Maximum wraith count reached
end
%%{init: {
"theme": "base",
"themeVariables": {
"primaryColor": "#1f1f1f",
"primaryTextColor": "#f0f0f0",
"primaryBorderColor": "#6b6b6b",
"lineColor": "#6b6b6b",
"tertiaryColor": "#3c3c3c",
"clusterBkg": "#1f1f1f",
"clusterBorder": "#6b6b6b"
}
}}%%
graph TB
subgraph Repair[Repair Service Container]
APP["Repair App (Go)"]
GRPC["gRPC Server :50061"]
DB["PostgreSQL Client (GORM)"]
KAFKA[Kafka Producer]
WCLI[Weapon gRPC Client]
end
GRPC -->|Listen| EXT[External Clients]
APP --> GRPC
APP --> DB
APP --> KAFKA
APP --> WCLI
DB -->|Connect| PSQL[(PostgreSQL)]
KAFKA -->|Publish| KTopic[(weapon.repair)]
WCLI -->|Call| WeaponSvc[Weapon Service]
%%{init: {
"theme": "base",
"themeVariables": {
"primaryColor": "#2b2b2b",
"primaryTextColor": "#e0e0e0",
"primaryBorderColor": "#5a5a5a",
"lineColor": "#5a5a5a"
}
}}%%
flowchart LR
Client((Client)) --> GW["API Gateway\nh2c gRPC proxy"]
GW --> RepairUp[(repair:50061)]
Client --> GW
GW --> WeaponUp[(weapon:50057)]
sequenceDiagram
participant Client1 as Challenger Client
participant Client2 as Opponent Client
participant Arena as Arena Service
participant Warrior as Warrior Service (gRPC)
participant MongoDB
participant Kafka
Note over Client1,Kafka: Send Invitation
Client1->>Arena: POST /api/v1/arena/invitations (opponent_name)
Arena->>Arena: Validate (cannot challenge yourself)
Arena->>Warrior: GetWarriorByUsername (gRPC, opponent_name)
Warrior-->>Arena: Opponent info (ID, username)
Arena->>MongoDB: Check for existing pending invitation
Arena->>MongoDB: Create invitation (status=pending, expires_at=+10min)
Arena->>Kafka: Publish arena.invitation.sent event
Arena-->>Client1: Invitation sent
Note over Client1,Kafka: Accept Invitation
Client2->>Arena: POST /api/v1/arena/invitations/accept (invitation_id)
Arena->>MongoDB: Get invitation by ID
Arena->>Arena: Validate (opponent can accept, not expired)
Arena->>Warrior: GetWarriorByID (gRPC, challenger_id)
Warrior-->>Arena: Challenger stats (HP, attack, defense)
Arena->>Warrior: GetWarriorByID (gRPC, opponent_id)
Warrior-->>Arena: Opponent stats (HP, attack, defense)
Arena->>Arena: Calculate HP (total_power * 10, min 100)
Arena->>MongoDB: Create arena_match (status=in_progress, current_attacker=1)
Arena->>MongoDB: Update invitation (status=accepted, battle_id=match_id)
Arena->>Kafka: Publish arena.invitation.accepted event
Arena->>Kafka: Publish arena.match.started event
Arena-->>Client2: Match started
Note over Client1,Kafka: Attack in Arena Match
Client1->>Arena: POST /api/v1/arena/matches/attack (match_id)
Arena->>MongoDB: Get match by ID
Arena->>Arena: Validate (match in progress, correct turn)
Arena->>Arena: Calculate damage (attacker.attack - defender.defense, min 10)
Arena->>Arena: Apply damage to defender.HP
alt Defender HP <= 0 (Defeated)
Arena->>MongoDB: Update match (status=completed, winner_id=attacker_id)
Arena->>Kafka: Publish arena.match.completed event
Arena-->>Client1: Match completed (winner)
else CurrentTurn >= MaxTurns (Timeout)
Arena->>Arena: Determine winner by HP (or draw)
Arena->>MongoDB: Update match (status=completed, winner_id or null)
Arena->>Kafka: Publish arena.match.completed event
Arena-->>Client1: Match completed (winner/draw)
else Continue
Arena->>MongoDB: Update match (current_turn++, current_attacker=switch)
Arena-->>Client1: Attack successful (updated HP)
end
Note over Client1,Kafka: Reject Invitation
Client2->>Arena: POST /api/v1/arena/invitations/reject (invitation_id)
Arena->>MongoDB: Update invitation (status=rejected)
Arena->>Kafka: Publish arena.invitation.rejected event
Arena-->>Client2: Invitation rejected
sequenceDiagram
participant Arena as Arena Service
participant Kafka as Kafka Events
participant Consumer as Event Consumers
Note over Arena,Consumer: Invitation Lifecycle Events
Arena->>Kafka: arena.invitation.sent (challenger, opponent, expires_at)
Note right of Kafka: Topic: arena.invitation.sent
alt Invitation Accepted
Arena->>Kafka: arena.invitation.accepted (challenger, opponent, match_id)
Arena->>Kafka: arena.match.started (player1, player2, match_id)
Note right of Kafka: Topics: arena.invitation.accepted<br/>arena.match.started
else Invitation Rejected
Arena->>Kafka: arena.invitation.rejected (challenger, opponent)
Note right of Kafka: Topic: arena.invitation.rejected
else Invitation Expired
Arena->>Kafka: arena.invitation.expired (challenger, opponent)
Note right of Kafka: Topic: arena.invitation.expired
end
Note over Arena,Consumer: Match Completion Event
Arena->>Arena: Match ends (winner determined)
Arena->>Kafka: arena.match.completed (player1, player2, winner, match_id)
Note right of Kafka: Topic: arena.match.completed
Consumer->>Kafka: Consume match completed (analytics, notifications)
graph TB
subgraph "Invitation Events"
E1[arena.invitation.sent<br/>Challenger sends invitation]
E2[arena.invitation.accepted<br/>Opponent accepts]
E3[arena.invitation.rejected<br/>Opponent rejects]
E4[arena.invitation.expired<br/>10 min timeout]
E5[arena.invitation.cancelled<br/>Challenger cancels]
end
subgraph "Match Events"
E6[arena.match.started<br/>Both players accepted]
E7[arena.match.completed<br/>Winner determined]
end
subgraph "Event Flow"
E1 -->|Opponent accepts| E2
E1 -->|Opponent rejects| E3
E1 -->|Timeout| E4
E1 -->|Challenger cancels| E5
E2 -->|Match created| E6
E6 -->|Match ends| E7
end
style E1 fill:#0b3d91,stroke:#001a4d,color:#ffffff
style E2 fill:#0d56b3,stroke:#001a4d,color:#ffffff
style E3 fill:#8b0000,stroke:#001a4d,color:#ffffff
style E4 fill:#8b0000,stroke:#001a4d,color:#ffffff
style E5 fill:#8b0000,stroke:#001a4d,color:#ffffff
style E6 fill:#0b3d91,stroke:#001a4d,color:#ffffff
style E7 fill:#0d56b3,stroke:#001a4d,color:#ffffff
sequenceDiagram
participant Client
participant Heal as ๐ Heal Service
participant Warrior as ๐ก๏ธ Warrior Service (gRPC)
participant Coin as ๐ฐ Coin Service (gRPC)
participant Kafka
participant PG as ๐พ PostgreSQL
Note over Client,PG: โ๏ธ Purchase Healing Package Flow
Client->>Heal: PurchaseHeal(warrior_id, heal_type, warrior_role)
Heal->>Warrior: GetWarriorByID (gRPC)
Warrior-->>Heal: Warrior info (HP, role, is_healing)
alt Warrior is currently healing
Heal->>Heal: Check healing_until timestamp
alt Healing not completed
Heal-->>Client: โ ๏ธ Error: Already healing (remaining time)
else Healing completed
Heal->>Warrior: UpdateWarriorHealingState (clear state)
end
end
Heal->>Heal: GetHealPackageByType (role-based validation)
Heal->>Heal: Validate role can use package (RBAC)
Heal->>Coin: ๐ฐ DeductCoins (gRPC, package price)
Coin-->>Heal: โ
Payment confirmed
Heal->>Warrior: UpdateWarriorHealingState (is_healing=true, healing_until)
Heal->>PG: Save healing record (duration, completed_at)
Note over Heal: โฑ๏ธ Background goroutine scheduled
Heal->>Heal: Schedule HP update after duration
Heal-->>Client: โ
Healing started (duration, coins_spent)
Note over Heal,PG: ๐ Healing Completion (Background)
Heal->>Heal: Wait for duration (15s - 1h)
Heal->>Warrior: UpdateWarriorHP (gRPC, new HP)
Warrior-->>Heal: โ
HP updated
Heal->>Warrior: UpdateWarriorHealingState (is_healing=false)
Heal->>Heal: ๐ Log healing completion
graph TB
subgraph "๐ก๏ธ Warrior Packages"
WF[๐ Full Heal<br/>๐ฐ 100 coins<br/>โฑ๏ธ 5 minutes]
WP[๐ 50% Heal<br/>๐ฐ 50 coins<br/>โฑ๏ธ 3 minutes]
end
subgraph "๐ Emperor Packages"
EF[โจ Emperor Full Heal<br/>๐ฐ 20 coins<br/>โก 30 seconds]
EP[โจ Emperor Quick Heal<br/>๐ฐ 10 coins<br/>โก 15 seconds]
end
subgraph "๐ Dragon Package"
DH[๐ฅ Dragon Heal<br/>๐ฐ 1000 coins<br/>โฑ๏ธ 1 hour<br/>๐ณ Paid by Dark Emperor]
end
subgraph "๐ฅ Roles"
W[๐ก๏ธ Warrior Role]
E[๐ Emperor Role<br/>light_emperor<br/>dark_emperor]
D[๐ Dragon Role]
end
W --> WF
W --> WP
W --> EF
W --> EP
E --> EF
E --> EP
E --> WF
E --> WP
D --> DH
D --> WF
D --> WP
style WF fill:#2ecc71,stroke:#27ae60,color:#ffffff
style WP fill:#2ecc71,stroke:#27ae60,color:#ffffff
style EF fill:#1abc9c,stroke:#16a085,color:#ffffff
style EP fill:#1abc9c,stroke:#16a085,color:#ffffff
style DH fill:#8b0000,stroke:#5a0000,color:#ffffff
style W fill:#3498db,stroke:#2980b9,color:#ffffff
style E fill:#f39c12,stroke:#e67e22,color:#ffffff
style D fill:#e74c3c,stroke:#c0392b,color:#ffffff
stateDiagram-v2
[*] --> WarriorHealthy: โ
Warrior at full HP
WarriorHealthy --> PurchaseHealing: โ๏ธ Battle/Arena completed<br/>๐ HP reduced
PurchaseHealing --> HealingInProgress: ๐ฐ Payment successful<br/>๐ณ Coins deducted
HealingInProgress --> HealingCompleted: โฑ๏ธ Duration elapsed<br/>๐ HP restored
HealingInProgress --> BattleBlocked: โ Attempt to start battle<br/>๐ Check healing state
HealingCompleted --> WarriorHealthy: โ
HP updated
BattleBlocked --> HealingInProgress: โณ Wait for completion
note right of HealingInProgress
๐ is_healing = true
โฑ๏ธ healing_until = timestamp
โ Cannot start battles/arena
end note
note right of HealingCompleted
โ
is_healing = false
๐งน healing_until = null
๐ HP updated to target value
end note
sequenceDiagram
participant Client
participant Battle as โ๏ธ Battle Service
participant Arena as ๐๏ธ Arena Service
participant Heal as ๐ Heal Service
participant Warrior as ๐ก๏ธ Warrior Service (gRPC)
participant Dragon as ๐ Dragon Service (gRPC)
participant Enemy as ๐น Enemy Service (gRPC)
participant Kafka
Note over Client,Kafka: โ๏ธ Battle Start with Healing Check
Client->>Battle: POST /api/battles (start battle)
Battle->>Warrior: GetWarriorByID (gRPC, participant IDs)
Warrior-->>Battle: Warrior info (is_healing, healing_until)
Battle->>Dragon: CheckDragonCanBattle (gRPC, dragon participants)
Dragon-->>Battle: Dragon battle eligibility
Battle->>Enemy: CheckEnemyCanBattle (gRPC, enemy participants)
Enemy-->>Battle: Enemy battle eligibility
alt Participant is healing
Battle->>Battle: CheckWarriorCanBattle (validation)
Battle-->>Client: โ ๏ธ Error: Participant is healing (remaining time)
else All participants ready
Battle->>Battle: Start battle (create participants)
Battle-->>Client: โ
Battle started
end
Note over Client,Kafka: ๐๏ธ Arena Match Start with Healing Check
Client->>Arena: POST /api/v1/arena/invitations/accept
Arena->>Warrior: GetWarriorByID (gRPC, challenger_id)
Warrior-->>Arena: Challenger info (is_healing)
Arena->>Warrior: GetWarriorByID (gRPC, opponent_id)
Warrior-->>Arena: Opponent info (is_healing)
alt Challenger or Opponent is healing
Arena-->>Client: โ ๏ธ Error: Warrior is healing (cannot start match)
else Both warriors ready
Arena->>Arena: Create match
Arena-->>Client: โ
Match started
end
Note over Client,Kafka: ๐ Battle/Arena Completion Triggers Healing
Battle->>Kafka: battle.completed event
Arena->>Kafka: arena.match.completed event
Heal->>Kafka: Consume battle.completed / arena.match.completed
Heal->>Heal: ๐ Log healing availability (participants can now heal)
sequenceDiagram
participant Battle as โ๏ธ Battle Service
participant Arena as ๐๏ธ Arena Service
participant Kafka as ๐จ Kafka Events
participant Heal as ๐ Heal Service
participant Warrior as ๐ก๏ธ Warrior Service
participant Dragon as ๐ Dragon Service
participant Enemy as ๐น Enemy Service
Note over Battle,Enemy: โ๏ธ Battle Completion Event
Battle->>Battle: Battle completed (winner determined)
Battle->>Kafka: ๐จ battle.completed (winner_id, loser_id, participants)
Kafka->>Heal: ๐ฅ Consume battle.completed
Heal->>Heal: ๐ Log healing available for participants<br/>(Warrior, Dragon, Enemy)
Note over Arena,Enemy: ๐๏ธ Arena Match Completion Event
Arena->>Arena: Match completed (winner determined)
Arena->>Kafka: ๐จ arena.match.completed (player1_id, player2_id, winner_id)
Kafka->>Heal: ๐ฅ Consume arena.match.completed
Heal->>Heal: ๐ Log healing available for players
Note over Heal,Enemy: ๐ Healing Purchase Flow (All Participants)
Heal->>Warrior: GetWarriorByID (check healing state)
Warrior-->>Heal: is_healing, healing_until
Heal->>Dragon: GetDragonByID (check healing state)
Dragon-->>Heal: is_healing, healing_until
Heal->>Enemy: GetEnemyByID (check healing state)
Enemy-->>Heal: is_healing, healing_until
Heal->>Heal: โ
Validate healing state
Heal->>Heal: โ๏ธ Purchase healing package<br/>(Warrior/Dragon/Enemy)
Heal->>Warrior: UpdateWarriorHealingState (set is_healing=true)
Heal->>Dragon: UpdateDragonHealingState (set is_healing=true)
Heal->>Enemy: UpdateEnemyHealingState (set is_healing=true)
Heal->>Heal: โฑ๏ธ Schedule HP update after duration
stateDiagram-v2
[*] --> InvitationSent: POST /invitations
InvitationSent --> InvitationAccepted: Opponent accepts
InvitationSent --> InvitationRejected: Opponent rejects
InvitationSent --> InvitationExpired: 10 min timeout
InvitationSent --> InvitationCancelled: Challenger cancels
InvitationAccepted --> MatchStarted: Create match
MatchStarted --> MatchInProgress: Start battle
MatchInProgress --> MatchCompleted: Winner determined
MatchInProgress --> MatchCompleted: Timeout (MaxTurns)
InvitationRejected --> [*]
InvitationExpired --> [*]
InvitationCancelled --> [*]
MatchCompleted --> [*]
note right of InvitationSent
Event: arena.invitation.sent
end note
note right of InvitationAccepted
Event: arena.invitation.accepted
end note
note right of MatchStarted
Event: arena.match.started
end note
note right of MatchCompleted
Event: arena.match.completed
end note
graph TB
subgraph "Arena Invitation Sent Event"
ES[arena.invitation.sent]
ES1[invitation_id: string]
ES2[challenger_id: uint]
ES3[challenger_name: string]
ES4[opponent_id: uint]
ES5[opponent_name: string]
ES6[expires_at: RFC3339]
ES --> ES1
ES --> ES2
ES --> ES3
ES --> ES4
ES --> ES5
ES --> ES6
end
subgraph "Arena Invitation Accepted Event"
EA[arena.invitation.accepted]
EA1[invitation_id: string]
EA2[challenger_id: uint]
EA3[opponent_id: uint]
EA4[battle_id: string]
EA --> EA1
EA --> EA2
EA --> EA3
EA --> EA4
end
subgraph "Arena Match Started Event"
MS[arena.match.started]
MS1[match_id: string]
MS2[player1_id: uint]
MS3[player2_id: uint]
MS4[battle_id: string]
MS --> MS1
MS --> MS2
MS --> MS3
MS --> MS4
end
subgraph "Arena Match Completed Event"
MC[arena.match.completed]
MC1[match_id: string]
MC2[player1_id: uint]
MC3[player2_id: uint]
MC4[winner_id: uint?]
MC5[winner_name: string]
MC --> MC1
MC --> MC2
MC --> MC3
MC --> MC4
MC --> MC5
end
style ES fill:#0b3d91,stroke:#001a4d,color:#ffffff
style EA fill:#0d56b3,stroke:#001a4d,color:#ffffff
style MS fill:#0b3d91,stroke:#001a4d,color:#ffffff
style MC fill:#0d56b3,stroke:#001a4d,color:#ffffff
Tรผm HTTP servisleri iรงin Swagger/OpenAPI dokรผmantasyonu mevcuttur. Swagger UI ile API endpoint'lerini test edebilir ve detaylฤฑ dokรผmantasyona eriลebilirsiniz.
- Warrior Service: http://localhost:8080/swagger/index.html
- Weapon Service: http://localhost:8081/swagger/index.html
- Dragon Service: http://localhost:8084/swagger/index.html
- Battle Service: http://localhost:8085/swagger/index.html
Swagger dokรผmantasyonlarฤฑnฤฑ yeniden oluลturmak iรงin:
# Otomatik script ile tรผm servisler iรงin
./scripts/swagger-gen.sh
# Veya manuel olarak her servis iรงin
cd cmd/warrior && swag init --parseDependency --parseInternal
cd cmd/weapon && swag init --parseDependency --parseInternal
cd cmd/dragon && swag init --parseDependency --parseInternal
cd cmd/battle && swag init --parseDependency --parseInternalรoฤu endpoint JWT token ile korunmaktadฤฑr. Swagger UI'da token kullanmak iรงin:
- Swagger UI'ฤฑn saฤ รผstรผndeki "Authorize" ๐ butonuna tฤฑklayฤฑn
Bearer <your-jwt-token>formatฤฑnda token'ฤฑ girin- รrnek:
Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Token almak iรงin /api/login endpoint'ini kullanabilirsiniz.
- Authentication: Login, Profile
- Warrior Management: CRUD operations (King only)
- Profile: Password change, Killed monsters, Strongest kill
- Role-based: Knights, Archers, Mages listing
- Weapon Listing: Get all weapons, filter by type
- Weapon Purchase: Buy weapons (triggers Kafka events)
- My Weapons: List owned weapons
- Admin: Create weapons (Light Emperor/King only)
- Dragon Management: Create, Attack, Get by ID
- Filtering: Get by type, Get by creator
- Events: Dragon death events published to Kafka
- Battle Management: Start battle, Attack, Get battle details
- Battle History: Get battles with RBAC (Emperors see all, Kings see faction, Warriors see own)
- Battle Statistics: Win rate, total battles, coins/experience earned
- Turn-based Combat: Turn history, damage tracking
- Rewards: Automatic coin rewards/penalties via gRPC
- โ๏ธ Healing Packages: Role-based healing packages (Warrior, Emperor, Dragon)
- ๐ Warrior: Full Heal (100 coins, 5 min) | 50% Heal (50 coins, 3 min)
- ๐ Emperor: Fast Full Heal (20 coins, 30 sec) | Quick Heal (10 coins, 15 sec)
- ๐ Dragon: Powerful Heal (1000 coins, 1 hour) - Paid by Dark Emperor
- โฑ๏ธ Healing Duration: Time-based healing with blocking during healing period
- ๐ RBAC: Role-based access control for healing packages
- ๐ HP Management: Updates HP via gRPC after healing duration (Warrior, Dragon, Enemy)
- ๐ก Event-Driven: Listens to
battle.completedandarena.match.completedevents - ๐พ Database: PostgreSQL (GORM) for healing records storage
- ๐ Redis Logging: Real-time healing progress logging to Redis Streams
healing:logs:{participant_id}: Redis Stream for healing events- Status tracking:
started,in_progress,completed,failed - Progress updates: Every 5 seconds during healing
- Timeline: Sorted set for chronological access
- ๐ฐ Coin Payment Logic:
- ๐ก๏ธ Warrior: Pays from own balance
- ๐น Enemy: Pays from own balance
- ๐ Dragon: Paid by Dark Emperor (creator)
- gRPC Endpoints:
PurchaseHeal: Purchase healing package (supports Warrior, Dragon, Enemy)GetHealingHistory: Retrieve healing history for a participant
- Coin Service: gRPC servis olduฤu iรงin protobuf dosyalarฤฑndan dokรผmantasyon oluลturulabilir (
api/proto/coin/coin.proto) - Heal Service: gRPC servis olduฤu iรงin protobuf dosyalarฤฑndan dokรผmantasyon oluลturulabilir (
api/proto/heal/heal.proto) - Enemy Service: ลu anda HTTP endpoint'leri implement edilmemiลtir (sadece Kafka consumer)
- API Gateway: Gateway รผzerinden eriลilen servislerin dokรผmantasyonlarฤฑ kendi servis portlarฤฑndan eriลilebilir. HealService gRPC proxy route:
/heal.HealService
graph TB
subgraph "๐ณ Docker Compose Services"
DCPG[๐พ PostgreSQL<br/>heal_db]
DCR[๐ Redis<br/>๐ Healing State Cache]
DCK[๐จ Kafka<br/>Events]
DCH[๐ Heal Service<br/>:50058]
DCW[๐ก๏ธ Warrior Service<br/>:50052]
DCC[๐ฐ Coin Service<br/>:50051]
DCD[๐ Dragon Service<br/>:50059]
DCE[๐น Enemy Service<br/>:50060]
DCGW[๐ Gateway<br/>:8090]
end
DCH -->|Read/Write| DCPG
DCH -->|๐ Cache| DCR
DCH -->|Consume Events| DCK
DCH -->|gRPC| DCW
DCH -->|gRPC| DCC
DCH -->|gRPC| DCD
DCH -->|gRPC| DCE
DCGW -->|gRPC Proxy| DCH
style DCH fill:#2ecc71,stroke:#27ae60,color:#ffffff
style DCPG fill:#3498db,stroke:#2980b9,color:#ffffff
style DCR fill:#e74c3c,stroke:#c0392b,color:#ffffff
style DCK fill:#9b59b6,stroke:#8e44ad,color:#ffffff
style DCW fill:#3498db,stroke:#2980b9,color:#ffffff
style DCC fill:#f39c12,stroke:#e67e22,color:#ffffff
style DCD fill:#8b0000,stroke:#5a0000,color:#ffffff
style DCE fill:#7f8c8d,stroke:#34495e,color:#ffffff
style DCGW fill:#16a085,stroke:#138d75,color:#ffffff
graph TB
subgraph "โธ๏ธ Kubernetes Namespace: network-sec"
KSPG[๐พ PostgreSQL<br/>StatefulSet]
KSR[๐ Redis<br/>๐ StatefulSet]
KSK[๐จ Kafka<br/>StatefulSet]
KSH[๐ Heal Service<br/>Deployment]
KSW[๐ก๏ธ Warrior Service<br/>Deployment]
KSC[๐ฐ Coin Service<br/>Deployment]
KSD[๐ Dragon Service<br/>Deployment]
KSE[๐น Enemy Service<br/>Deployment]
KSGW[๐ Gateway<br/>Deployment]
KSSH[๐ Heal Service<br/>Service :50058]
KSING[๐ Ingress]
end
KSH -->|Read/Write| KSPG
KSH -->|๐ Cache| KSR
KSH -->|Consume Events| KSK
KSH -->|gRPC| KSW
KSH -->|gRPC| KSC
KSH -->|gRPC| KSD
KSH -->|gRPC| KSE
KSSH -.->|Exposes| KSH
KSGW -->|gRPC Proxy| KSSH
KSING -->|Routes| KSGW
style KSH fill:#2ecc71,stroke:#27ae60,color:#ffffff
style KSPG fill:#3498db,stroke:#2980b9,color:#ffffff
style KSR fill:#e74c3c,stroke:#c0392b,color:#ffffff
style KSK fill:#9b59b6,stroke:#8e44ad,color:#ffffff
style KSW fill:#3498db,stroke:#2980b9,color:#ffffff
style KSC fill:#f39c12,stroke:#e67e22,color:#ffffff
style KSD fill:#8b0000,stroke:#5a0000,color:#ffffff
style KSE fill:#7f8c8d,stroke:#34495e,color:#ffffff
style KSGW fill:#16a085,stroke:#138d75,color:#ffffff
style KSSH fill:#2ecc71,stroke:#27ae60,color:#ffffff
style KSING fill:#16a085,stroke:#138d75,color:#ffffff
sequenceDiagram
participant Client
participant Heal as ๐ Heal Service
participant Redis as ๐ Redis Streams
participant Warrior as ๐ก๏ธ Warrior Service
Note over Client,Warrior: โ๏ธ Healing Purchase and Logging
Client->>Heal: PurchaseHeal (gRPC)
Heal->>Heal: Validate & Process Payment
Heal->>Redis: ๐ LogHealingStarted (status: "started")
Note right of Redis: ๐ Stream: healing:logs:{participant_id}<br/>๐
Timeline: healing:logs:{participant_id}:timeline
Heal->>Heal: Schedule HP Update (background goroutine)
Heal->>Warrior: UpdateWarriorHealingState (is_healing=true)
Heal-->>Client: โ
Healing started (duration)
Note over Heal,Redis: ๐ Progress Logging (Every 5 seconds)
loop Every 5 seconds
Heal->>Heal: Calculate progress percentage
Heal->>Redis: ๐ LogHealingProgress (status: "in_progress")
Note right of Redis: ๐ Progress: 0% โ 100%<br/>โฑ๏ธ Remaining seconds tracked
end
Note over Heal,Warrior: ๐ Healing Completion
Heal->>Heal: โฑ๏ธ Duration elapsed
Heal->>Warrior: UpdateWarriorHP (gRPC)
Heal->>Warrior: UpdateWarriorHealingState (is_healing=false)
Heal->>Redis: โ
LogHealingCompleted (status: "completed")
Note right of Redis: ๐ Final log entry with HP update
Note over Client,Redis: ๐ Query Healing Logs
Client->>Heal: GetHealingLogs (participant_id)
Heal->>Redis: XRevRangeN (get latest entries)
Redis-->>Heal: ๐ Healing log entries
Heal-->>Client: ๐ Healing history with progress
graph TB
subgraph "๐ HealService Container"
APP[๐ Heal Service<br/>Go Application]
GRPC[๐ก gRPC Server<br/>:50058]
DB[๐พ PostgreSQL Client<br/>GORM]
REDIS[๐ Redis Client]
KAFKA[๐จ Kafka Consumer]
GRPCW[๐ก๏ธ Warrior gRPC<br/>Client]
GRPCC[๐ฐ Coin gRPC<br/>Client]
GRPCD[๐ Dragon gRPC<br/>Client]
GRPCE[๐น Enemy gRPC<br/>Client]
end
APP --> GRPC
APP --> DB
APP --> REDIS
APP --> KAFKA
APP --> GRPCW
APP --> GRPCC
APP --> GRPCD
APP --> GRPCE
GRPC -->|Listen| EXTERNAL[External Clients]
DB -->|Connect| PG[(๐พ PostgreSQL)]
REDIS -->|Connect| RD[(๐ Redis)]
KAFKA -->|Consume| KF[(๐จ Kafka)]
GRPCW -->|Call| W[๐ก๏ธ Warrior Service]
GRPCC -->|Call| C[๐ฐ Coin Service]
GRPCD -->|Call| D[๐ Dragon Service]
GRPCE -->|Call| E[๐น Enemy Service]
style APP fill:#2ecc71,stroke:#27ae60,color:#ffffff
style GRPC fill:#1abc9c,stroke:#16a085,color:#ffffff
style DB fill:#3498db,stroke:#2980b9,color:#ffffff
style REDIS fill:#e74c3c,stroke:#c0392b,color:#ffffff
style KAFKA fill:#9b59b6,stroke:#8e44ad,color:#ffffff
style GRPCW fill:#3498db,stroke:#2980b9,color:#ffffff
style GRPCC fill:#f39c12,stroke:#e67e22,color:#ffffff
style GRPCD fill:#8b0000,stroke:#5a0000,color:#ffffff
style GRPCE fill:#7f8c8d,stroke:#34495e,color:#ffffff
sequenceDiagram
participant Client
participant Heal as ๐ Heal Service
participant Dragon as ๐ Dragon Service (gRPC)
participant Warrior as ๐ก๏ธ Warrior Service (gRPC)
participant Coin as ๐ฐ Coin Service (gRPC)
participant Redis as ๐ Redis Streams
Note over Client,Redis: ๐ Dragon Healing Purchase
Client->>Heal: PurchaseHeal(dragon_id, "dragon", "dragon")
Heal->>Dragon: GetDragonByID (gRPC)
Dragon-->>Heal: Dragon info (HP, is_alive, created_by)
alt Dragon is not alive
Heal-->>Client: โ ๏ธ Error: Dragon is not alive
else Dragon is alive and healing
Heal-->>Client: โ ๏ธ Error: Dragon is already healing
end
Heal->>Heal: GetHealPackageByType ("dragon", "dragon")
Heal->>Heal: Validate role (RBAC: dragon role only)
Note over Heal,Coin: ๐ณ Payment by Dark Emperor
Heal->>Dragon: GetDragonByID (get created_by username)
Dragon-->>Heal: Dark Emperor username
Heal->>Warrior: GetWarriorByUsername (gRPC, dark_emperor)
Warrior-->>Heal: Dark Emperor warrior ID
Heal->>Coin: ๐ฐ DeductCoins (gRPC, 1000 coins from Dark Emperor)
Coin-->>Heal: โ
Payment confirmed (Dark Emperor paid)
Heal->>Dragon: UpdateDragonHealingState (is_healing=true, healing_until)
Heal->>Redis: ๐ LogHealingStarted (status: "started")
Heal-->>Client: โ
Healing started (1 hour duration, paid by Dark Emperor)
Note over Heal,Redis: โฑ๏ธ Healing Progress (1 hour)
loop Every 5 seconds for 1 hour
Heal->>Heal: Calculate progress percentage
Heal->>Redis: ๐ LogHealingProgress (status: "in_progress")
end
Note over Heal,Dragon: ๐ Healing Completion
Heal->>Heal: โฑ๏ธ 1 hour elapsed
Heal->>Dragon: UpdateDragonHP (gRPC, max HP)
Heal->>Dragon: UpdateDragonHealingState (is_healing=false)
Heal->>Redis: โ
LogHealingCompleted (status: "completed")
Heal-->>Client: โ
Dragon fully healed!
sequenceDiagram
participant Client
participant Heal as ๐ Heal Service
participant Enemy as ๐น Enemy Service (gRPC)
participant Redis as ๐ Redis Streams
Note over Client,Redis: ๐น Enemy Healing Purchase
Client->>Heal: PurchaseHeal(enemy_id, "enemy", "full", "warrior")
Heal->>Enemy: GetEnemyByID (gRPC)
Enemy-->>Heal: Enemy info (HP, max_health, coin_balance, is_healing)
alt Enemy is healing
Heal-->>Client: โ ๏ธ Error: Enemy is already healing
end
Heal->>Heal: GetHealPackageByType ("full", "warrior")
Heal->>Heal: Validate role (RBAC: all roles can use warrior packages)
Note over Heal,Enemy: ๐ฐ Payment from Enemy's Balance
Heal->>Enemy: DeductEnemyCoins (gRPC, package price from enemy balance)
alt Insufficient balance
Enemy-->>Heal: โ ๏ธ Error: Insufficient balance
Heal-->>Client: โ ๏ธ Error: Enemy doesn't have enough coins
else Payment successful
Enemy-->>Heal: โ
Payment confirmed (coins deducted from enemy)
Heal->>Enemy: UpdateEnemyHealingState (is_healing=true, healing_until)
Heal->>Redis: ๐ LogHealingStarted (status: "started")
Heal-->>Client: โ
Healing started (duration, coins_spent)
Note over Heal,Redis: โฑ๏ธ Healing Progress
loop Every 5 seconds
Heal->>Heal: Calculate progress percentage
Heal->>Redis: ๐ LogHealingProgress (status: "in_progress")
end
Note over Heal,Enemy: ๐ Healing Completion
Heal->>Heal: โฑ๏ธ Duration elapsed
Heal->>Enemy: UpdateEnemyHP (gRPC, new HP)
Heal->>Enemy: UpdateEnemyHealingState (is_healing=false)
Heal->>Redis: โ
LogHealingCompleted (status: "completed")
Heal-->>Client: โ
Enemy fully healed!
end
graph TB
subgraph "๐ก๏ธ Warrior Healing"
W1[Warrior<br/>PurchaseHeal]
W2[๐ฐ Coin Service<br/>Deduct from Warrior]
W3[โ
Payment Complete]
W1 --> W2 --> W3
end
subgraph "๐น Enemy Healing"
E1[Enemy<br/>PurchaseHeal]
E2[๐ฐ Enemy Service<br/>Deduct from Enemy Balance]
E3[โ
Payment Complete]
E1 --> E2 --> E3
end
subgraph "๐ Dragon Healing"
D1[Dragon<br/>PurchaseHeal]
D2[๐ Get Dragon Info<br/>Find Dark Emperor]
D3[๐ก๏ธ Warrior Service<br/>Get Dark Emperor ID]
D4[๐ฐ Coin Service<br/>Deduct from Dark Emperor]
D5[โ
Payment Complete<br/>Dark Emperor Paid]
D1 --> D2 --> D3 --> D4 --> D5
end
style W1 fill:#3498db,stroke:#2980b9,color:#ffffff
style W2 fill:#f39c12,stroke:#e67e22,color:#ffffff
style W3 fill:#2ecc71,stroke:#27ae60,color:#ffffff
style E1 fill:#7f8c8d,stroke:#34495e,color:#ffffff
style E2 fill:#f39c12,stroke:#e67e22,color:#ffffff
style E3 fill:#2ecc71,stroke:#27ae60,color:#ffffff
style D1 fill:#8b0000,stroke:#5a0000,color:#ffffff
style D2 fill:#3498db,stroke:#2980b9,color:#ffffff
style D3 fill:#3498db,stroke:#2980b9,color:#ffffff
style D4 fill:#f39c12,stroke:#e67e22,color:#ffffff
style D5 fill:#2ecc71,stroke:#27ae60,color:#ffffff
- Repairs damaged weapons by restoring durability to max after payment.
- Stores repair orders in PostgreSQL (GORM).
- Publishes
weapon.repairevents to Kafka. Coin service consumes and deducts balance. - gRPC endpoints exposed via gateway (
/repair.RepairService).
%%{init: {
"theme": "base",
"themeVariables": {
"primaryColor": "#2b2b2b",
"primaryTextColor": "#e0e0e0",
"primaryBorderColor": "#5a5a5a",
"lineColor": "#5a5a5a",
"tertiaryColor": "#3a3a3a",
"clusterBkg": "#2b2b2b",
"clusterBorder": "#5a5a5a"
}
}}%%
sequenceDiagram
participant Client
participant GW as API Gateway
participant Repair as Repair Service (gRPC)
participant Weapon as Weapon Service (gRPC)
participant Kafka as Kafka
participant Coin as Coin Service (gRPC)
Client->>GW: RepairWeapon(owner_type, owner_id, weapon_id)
GW->>Repair: gRPC RepairWeapon
Repair->>Weapon: GetWeapon(weapon_id)
Weapon-->>Repair: durability, max_durability
Repair->>Repair: compute cost = (max - cur) * 2
alt cost == 0
Repair-->>GW: accepted=false, status=completed
else cost > 0
Repair->>Repair: create order (Postgres)
Repair->>Kafka: publish weapon.repair {owner, weapon, cost, order}
Kafka->>Coin: consume weapon.repair
Coin->>Coin: DeductCoins(owner)
Coin-->>Kafka: ack
Repair->>Weapon: (async) set durability to max (impl option)
Repair-->>GW: accepted=true, status=pending/completed
end
%%{init: {
"theme": "base",
"themeVariables": {
"primaryColor": "#36454F",
"primaryTextColor": "#E0E0E0",
"primaryBorderColor": "#212121",
"lineColor": "#424242",
"tertiaryColor": "#616161",
"clusterBkg": "#424242",
"clusterBorder": "#212121"
}
}}%%
graph TB
subgraph "Monitoring Stack"
PRO[Prometheus<br/>:9090<br/>Metrics Collection]
GRA[Grafana<br/>:3000<br/>Visualization]
ALM[Alertmanager<br/>:9093<br/>Alert Routing]
end
subgraph "Microservices"
W[Warrior<br/>/metrics :8080]
WP[Weapon<br/>/metrics :8081]
C[Coin<br/>/metrics :8091]
E[Enemy<br/>/metrics :8092]
D[Dragon<br/>/metrics :8084]
B[Battle<br/>/metrics :8085]
BS[Battlespell<br/>/metrics :8086]
A[Arena<br/>/metrics :8087]
AS[Arenaspell<br/>/metrics :8088]
R[Repair<br/>/metrics :8082]
H[Heal<br/>/metrics :8089]
AR[Armor<br/>/metrics :8082]
end
W -->|Scrape| PRO
WP -->|Scrape| PRO
C -->|Scrape| PRO
E -->|Scrape| PRO
D -->|Scrape| PRO
B -->|Scrape| PRO
BS -->|Scrape| PRO
A -->|Scrape| PRO
AS -->|Scrape| PRO
R -->|Scrape| PRO
H -->|Scrape| PRO
AR -->|Scrape| PRO
PRO -->|Query| GRA
PRO -->|Alerts| ALM
ALM -->|Notify| NOTIFY[Email/Webhook<br/>Notifications]
style PRO fill:#36454F,stroke:#212121,stroke-width:3px,color:#E0E0E0
style GRA fill:#36454F,stroke:#212121,stroke-width:3px,color:#E0E0E0
style ALM fill:#36454F,stroke:#212121,stroke-width:3px,color:#E0E0E0
style W fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style WP fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style C fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style E fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style D fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style B fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style BS fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style A fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style AS fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style R fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style H fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style AR fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
%%{init: {
"theme": "base",
"themeVariables": {
"primaryColor": "#36454F",
"primaryTextColor": "#E0E0E0",
"primaryBorderColor": "#212121",
"lineColor": "#424242",
"tertiaryColor": "#616161",
"clusterBkg": "#424242",
"clusterBorder": "#212121"
}
}}%%
sequenceDiagram
participant Client
participant Service as Microservice
participant Metrics as Metrics Exporter
participant Prom as Prometheus
participant Grafana as Grafana
Client->>Service: HTTP/gRPC Request
Service->>Metrics: Record HTTP Request<br/>(method, endpoint, status)
Service->>Metrics: Record Duration<br/>(histogram)
Service->>Service: Process Request
Service-->>Client: Response
Note over Service,Metrics: Metrics Continuously Exposed
Metrics->>Prom: GET /metrics<br/>(scrape interval: 15s)
Prom->>Prom: Store in TSDB
Note over Prom,Grafana: Visualization
Grafana->>Prom: PromQL Query
Prom-->>Grafana: Metrics Data
Grafana-->>Grafana: Render Dashboard
%%{init: {
"theme": "base",
"themeVariables": {
"primaryColor": "#36454F",
"primaryTextColor": "#E0E0E0",
"primaryBorderColor": "#212121",
"lineColor": "#424242",
"tertiaryColor": "#616161",
"clusterBkg": "#424242",
"clusterBorder": "#212121"
}
}}%%
graph TB
subgraph "Health Check Endpoints"
HEALTH["/health<br/>Full Health Check<br/>with Components"]
READY["/ready<br/>Readiness Probe<br/>K8s Ready"]
LIVE["/live<br/>Liveness Probe<br/>K8s Alive"]
end
subgraph "Health Checkers"
DB["Database Checker<br/>PostgreSQL/MySQL/MongoDB"]
SIMPLE["Simple Checker<br/>Always Healthy"]
end
subgraph "Components"
PG[(PostgreSQL)]
MY[(MySQL)]
MG[(MongoDB)]
end
HEALTH -->|Checks| DB
HEALTH -->|Checks| SIMPLE
READY -->|Quick Check| SIMPLE
LIVE -->|Quick Check| SIMPLE
DB -->|Ping| PG
DB -->|Ping| MY
DB -->|Ping| MG
style HEALTH fill:#36454F,stroke:#212121,stroke-width:3px,color:#E0E0E0
style READY fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style LIVE fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style DB fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style SIMPLE fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
%%{init: {
"theme": "base",
"themeVariables": {
"primaryColor": "#36454F",
"primaryTextColor": "#E0E0E0",
"primaryBorderColor": "#212121",
"lineColor": "#424242",
"tertiaryColor": "#616161",
"clusterBkg": "#424242",
"clusterBorder": "#212121"
}
}}%%
sequenceDiagram
participant Prom as Prometheus
participant Rules as Alert Rules
participant AM as Alertmanager
participant CriticalReceiver as Critical Receiver
participant WarningReceiver as Warning Receiver
participant Notify as Notification Channels
Prom->>Rules: Evaluate Rules (every 15s)
Rules->>Rules: Check Conditions<br/>(ServiceDown, HighErrorRate, etc.)
alt Alert Fired
Rules->>AM: Send Alert
AM->>AM: Group & Route
alt Critical Alert
AM->>CriticalReceiver: Route to Critical
CriticalReceiver->>Notify: Email/Webhook
else Warning Alert
AM->>WarningReceiver: Route to Warning
WarningReceiver->>Notify: Webhook
end
Notify->>Notify: Send Notification
end
%%{init: {
"theme": "base",
"themeVariables": {
"primaryColor": "#36454F",
"primaryTextColor": "#E0E0E0",
"primaryBorderColor": "#212121",
"lineColor": "#424242",
"tertiaryColor": "#616161",
"clusterBkg": "#424242",
"clusterBorder": "#212121"
}
}}%%
graph TB
subgraph "HTTP Metrics"
H1[http_requests_total<br/>Counter<br/>method, endpoint, status]
H2[http_request_duration_seconds<br/>Histogram<br/>method, endpoint, status]
end
subgraph "gRPC Metrics"
G1[grpc_requests_total<br/>Counter<br/>method, status]
G2[grpc_request_duration_seconds<br/>Histogram<br/>method, status]
end
subgraph "Database Metrics"
D1[database_connections<br/>Gauge<br/>database, status]
D2[database_query_duration_seconds<br/>Histogram<br/>database, query_type]
D3[database_connection_status<br/>Gauge<br/>database]
end
subgraph "Kafka Metrics"
K1[kafka_messages_produced_total<br/>Counter<br/>topic]
K2[kafka_messages_consumed_total<br/>Counter<br/>topic]
K3[kafka_processing_duration_seconds<br/>Histogram<br/>topic]
end
subgraph "Business Metrics"
B1[business_operations_total<br/>Counter<br/>operation, status]
B2[business_operation_duration_seconds<br/>Histogram<br/>operation]
end
style H1 fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style H2 fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style G1 fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style G2 fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style D1 fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style D2 fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style D3 fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style K1 fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style K2 fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style K3 fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style B1 fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style B2 fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
%%{init: {
"theme": "base",
"themeVariables": {
"primaryColor": "#36454F",
"primaryTextColor": "#E0E0E0",
"primaryBorderColor": "#212121",
"lineColor": "#424242",
"tertiaryColor": "#616161",
"clusterBkg": "#424242",
"clusterBorder": "#212121"
}
}}%%
graph TB
subgraph "Unit Tests"
U1[Service Logic Tests]
U2[Repository Tests]
U3[Business Logic Tests]
end
subgraph "Integration Tests"
I1[Database Integration]
I2[gRPC Client Integration]
I3[Kafka Integration]
I4[Service-to-Service]
end
subgraph "E2E Tests"
E1[Complete Workflows]
E2[Battle Flow]
E3[Arena Flow]
E4[Weapon/Armor Purchase & Repair]
end
subgraph "Performance Tests"
P1[Load Tests]
P2[Concurrency Tests]
P3[Race Condition Tests]
end
U1 --> I1
U2 --> I2
U3 --> I3
I1 --> E1
I2 --> E2
I3 --> E3
I4 --> E4
E1 --> P1
E2 --> P2
E3 --> P3
style U1 fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style U2 fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style U3 fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style I1 fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style I2 fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style I3 fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style I4 fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style E1 fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style E2 fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style E3 fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style E4 fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style P1 fill:#36454F,stroke:#212121,stroke-width:3px,color:#E0E0E0
style P2 fill:#36454F,stroke:#212121,stroke-width:3px,color:#E0E0E0
style P3 fill:#36454F,stroke:#212121,stroke-width:3px,color:#E0E0E0
%%{init: {
"theme": "base",
"themeVariables": {
"primaryColor": "#36454F",
"primaryTextColor": "#E0E0E0",
"primaryBorderColor": "#212121",
"lineColor": "#424242",
"tertiaryColor": "#616161",
"clusterBkg": "#424242",
"clusterBorder": "#212121"
}
}}%%
sequenceDiagram
participant Dev as Developer
participant TestRunner as Test Runner
participant UnitTests as Unit Tests
participant IntTests as Integration Tests
participant E2ETests as E2E Tests
participant TestDB as In-Memory DB
participant MockServices as Mock Services
Dev->>TestRunner: go test ./tests/...
Note over TestRunner,UnitTests: Unit Tests Phase
TestRunner->>UnitTests: Execute Unit Tests
UnitTests->>TestDB: Setup In-Memory SQLite/MongoDB
UnitTests->>UnitTests: Test Service Logic
UnitTests->>UnitTests: Test Repository
UnitTests-->>TestRunner: Unit Test Results
Note over TestRunner,IntTests: Integration Tests Phase
TestRunner->>IntTests: Execute Integration Tests
IntTests->>TestDB: Setup Test Databases
IntTests->>MockServices: Setup Mock gRPC Clients
IntTests->>IntTests: Test Service Integration
IntTests-->>TestRunner: Integration Test Results
Note over TestRunner,E2ETests: E2E Tests Phase
TestRunner->>E2ETests: Execute E2E Tests
E2ETests->>TestDB: Setup Full Test Environment
E2ETests->>E2ETests: Test Complete Workflows
E2ETests-->>TestRunner: E2E Test Results
TestRunner-->>Dev: Final Test Report
%%{init: {
"theme": "base",
"themeVariables": {
"primaryColor": "#36454F",
"primaryTextColor": "#E0E0E0",
"primaryBorderColor": "#212121",
"lineColor": "#424242",
"tertiaryColor": "#616161",
"clusterBkg": "#424242",
"clusterBorder": "#212121"
}
}}%%
graph TB
subgraph "Tested Services"
W["Warrior<br/>โ
Unit Tests"]
WP["Weapon<br/>โ
Unit Tests"]
C["Coin<br/>โ
Unit Tests"]
E["Enemy<br/>โ
Unit Tests"]
D["Dragon<br/>โ
Unit Tests"]
R["Repair<br/>โ
Unit Tests"]
H["Heal<br/>โ
Unit Tests"]
AR["Armor<br/>โ
Unit Tests"]
end
subgraph "Integration Tests"
I1["Weapon Battle<br/>Repair Flow"]
I2["Arena Flow"]
I3["Battle Flow"]
end
subgraph "Test Types"
T1["Unit Tests<br/>In-Memory DB"]
T2["Integration Tests<br/>Service Integration"]
T3["E2E Tests<br/>Complete Workflows"]
T4["Performance Tests<br/>Load & Concurrency"]
T5["Edge Cases<br/>Boundary Conditions"]
T6["Error Handling<br/>Invalid Inputs"]
end
W --> T1
WP --> T1
C --> T1
E --> T1
D --> T1
R --> T1
H --> T1
AR --> T1
WP --> I1
I1 --> T2
I2 --> T2
I3 --> T2
T2 --> T3
T3 --> T4
T4 --> T5
T5 --> T6
style W fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style WP fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style C fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style E fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style D fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style R fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style H fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style AR fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style I1 fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style I2 fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style I3 fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style T1 fill:#36454F,stroke:#212121,stroke-width:3px,color:#E0E0E0
style T2 fill:#36454F,stroke:#212121,stroke-width:3px,color:#E0E0E0
style T3 fill:#36454F,stroke:#212121,stroke-width:3px,color:#E0E0E0
style T4 fill:#36454F,stroke:#212121,stroke-width:3px,color:#E0E0E0
style T5 fill:#36454F,stroke:#212121,stroke-width:3px,color:#E0E0E0
style T6 fill:#36454F,stroke:#212121,stroke-width:3px,color:#E0E0E0
%%{init: {
"theme": "base",
"themeVariables": {
"primaryColor": "#36454F",
"primaryTextColor": "#E0E0E0",
"primaryBorderColor": "#212121",
"lineColor": "#424242",
"tertiaryColor": "#616161",
"clusterBkg": "#424242",
"clusterBorder": "#212121"
}
}}%%
graph TB
subgraph "Development"
TEST["Test Execution"]
COV["Code Coverage"]
end
subgraph "Monitoring"
METRICS["Metrics Collection"]
HEALTH["Health Checks"]
ALERTS["Alerting"]
end
subgraph "Quality Gates"
Q1["Unit Test Coverage >80%"]
Q2["Integration Tests Pass"]
Q3["E2E Tests Pass"]
Q4["No Critical Alerts"]
Q5["Health Checks Green"]
end
TEST --> COV
COV --> Q1
TEST --> Q2
TEST --> Q3
METRICS --> ALERTS
HEALTH --> ALERTS
ALERTS --> Q4
HEALTH --> Q5
Q1 --> DEPLOY["Deploy to Production"]
Q2 --> DEPLOY
Q3 --> DEPLOY
Q4 --> DEPLOY
Q5 --> DEPLOY
style TEST fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style COV fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style METRICS fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style HEALTH fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style ALERTS fill:#616161,stroke:#212121,stroke-width:2px,color:#E0E0E0
style Q1 fill:#36454F,stroke:#212121,stroke-width:3px,color:#E0E0E0
style Q2 fill:#36454F,stroke:#212121,stroke-width:3px,color:#E0E0E0
style Q3 fill:#36454F,stroke:#212121,stroke-width:3px,color:#E0E0E0
style Q4 fill:#36454F,stroke:#212121,stroke-width:3px,color:#E0E0E0
style Q5 fill:#36454F,stroke:#212121,stroke-width:3px,color:#E0E0E0
style DEPLOY fill:#36454F,stroke:#212121,stroke-width:3px,color:#E0E0E0