Observabilité

Format de logs, corrélation de requêtes, health check, seuils d'alerte et bonnes pratiques d'observabilité de la plateforme.

Objectifs

  • Faciliter le diagnostic rapide des incidents.
  • Relier chaque erreur à une requête via requestId.
  • Fournir une base de pilotage pour tous les modules métier (auth, booking, finance).

Format de logs

Les logs sont émis en format JSON line via app/mypromo/server/modules/shared/infrastructure/logger.ts.

Champs standard :

ChampDescription
timestampDate ISO 8601 (ex. 2026-02-09T10:00:00.000Z)
leveldebug / info / warn / error
scopeModule ou couche émetteur (ex. api-handler, auth-audit)
messageDescription courte de l'événement
requestIdIdentifiant de corrélation (si disponible)

Exemple :

{
  "timestamp": "2026-02-09T10:00:00.000Z",
  "level": "error",
  "scope": "api-handler",
  "message": "request failed",
  "requestId": "f7a2f4b6-..."
}

Le niveau minimal de sortie est configurable via la variable d'environnement LOG_LEVEL (valeur par défaut : info). Les niveaux inférieurs au seuil configuré ne produisent aucune sortie.

Corrélation de requêtes

Gérée par app/mypromo/server/middleware/request-id.ts :

  1. Le middleware lit l'en-tête entrant x-request-id si présent et valide (max 128 caractères, pattern ^[A-Za-z0-9._:-]+$).
  2. Sinon, il génère un UUID côté serveur.
  3. L'identifiant est attaché au contexte de l'événement Nitro (event.context.requestId).
  4. L'en-tête x-request-id est systématiquement renvoyé dans la réponse.

Tous les appels à log() propagent le requestId du contexte, ce qui permet de regrouper l'ensemble des entrées de log d'une même requête HTTP.

Rate limiting

app/mypromo/server/middleware/rate-limit.ts applique un anti-abus en mémoire sur deux groupes de routes :

RègleRoutes concernéesLimite
auth-sensitive/api/auth/sign-in, /api/auth/sign-up, reset mot de passe, vérification email10 req/min par IP
admin-critical/api/admin/**, /api/auth/assign-role, /api/notifications/email-smoke60 req/min par IP

Les dépassements produisent une réponse 429 Too Many Requests avec un log warn dans le scope api-rate-limit. La réponse JSON contient data.retryAfterSeconds indiquant le délai en secondes avant de réessayer. Les en-têtes x-ratelimit-limit, x-ratelimit-remaining et x-ratelimit-reset sont positionnés uniquement sur les réponses qui ne dépassent pas la limite (requêtes autorisées).

Télémétrie in-process

app/mypromo/server/modules/shared/infrastructure/telemetry.ts maintient des compteurs en mémoire :

  • apiRequestsTotal — nombre total de requêtes API traitées.
  • apiErrorsTotal — nombre total d'erreurs API.

Ces valeurs sont exposées dans la réponse du health check (champ telemetry). Elles se remettent à zéro au redémarrage du processus.

Health check

Route : GET /api/health

Payload retourné :

{
  "service": "pulse-my-promo-api",
  "status": "ok",
  "environment": "production",
  "uptimeSeconds": 3600,
  "telemetry": {
    "apiRequestsTotal": 1200,
    "apiErrorsTotal": 3
  }
}

Le handler est défini dans app/mypromo/server/api/health.get.ts. Il n'effectue pas de vérification de connectivité base de données — il sert de signal de vivacité du processus Node.

Audit de sécurité

Les actions sensibles sont persistées en base PostgreSQL via la table SecurityAuditLog (gérée par Prisma). Le repository se trouve dans app/mypromo/server/modules/auth/infrastructure/security-audit.repository.ts.

Événements tracés :

  • Auth : auth.sign_up.*, auth.sign_in.*, auth.magic_link.*, auth.sign_out.success, auth.password_reset.*, auth.email_verification.*
  • Actions admin : création d'admin, mise à jour utilisateur par admin, création de membership organisation, changement de rôle, KYB, blocage utilisateur
  • Invitations organisation : création et acceptation

L'interface admin de consultation est exposée via GET /api/admin/audit/security.

Erreurs non capturées

Le plugin app/mypromo/server/plugins/10-error-logging.ts accroche le hook error de Nitro pour journaliser toute erreur serveur non gérée par un handler, avec le requestId associé lorsqu'il est disponible.

Arrêt propre

app/mypromo/server/plugins/99-prisma-close.ts accroche le hook close de Nitro pour déconnecter explicitement le client Prisma à l'arrêt du processus, évitant les connexions PostgreSQL pendantes.

Seuils d'alerte

Les seuils suivants sont des seuils de référence proposés, à configurer dans l'outil de monitoring retenu. Ils ne sont pas câblés à un système d'alerte actif à ce stade :

ConditionSeuil proposé
Taux d'erreurs 5xx> 2 % sur 5 min
Health check indisponible> 2 min
Build CI en échec sur branche principaleimmédiat

Bonnes pratiques

  • Ne jamais logger de secrets : clés API, mots de passe, tokens.
  • Limiter la taille des payloads loggés.
  • Préférer des codes d'erreur stables (error.code) aux messages libres.
  • Utiliser le champ scope pour identifier clairement la couche émettrice.