Skip to content

00 — VARIABLES GLOBALES, STACK & STRUCTURE IaC

Objectif

Ce document est le socle de référence du projet. L'agent doit le lire avant tout autre fichier. Il contient les variables globales, la stack technique retenue avec les justifications, l'inventaire complet des services, et la structure IaC que l'agent doit respecter.

Aucun script n'est à générer à partir de ce fichier. C'est un document de contexte et de décisions.


1. IDENTITÉ DU PROJET

CléValeur
Nom du projetNex
Domaine techniquepaywithnex
TypeFintech — services financiers numériques (mobile money)
Zone cibleCEMAC (Afrique centrale)
RégulateurBEAC / COBAC
Équipe technique3 développeurs + 1 CDP
ArchitectureMicroservices (11 services NestJS + 2 dashboards Nuxt + 2 apps mobiles React Native)

2. INVENTAIRE TECHNIQUE COMPLET

2.1 Applications Front-End

AppFrameworkModeUIPackage ManagerDéploiement
CMMS DashboardNuxt 4.2.2SPA (SSR désactivé)Nuxt UI 4.3 + TailwindpnpmFirebase Hosting
BackofficeNuxt 4.2.2SSR ou SPANuxt UI 4.3 + TailwindpnpmFirebase Hosting

Stack commune front : TypeScript 5.9.x, Pinia (state), Zod (validation).

2.2 Applications Mobiles

AppFrameworkDéploiement
App ClientReact NativeApp Store (iOS) + Google Play (Android)
App MarchandReact NativeApp Store (iOS) + Google Play (Android)

2.3 Microservices Back-End

Socle commun à tous les services :

ÉlémentDétail
FrameworkNestJS 11.0.1
LangageTypeScript
Base de donnéesPostgreSQL (pg 8.16.3) — sauf logs-reporting
ORMTypeORM 0.3.27
BuildSWC (@swc/cli, @swc/core)
TestsJest + Supertest
Documentation APISwagger / OpenAPI
LintingESLint + Prettier

Détail par service :

#ServicePortBase de donnéesRedisDépendances externesExposition
1auth3001PostgreSQLOui (sessions, cache)Auth0, JWT, bcryptPublique (via Ingress)
2ledger-wallets3002PostgreSQLNonAxios, seeders walletsInterne
3customer-profiles-kyc3003PostgreSQLNonInterne
4orchestrator3004PostgreSQLNonAxios (appels inter-services)Publique (via Ingress)
5notifications3005PostgreSQLNonFirebase FCM, AxiosInterne
6configuration3006PostgreSQLNonSeeders données ref.Publique (via Ingress)
7file-service3007PostgreSQLNonFirebase Storage, MulterInterne
8providers-gateway3008PostgreSQLNonInterne
9risk-engine3009PostgreSQLNonInterne
10service-catalog3010PostgreSQLOui (cache)Axios, OpenAPI GeneratorInterne
11logs-reporting3011AucuneNonInterne

Note : ces ports correspondent au code existant dans le monorepo. Ne pas les modifier.

2.4 Architecture du monorepo

Le projet est un monorepo unique (nex/) hébergé dans un seul repo GitLab, géré par pnpm workspaces et Turborepo.

nex/                                     # Racine du monorepo (un seul repo GitLab)
├── apps/
│   ├── mobile-client/                   # Expo SDK 53 / RN 0.79.5 — App Client (NokiPay)
│   ├── mobile-pro/                      # Expo SDK 53 / RN 0.79.5 — App Marchand (NxPay Business)
│   ├── cmms/                            # Nuxt 4.2.2 · SPA · Nuxt UI · Tailwind
│   └── backoffice/                      # Nuxt 4.2.2 · Nuxt UI · Tailwind
├── packages/
│   ├── tokens/                          # Design tokens (ZERO deps, platform-agnostic)
│   ├── ui-mobile/                       # Design system React Native (raw TS, Metro transpiles)
│   ├── ui-web/                          # Design system Web (CSS themes Nuxt UI)
│   ├── shared-types/                    # DTOs, enums, interfaces (ZERO deps)
│   ├── shared-utils/                    # Formatters, validators, CEMAC constants
│   ├── eslint-config/                   # Configs ESLint partagées
│   └── tsconfig/                        # Configs TypeScript partagées
├── services/
│   ├── auth/                            # NestJS · PostgreSQL · Redis · Auth0
│   ├── ledger-wallets/                  # NestJS · PostgreSQL · Seeders (critique)
│   ├── customer-profiles-kyc/           # NestJS · PostgreSQL
│   ├── orchestrator/                    # NestJS · PostgreSQL · Cucumber (BDD tests)
│   ├── notifications/                   # NestJS · PostgreSQL · Firebase FCM
│   ├── configuration/                   # NestJS · PostgreSQL · Seeders
│   ├── file-service/                    # NestJS · PostgreSQL · Firebase Storage
│   ├── providers-gateway/               # NestJS · PostgreSQL
│   ├── risk-engine/                     # NestJS · PostgreSQL
│   ├── service-catalog/                 # NestJS · PostgreSQL · Redis
│   └── logs-reporting/                  # NestJS (sans BDD)
├── infrastructure/                      # Tout l'IaC (voir section 6)
├── infra-2026/                          # Documentation du plan de déploiement
├── pnpm-workspace.yaml
├── turbo.json
├── package.json
└── .gitlab-ci.yml                       # Pipeline CI/CD unique à la racine

Conséquences pour le CI/CD :

  • Un seul .gitlab-ci.yml à la racine du monorepo
  • Turborepo pilote la détection des changements (--filter=...[origin/staging...HEAD])
  • Un seul Dockerfile templatisé pour les 11 services (voir section 6)
  • Le contexte Docker est la racine du monorepo (les services dépendent des packages locaux)

3. VARIABLES GLOBALES

L'agent utilise ces variables pour paramétrer chaque script et manifest. Aucune valeur ne doit être hardcodée ailleurs.

yaml
# ============================================================
# NEX — VARIABLES GLOBALES
# ============================================================

# --- Projet ---
project_name: "nex"
project_domain: "paywithnex"
company_name: "Nex"

# --- AWS ---
aws_region_primary: "eu-west-1"       # Ireland
aws_region_backup: "eu-west-3"        # Paris (backups cross-région)
aws_account_id: "XXXXXXXXXXXX"        # À remplir

# --- Environnements ---
environments:
  staging:
    shortname: "stg"
    eks_cluster: "nex-staging"
    rds_db: "nex_staging"
  production:
    shortname: "prd"
    eks_cluster: "nex-production"
    rds_db: "nex_production"
  review:
    # Environnements éphémères de review (un par epic/branche)
    # Déployés comme namespaces temporaires sur le cluster staging
    shortname: "rev"
    eks_cluster: "nex-staging"            # Réutilise le cluster staging
    namespace_pattern: "nex-review-{branch}"
    rds_schema_pattern: "review_{branch}" # Schema dédié dans la même instance RDS staging
    replicas: 1                           # Toujours 1 replica en review
    ttl_hours: 48                         # Détruit automatiquement après 48h sans commit
    dns_pattern: "{branch}.review.paywithnex.com"

# --- Réseau (VPC) ---
vpc_cidr: "10.0.0.0/16"
subnets:
  public_a:   "10.0.1.0/24"          # eu-west-1a — Load Balancer, NAT
  public_b:   "10.0.2.0/24"          # eu-west-1b — Load Balancer, NAT
  private_a:  "10.0.10.0/24"         # eu-west-1a — Pods EKS
  private_b:  "10.0.20.0/24"         # eu-west-1b — Pods EKS
  data_a:     "10.0.100.0/24"        # eu-west-1a — RDS, Redis
  data_b:     "10.0.200.0/24"        # eu-west-1b — RDS, Redis

# --- Domaines ---
domains:
  root: "paywithnex.com"              # Adapter au TLD réel
  api_staging: "staging.paywithnex.com"
  api_prod: "api.paywithnex.com"
  admin: "admin.paywithnex.com"       # CMMS Dashboard
  backoffice: "bo.paywithnex.com"     # Backoffice
  app: "app.paywithnex.com"           # Landing page éventuelle
  review_wildcard: "*.review.paywithnex.com"  # Envs de review éphémères

# --- Kubernetes (EKS) ---
eks:
  k8s_version: "1.29"
  node_instance_type: "t3.medium"     # 2 vCPU, 4 Go RAM
  node_min: 2
  node_max: 5
  node_desired: 2                     # Staging. Prod: 3.

# --- Base de données (RDS PostgreSQL) ---
rds:
  engine_version: "16.4"
  instance_class_staging: "db.t3.small"
  instance_class_prod: "db.t3.medium"
  storage: 20                          # Go initial
  max_storage: 100                     # Go auto-scaling
  backup_retention: 30                 # jours
  port: 5432

# --- Redis (ElastiCache) ---
redis:
  engine_version: "7.1"
  node_type_staging: "cache.t3.micro"
  node_type_prod: "cache.t3.small"
  port: 6379

# --- Tags AWS (sur TOUTES les ressources) ---
tags:
  Project: "nex"
  ManagedBy: "terraform"
  Team: "engineering"

4. SERVICES — CONFIGURATION DE DÉPLOIEMENT

4.1 Services publics (exposés via Ingress)

yaml
services_public:
  - name: "auth"
    path: "/auth"                     # Route Ingress
    port: 3001
    replicas_staging: 2
    replicas_prod: 3
    memory: "256Mi"
    cpu: "250m"
    health_path: "/health"
    needs_redis: true
    needs_postgres: true
    env_specific:
      - AUTH0_DOMAIN
      - AUTH0_CLIENT_ID
      - AUTH0_CLIENT_SECRET
      - AUTH0_AUDIENCE
      - JWT_SECRET

  - name: "configuration"
    path: "/configuration"
    port: 3006
    replicas_staging: 1
    replicas_prod: 2
    memory: "128Mi"
    cpu: "125m"
    health_path: "/health"
    needs_redis: false
    needs_postgres: true
    env_specific: []
    note: "Service pilote CI/CD — zéro dépendance externe"

  - name: "orchestrator"
    path: "/api"
    port: 3004
    replicas_staging: 2
    replicas_prod: 3
    memory: "512Mi"
    cpu: "500m"
    health_path: "/health"
    needs_redis: false
    needs_postgres: true
    env_specific: []
    note: "Dépend de TOUS les services internes. Déployé en dernier."

4.2 Services internes (ClusterIP uniquement)

yaml
services_internal:
  - name: "ledger-wallets"
    port: 3002
    replicas_staging: 2
    replicas_prod: 3
    memory: "512Mi"
    cpu: "500m"
    health_path: "/health"
    needs_redis: false
    needs_postgres: true
    note: "Service critique — gère les soldes. Replicas élevés."

  - name: "customer-profiles-kyc"
    port: 3003
    replicas_staging: 1
    replicas_prod: 2
    memory: "256Mi"
    cpu: "250m"
    health_path: "/health"
    needs_redis: false
    needs_postgres: true

  - name: "notifications"
    port: 3005
    replicas_staging: 1
    replicas_prod: 2
    memory: "256Mi"
    cpu: "250m"
    health_path: "/health"
    needs_redis: false
    needs_postgres: true
    env_specific:
      - FIREBASE_PROJECT_ID
      - FIREBASE_SERVER_KEY
      - RESEND_API_KEY

  - name: "file-service"
    port: 3007
    replicas_staging: 1
    replicas_prod: 2
    memory: "256Mi"
    cpu: "250m"
    health_path: "/health"
    needs_redis: false
    needs_postgres: true
    env_specific:
      - FIREBASE_PROJECT_ID
      - FIREBASE_STORAGE_BUCKET
    note: "Firebase Storage pour fichiers users, S3 pour backups."

  - name: "providers-gateway"
    port: 3008
    replicas_staging: 1
    replicas_prod: 2
    memory: "256Mi"
    cpu: "250m"
    health_path: "/health"
    needs_redis: false
    needs_postgres: true

  - name: "risk-engine"
    port: 3009
    replicas_staging: 1
    replicas_prod: 2
    memory: "256Mi"
    cpu: "250m"
    health_path: "/health"
    needs_redis: false
    needs_postgres: true

  - name: "service-catalog"
    port: 3010
    replicas_staging: 1
    replicas_prod: 2
    memory: "256Mi"
    cpu: "250m"
    health_path: "/health"
    needs_redis: true
    needs_postgres: true

  - name: "logs-reporting"
    port: 3011
    replicas_staging: 1
    replicas_prod: 1
    memory: "128Mi"
    cpu: "125m"
    health_path: "/health"
    needs_redis: false
    needs_postgres: false
    note: "Service le plus léger — pas de base de données."

4.3 Ordre de déploiement

L'agent doit respecter cet ordre. Chaque étape valide le /health du service avant de passer au suivant.

yaml
deploy_order:
  # --- Phase A : Service pilote (valide la chaîne CI/CD) ---
  pilot: "configuration"
  # Pourquoi : zéro dépendance externe, service le plus simple.
  # Valide : GitLab CI → build Docker → push registry → deploy K8s → /health OK

  # --- Phase B : Généralisation (ordre de dépendance) ---
  wave_1:                             # Services sans dépendance inter-service
    - "logs-reporting"                # Pas de DB, le plus léger
    - "customer-profiles-kyc"         # Juste PostgreSQL
    - "providers-gateway"             # Juste PostgreSQL
    - "risk-engine"                   # Juste PostgreSQL

  wave_2:                             # Services avec dépendances externes
    - "auth"                          # Redis + Auth0
    - "service-catalog"               # Redis
    - "file-service"                  # Firebase Storage
    - "ledger-wallets"                # PostgreSQL (critique — seeders)

  wave_3:                             # Services qui dépendent d'autres services
    - "notifications"                 # Firebase FCM + Resend

  wave_4:                             # Orchestrateur — dépend de TOUT
    - "orchestrator"                  # Appelle tous les autres via HTTP

5. STACK TECHNIQUE RETENUE

5.1 Vue d'ensemble

CoucheProviderServiceJustification
Code + CI/CDGitLabGitLab.com (SaaS) + GitLab CIPipeline natif, registre Docker inclus
Registre DockerGitLabContainer RegistryGratuit, intégré au CI, pas de lock-in
CDN + WAF + DNSCloudflareProMeilleur WAF/DDoS, edge global
Dashboards (Nuxt.js)FirebaseHostingSPA/SSR natif, CDN Google, CLI simple
Apps mobilesApple / GoogleApp Store + Play StoreDistribution standard
ComputeAWSEKS (Kubernetes)K8s standard portable + réseau AWS
Base de donnéesAWSRDS PostgreSQLMulti-AZ, backups auto, failover
CacheAWSElastiCache RedisSessions (auth), cache (service-catalog)
Stockage fichiers usersFirebaseCloud StorageUtilisé par file-service (déjà intégré)
Stockage backupsAWSS3 + GlacierBackups DB, archivage réglementaire
AuthAuth0Free → EssentialOAuth2/OIDC, MFA, tenant EU
Push notificationsFirebaseCloud Messaging (FCM)Gratuit, standard iOS/Android
MonitoringGrafana CloudPrometheus + Loki + TempoMétriques + logs + traces, multi-cloud
Erreurs applicativesSentryTeamCrash reporting avec contexte
Uptime externeUptimeRobotProMonitoring indépendant, rapports régulateur
SecretsDopplerTeamMulti-cloud, injecte dans K8s
Qualité codeSonarCloudFreeAnalyse statique dans le pipeline
Email transactionnelResendFree → ProConfirmations, alertes
SMS/OTPÀ définirTwilio ou Africa's Talking

5.2 Principes directeurs

  • Zéro vendor lock-in : chaque brique est remplaçable indépendamment.
  • Best of breed : chaque provider sur son point fort.
  • AWS pour les données et le réseau : fiabilité critique.
  • Firebase pour les fichiers et le hosting : déjà intégré dans le code (file-service, notifications).
  • Kubernetes comme abstraction compute : manifests portables vers n'importe quel cluster.

5.3 Ce que l'agent NE doit PAS faire

  • Ne pas utiliser AWS CloudFront → Cloudflare gère le CDN
  • Ne pas utiliser AWS Route 53 → Cloudflare gère le DNS
  • Ne pas utiliser AWS Secrets Manager → Doppler gère les secrets
  • Ne pas utiliser AWS CloudWatch comme monitoring principal → Grafana Cloud
  • Ne pas utiliser AWS SES → Resend gère les emails
  • Ne pas utiliser AWS ECR → GitLab Container Registry
  • Ne pas utiliser AWS S3 pour les fichiers users → Firebase Storage (déjà dans file-service)
  • Ne pas créer de ressources hors eu-west-1 sauf backups cross-région (eu-west-3)

6. STRUCTURE IaC (dans le monorepo)

L'infrastructure vit dans le dossier infrastructure/ du monorepo nex/. Pas de repo séparé.

nex/infrastructure/                          # Tout l'IaC est ici

├── docker/
│   ├── Dockerfile.service                   # UNIQUE — templatisé pour les 11 services
│   ├── .dockerignore                        # Exclut node_modules, .git, tests, docs
│   ├── postgresql/                          # Dev local (existant)
│   ├── redis/                               # Dev local (existant)
│   └── node/                                # Dev local (existant)

├── terraform/
│   ├── bootstrap/                           # S3 state + DynamoDB lock (une seule fois)
│   ├── modules/
│   │   ├── vpc/                             # VPC, subnets, NAT, IGW, routes, SG
│   │   ├── eks/                             # Cluster EKS, node groups, IAM, OIDC
│   │   ├── rds/                             # PostgreSQL, subnet groups, params
│   │   ├── redis/                           # ElastiCache, subnet groups
│   │   ├── s3/                              # Buckets backups, lifecycle, encryption
│   │   └── iam/                             # Rôles globaux, policies
│   └── environments/
│       ├── staging/                         # main.tf, variables.tf, outputs.tf, backend.tf
│       └── production/                      # Même structure, params différents

├── kubernetes/
│   ├── base/                                # Ressources communes (Kustomize)
│   │   ├── kustomization.yaml
│   │   ├── namespaces.yaml
│   │   ├── network-policies.yaml
│   │   ├── resource-quotas.yaml
│   │   └── ingress/
│   ├── services/                            # Un dossier par microservice (11)
│   │   ├── auth/
│   │   ├── ledger-wallets/
│   │   ├── customer-profiles-kyc/
│   │   ├── orchestrator/
│   │   ├── notifications/
│   │   ├── configuration/
│   │   ├── file-service/
│   │   ├── providers-gateway/
│   │   ├── risk-engine/
│   │   ├── service-catalog/
│   │   └── logs-reporting/
│   ├── overlays/
│   │   ├── staging/                         # Kustomize overlay staging
│   │   ├── production/                      # Kustomize overlay production
│   │   └── review/                          # Kustomize overlay review (replicas=1, resources réduits)
│   ├── monitoring/                          # Grafana Agent, Prometheus, Loki, dashboards
│   └── jobs/                                # CronJobs (backups, cleanup review envs)

├── firebase/
│   ├── firebase.json                        # Config Hosting (CMMS + Backoffice)
│   └── .firebaserc                          # Alias des projets

├── nginx/                                   # Reverse proxy dev local (existant)
├── prisma/                                  # Schema introspection (existant)
├── swagger/                                 # Swagger Hub (existant)
├── railway/                                 # Ancien hosting (conservé temporairement)

├── scripts/                                 # Existant + nouveaux scripts
│   ├── database/                            # Migrations SQL, seeds (existant)
│   ├── setup-kubeconfig.sh                  # NOUVEAU
│   ├── seed-database.sh                     # NOUVEAU
│   ├── backup-manual.sh                     # NOUVEAU
│   ├── rotate-db-password.sh                # NOUVEAU
│   ├── rollback.sh                          # NOUVEAU
│   └── review-env-cleanup.sh                # NOUVEAU — supprime les envs review > TTL

└── docs/                                    # Existant + runbook
    └── runbook-astreinte.md                 # NOUVEAU

Le pipeline CI/CD principal (.gitlab-ci.yml) est à la racine du monorepo nex/, pas dans infrastructure/.

Conventions pour l'agent

  • Nommage Terraform : nex-{env}-{resource} (ex: nex-staging-postgres)
  • Nommage K8s : namespace nex-{env}, labels app: {service}, project: nex, environment: {env}
  • Nommage K8s review : namespace nex-review-{branch}, même labels + review: true
  • Nommage S3 : nex-{env}-{usage} (ex: nex-staging-backups)
  • Dockerfile : UN SEUL infrastructure/docker/Dockerfile.service templatisé via build arg SERVICE. Multi-stage build, image finale node:20-alpine, user non-root, HEALTHCHECK inclus. Contexte Docker = racine du monorepo. Utilise pnpm --filter @nex/{service}... pour installer uniquement le service et ses dépendances workspace.
  • Build : utiliser SWC (déjà configuré dans les services) pas tsc
  • Package manager : pnpm (pas npm, pas yarn)
  • Pipeline CI : un seul .gitlab-ci.yml à la racine. Turborepo (--filter=...[origin/staging...HEAD]) détecte les services/packages impactés par les changements. Ne build que ce qui a changé.
  • Secrets : jamais dans Git. Tout via Doppler → External Secrets Operator → K8s Secrets
  • Tags : chaque ressource AWS porte les tags définis dans les variables

7. PRÉ-REQUIS

7.1 Comptes à créer avant de démarrer

ServiceActionRésultat attendu
AWSCompte dédié + MFA root + IAM admin + CloudTrail + Budget alertsaws sts get-caller-identity OK
CloudflareCompte + domaine paywithnex.comNameservers Cloudflare actifs
GitLabGroupe nex + un seul repo monorepoRepo accessible
Auth0Tenant EU + apps "Nex API" et "Nex Mobile"Client ID/Secret dispo
FirebaseProjet "nex-app" + Hosting + FCM + StorageConsole accessible
Grafana CloudCompte Free + endpoints Prometheus/Loki/TempoURLs + API key
SentryOrganisation "nex" + un projet par serviceDSN récupérés
DopplerWorkspace "nex" + envs dev/staging/productiondoppler configs OK
UptimeRobotCompte ProDashboard accessible
ResendCompte + domaine vérifiéAPI key récupérée
SonarCloudOrganisation liée au GitLabProjet visible
Apple DeveloperCompte ($99/an)Accès App Store Connect
Google PlayCompte ($25 one-time)Accès Play Console

7.2 Outils CLI

L'agent vérifie que ces outils sont installés avant de commencer :

  • aws (>= 2.x) configuré avec profil nex-admin
  • terraform (>= 1.7)
  • kubectl (>= 1.29)
  • helm (>= 3.14)
  • kustomize
  • docker
  • doppler
  • firebase-tools
  • pnpm
  • turbo (Turborepo — orchestration monorepo)
  • jq, yq

8. PLAN DE DÉPLOIEMENT — VUE D'ENSEMBLE

FichierContenuDépend de
01_infra_base.mdVPC, EKS, RDS, Redis, S3, DNS, certificatsCe fichier (00)
02_cicd_et_services.mdGitLab CI + deploy pilote (configuration) + généralisation (11 services)01
03_gateway_cdn_securisation.mdCloudflare, WAF, network policies, SG, secrets, hardening02
04_monitoring_alertes.mdGrafana, Sentry, UptimeRobot, alertes, dashboards, runbook03
05_deploy_mobile_stores.mdBuild React Native, Fastlane, App Store, Play Store, CI/CD mobile02

Le fichier 05 (mobile) peut être exécuté en parallèle du 03 et 04 — il n'a pas de dépendance sur la sécurisation ni le monitoring.


Ce document est la référence absolue du projet. En cas de conflit entre ce fichier et un autre, ce fichier fait autorité.

NxPay — Plateforme fintech CEMAC