Un code, quatre audiences
L’API est un unique code Fastify, déployé en containers indépendants, un par audience. L’audience
est choisie au démarrage par APP_AUDIENCE.
La table de routage est dans src/app/audiences.ts : préfixe, factory d’app, modules, et pour rs le
flag realtime.
APP_AUDIENCE n’a aucune valeur par défaut. Absente ou inconnue, le process crashe au démarrage.
C’est voulu : impossible de lancer la mauvaise audience par accident.
Pourquoi un seul code : une migration, une suite de tests, un pipeline. Les audiences ne diffèrent
que par les routes montées — tout le partagé (DB, plugins, erreurs, pagination, i18n) n’existe qu’une fois.
Arborescence
Une nouvelle fonctionnalité vit dans audiences/<audience>/modules/<nom>/v1/ et s’enregistre comme
plugin Fastify.
Base de données
Un seul Postgres, un seul schéma Prisma dans apps/api/database/ — workspace séparé pour que les
migrations tournent sans démarrer le serveur.
Ne jamais éditer une migration déjà commitée. Voir Migrations pour la règle
expand/contract, obligatoire.
Erreurs
Tout ce qui peut remonter à un client HTTP doit être un AppError (src/kit/errors/app-error.ts),
jamais un Error brut : le handler Fastify global mappe AppError sur son statusCode / code, alors
qu’un Error brut devient un 500 INTERNAL_SERVER_ERROR générique — le message réel est loggé mais
perdu pour le client.
Santé
/health (liveness) et /health/ready (readiness). Le health gate des déploiements sonde
/health/ready pour l’API et /health pour les fronts.
Tests
Les tests d’intégration utilisent inject() de Fastify contre une vraie base : le globalSetup dérive
une base template migrée puis la clone une fois par worker. Les tests de routes s’appuient sur les
fixtures rsFixture, boFixture, adFixture, prFixture.