chore: add INFRA doc

This commit is contained in:
2026-05-02 19:15:07 +02:00
parent cfe1d49da9
commit 56d651f01c
+108 -131
View File
@@ -69,9 +69,9 @@ graph TB
ADM -->|HTTPS| WAF
%% ─── Routage WAF ────────────────────────────────────────────
WAF -->|"/api/*"| BACK
WAF -->|"/* SPA"| FRONT
WAF -->|"/uploads/*"| BACK
WAF -->|"/api/*"| BACK
WAF -->|"/* SPA"| FRONT
WAF -->|"/uploads/*"| BACK
%% ─── Backend ↔ données ──────────────────────────────────────
BACK --> PG
@@ -125,30 +125,24 @@ graph TB
| `gestion-postgres` | `postgres:16-alpine` | 5432 (interne) | Base de données principale |
| `gestion-redis` | `redis:7-alpine` | 6379 (interne) | Cache · Sessions · File livreurs |
### Réseau Docker
Tous les conteneurs partagent le bridge `gestion-network` (`gestion-br0`). Seul le WAF expose des ports publics.
### Flux de trafic
```
Internet
▼ :443 (TLS 1.2/1.3)
┌─────────────────────────────────────┐
│ WAF nginx + ModSecurity CRS L2 │
│ • Rate limit : 20 req/s/IP │
│ • HSTS 2 ans │
│ • CSP / X-Frame / Permissions │
│ • Ban auto sur SQLi / XSS / LFI │
└──────┬──────────────┬───────────────┘
│ /api/* │ /*
▼ ▼
Backend Frontend
Go/Gin nginx SPA
├──► PostgreSQL (persistance)
└──► Redis (cache / queues)
```mermaid
flowchart TD
INET["🌐 Internet"] -->|":443 TLS 1.2/1.3"| WAF
subgraph WAF["🛡️ WAF — nginx + ModSecurity CRS L2"]
W1["Rate limit : 20 req/s/IP"]
W2["HSTS 2 ans · CSP · X-Frame"]
W3["Ban auto : SQLi / XSS / LFI / RCE"]
end
WAF -->|"/api/*"| BACK["⚙️ Backend\nGo / Gin :8080"]
WAF -->|"/* SPA"| FRONT["🖥️ Frontend\nnginx :80"]
WAF -->|"/uploads/*\n(fichiers statiques)"| BACK
BACK --> PG["🗄️ PostgreSQL 16"]
BACK --> REDIS["⚡ Redis 7\nSessions · Queue · Cache"]
```
### Volumes persistants
@@ -157,31 +151,40 @@ Internet
|---|---|
| `postgres_data` | Données PostgreSQL |
| `redis_data` | Persistance Redis (AOF) |
| `backend_uploads` | Fichiers uploadés (images, vidéos) — monté en `:ro` dans le WAF pour `/uploads/` |
| `backend_uploads` | Fichiers uploadés — monté en `:ro` dans le WAF pour `/uploads/` |
### Variables d'environnement requises
```env
# Base de données
DB_PASSWORD=
DB_NAME=gestion_db
| Variable | Valeur par défaut | Description |
|---|---|---|
| `DB_PASSWORD` | — | Mot de passe PostgreSQL |
| `DB_NAME` | `gestion_db` | Nom de la base |
| `SESSION_SECRET` | — | Secret session Gin |
| `USER_JWT_SECRET` | — | JWT clients |
| `USER_JWT_SECRET_OLD` | — | JWT clients (rotation) |
| `ADMIN_JWT_SECRET` | — | JWT admin/cabine |
| `ADMIN_JWT_SECRET_OLD` | — | JWT admin (rotation) |
| `REDIS_PASSWORD` | — | Mot de passe Redis |
| `TOMTOM_API_KEY` | — | Clé TomTom Maps |
| `TELEGRAM_WEBHOOK_URL` | — | URL webhook Telegram |
| `TELEGRAM_WEBHOOK_SECRET` | — | Secret webhook Telegram |
| `NOWPAYMENTS_IPN_SECRET` | — | Secret IPN NowPayments |
# JWT
SESSION_SECRET=
USER_JWT_SECRET=
USER_JWT_SECRET_OLD=
ADMIN_JWT_SECRET=
ADMIN_JWT_SECRET_OLD=
---
# Redis
REDIS_PASSWORD=
## VPS Pre-prod
# Services externes
TOMTOM_API_KEY=
TELEGRAM_WEBHOOK_URL=
TELEGRAM_WEBHOOK_SECRET=
NOWPAYMENTS_IPN_SECRET=
```
Même stack que la production, déployé depuis la branche `pre-prod` via `SERVER_HOST` / `SERVER_SSH_KEY`.
### Services
| Conteneur | Image | Ports | Rôle |
|---|---|---|---|
| `gestion-waf` | `xor1234/backend-mln:waf` | **80, 443** (public) | WAF ModSecurity |
| `gestion-backend` | `xor1234/backend-mln:latest` | 8080 (interne) | API Go/Gin |
| `gestion-frontend` | `xor1234/frontend-mln:latest` | 80 (interne) | SPA React/Vite |
| `gestion-postgres` | `postgres:16-alpine` | 5432 (interne) | Base de données |
| `gestion-redis` | `redis:7-alpine` | 6379 (interne) | Cache · Sessions |
---
@@ -208,116 +211,90 @@ NOWPAYMENTS_IPN_SECRET=
### Dozzle — agents distants
Dozzle agrège les logs de plusieurs serveurs via des agents distants :
| Adresse | Usage |
|---|---|
| `5.181.0.112:7007` | Agent VPS 1 |
| `185.234.9.102:7007` | Agent VPS 2 |
```mermaid
graph LR
DOZZLE["📋 Dozzle\nuber-stup.club"] -->|":7007"| A1["VPS Production\n5.181.0.112"]
DOZZLE -->|":7007"| A2["VPS Pre-prod\n185.234.9.102"]
```
---
## CI/CD
### Pipelines
### Pipeline backend (pre-prod & main)
#### `backend-build.yml` — branche `main`
```mermaid
flowchart TD
PUSH["push backend/**"] --> LINT["lint\ngolangci-lint"]
LINT --> BUILD["build\ngo build ./..."]
BUILD --> ARTIFACT["artifact\nbackend-binary 7j"]
BUILD --> DOCKER{"push only?"}
DOCKER -->|oui| D1["docker build runtime\n→ xor1234/backend-mln:latest"]
DOCKER -->|oui| D2["docker build waf\n→ xor1234/backend-mln:waf"]
D1 --> DEPLOY["SSH deploy\ndocker compose pull backend waf\ndocker compose up -d --no-deps backend waf"]
D2 --> DEPLOY
```
push main/backend/**
lint (golangci-lint)
build (go build ./...)
└─ artifact: backend-binary (7j)
│ [push only]
docker
├─ build --target runtime → xor1234/backend-mln:latest
└─ build --target waf → xor1234/backend-mln:waf
│ [push only]
deploy (SSH)
├─ docker compose pull backend waf
└─ docker compose up -d --no-deps backend waf
style DOCKER fill:#f0f0f0
```
#### `frontend-web-build.yml` — branche `main`
### Pipeline frontend web (pre-prod & main)
```
push main/frontend-prep/** ou docker/frontend/**
lint-typecheck (tsc + eslint)
build (npm run build)
└─ artifact: frontend-web-dist (7j)
│ [push only]
docker
└─ build → xor1234/frontend-mln:latest
│ [push only]
deploy (SSH)
├─ docker compose pull frontend
└─ docker compose up -d --no-deps frontend
```mermaid
flowchart TD
PUSH["push frontend-prep/**\nou docker/frontend/**"] --> LINT["lint-typecheck\ntsc + eslint"]
LINT --> BUILD["build\nnpm run build"]
BUILD --> ARTIFACT["artifact\nfrontend-web-dist 7j"]
BUILD --> DOCKER{"push only?"}
DOCKER -->|oui| D1["docker build\n→ xor1234/frontend-mln:latest"]
D1 --> DEPLOY["SSH deploy\ndocker compose pull frontend\ndocker compose up -d --no-deps frontend"]
style DOCKER fill:#f0f0f0
```
#### `frontend-admin-build.yml` / `frontend-client-build.yml` — branche `main`
### Pipeline mobile (main uniquement)
```
push main/frontend-admin/** (ou mobile/**)
typecheck (tsc --noEmit)
│ [push only]
build-apk-prod (EAS)
├─ eas build --platform android --profile production
└─ artifact: admin-panel-android-prod-apk (14j)
```mermaid
flowchart TD
PUSH_A["push frontend-admin/**"] --> TC_A["typecheck\ntsc --noEmit"]
TC_A --> EAS_A["EAS build android\n--profile production"]
EAS_A --> APK_A["artifact\nadmin-panel-android-prod-apk 14j"]
PUSH_C["push mobile/**"] --> TC_C["typecheck\ntsc --noEmit"]
TC_C --> EAS_C["EAS build android\n--profile production"]
EAS_C --> APK_C["artifact\nclient-android-prod-apk 14j"]
```
### Secrets GitHub requis
| Secret | Usage |
|---|---|
| `DOCKERHUB_USERNAME` | Login Docker Hub |
| `DOCKERHUB_TOKEN` | Token Docker Hub |
| `SERVER_HOST` / `SERVER_HOST_PROD` | IP/hostname VPS |
| `SERVER_USER` | Utilisateur SSH |
| `SERVER_SSH_KEY` / `SERVER_SSH_KEY_PROD` | Clé privée SSH ED25519 |
| `COMPOSE_PATH` | Chemin absolu du docker-compose-prod.yml |
| `EXPO_TOKEN` | Token Expo EAS |
| `EXPO_PROJECT_ID` / `EXPO_PROJECT_ID_CLIENT` | IDs projets EAS |
| `VITE_TOMTOM_API_KEY` | Clé TomTom pour le build frontend |
| Secret | Branche | Usage |
|---|---|---|
| `DOCKERHUB_USERNAME` | main + pre-prod | Login Docker Hub |
| `DOCKERHUB_TOKEN` | main + pre-prod | Token Docker Hub |
| `SERVER_HOST` | pre-prod | IP/hostname VPS pre-prod |
| `SERVER_HOST_PROD` | main | IP/hostname VPS production |
| `SERVER_USER` | main + pre-prod | Utilisateur SSH |
| `SERVER_SSH_KEY` | pre-prod | Clé privée SSH ED25519 pre-prod |
| `SERVER_SSH_KEY_PROD` | main | Clé privée SSH ED25519 prod |
| `COMPOSE_PATH` | main + pre-prod | Chemin absolu docker-compose-prod.yml |
| `EXPO_TOKEN` | main | Token Expo EAS |
| `EXPO_PROJECT_ID` | main | ID projet EAS admin |
| `EXPO_PROJECT_ID_CLIENT` | main | ID projet EAS client |
| `VITE_TOMTOM_API_KEY` | main + pre-prod | Clé TomTom pour build frontend |
---
## Backend — architecture interne
```mermaid
graph TD
MAIN["main.go\ninit DB · Redis · services · Gin"] --> ROUTES["routes/routes.go\npublic · client · admin · cabine · livreur"]
ROUTES --> HANDLERS["handlers/\nauth · commands · delivery\npanier · notifications · payments"]
HANDLERS --> MODELS["models/\nstructs GORM"]
HANDLERS --> DB["db/\nconnexion · migrations · queries"]
HANDLERS --> SERVICES["services/\nTomTom · Telegram · NowPayments"]
MAIN --> WORKERS["workers/\ncron_auto_assign 5min\npayment_checker 2min\nqueue_cleanup 5min"]
MAIN --> MW["middleware/\nsession · block · clock"]
```
backend/gestion/
├── main.go ← init DB, Redis, services, workers, Gin router
├── routes/routes.go ← toutes les routes (public / client / admin / cabine / livreur)
├── handlers/ ← logique HTTP (auth, commands, delivery, payments…)
├── models/ ← structs Go (GORM)
├── db/ ← connexion, migrations, queries
├── services/ ← TomTom, Telegram, NowPayments
├── middleware/ ← session, block, clock
├── workers/ ← cron auto-assign (5 min), payment checker (2 min)
└── uploads/ ← fichiers statiques servis via /uploads/
```
### Workers background
| Worker | Intervalle | Rôle |
|---|---|---|
| `cron_auto_assign` | 5 min | Assigne automatiquement les commandes `pending` aux livreurs disponibles via la queue Redis |
| `payment_checker` | 2 min | Vérifie le statut des paiements crypto NowPayments en attente |
| Queue cleanup | 5 min | Nettoie les entrées expirées dans les queues Redis |
### Rôles utilisateurs