diff --git a/INFRA.md b/INFRA.md index 986efb1b..ff22d7a7 100644 --- a/INFRA.md +++ b/INFRA.md @@ -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