> ## Documentation Index
> Fetch the complete documentation index at: https://api-documentation.kare-app.fr/llms.txt
> Use this file to discover all available pages before exploring further.

# API

> Un seul code Fastify, quatre audiences

## 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`.

```mermaid theme={null}
flowchart TD
    A["apps/api"] --> R["APP_AUDIENCE=rs<br/>préfixe /rs<br/>front kare<br/>+ WebSocket"]
    A --> B["APP_AUDIENCE=bo<br/>préfixe /bo<br/>front backoffice"]
    A --> D["APP_AUDIENCE=ad<br/>préfixe /ad<br/>front audit"]
    A --> P["APP_AUDIENCE=pr<br/>préfixe /pr<br/>front provider"]
```

La table de routage est dans `src/app/audiences.ts` : préfixe, factory d'app, modules, et pour `rs` le
flag `realtime`.

<Warning>
  `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.
</Warning>

**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

```text theme={null}
apps/api/src/
├── server.ts            lit APP_AUDIENCE et démarre le bon serveur
├── app/
│   ├── audiences.ts     audience → préfixe + app + modules
│   ├── build-app.ts     factory partagée : plugins, DB, health
│   └── audience-app.ts  assemblage d'une audience
├── audiences/
│   ├── rs/  bo/  ad/  pr/
│   │   ├── app.ts       enregistre les modules de l'audience
│   │   ├── modules/     un dossier par domaine métier, versionné (v1/)
│   │   ├── plugins/     spécifique à l'audience
│   │   └── lib/
├── plugins/             transverse : auth, rate-limit, i18n, Sentry, erreurs
├── lib/                 métier transverse : audit, authz, email, jobs, realtime, upload, pdf…
├── db/                  client Prisma généré et helpers de champs
├── infra/               config d'env, adaptateurs, enums
├── kit/                 outils : errors, pagination, parse-query, openapi, readiness
└── seed/                seeder (jamais servi en HTTP)
```

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.

| Chemin                        | Contenu                                  |
| ----------------------------- | ---------------------------------------- |
| `database/prisma/schemas/`    | schéma Prisma découpé                    |
| `database/prisma/migrations/` | migrations                               |
| `database/data-migrations/`   | migrations de données, scripts autonomes |

<Warning>
  Ne jamais éditer une migration déjà commitée. Voir [Migrations](/devops/migrations) pour la règle
  expand/contract, obligatoire.
</Warning>

## 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.

| Couche                                         | Comment lever                                                                     |
| ---------------------------------------------- | --------------------------------------------------------------------------------- |
| Transverse (guards, contexte d'auth, handlers) | `throwErr('forbidden' \| 'unauthorized' \| 'notFound' \| …)` depuis `@kit/errors` |
| Règle métier d'un module                       | codes dans le `domain/errors.ts` du module, levés via un helper `assertXxx`       |
| Invariant interne jamais exposé                | `throw new Error(...)` toléré : bootstrap fail-fast, `src/seed/**`, tests         |
| Hooks Better Auth (`src/lib/auth/config/**`)   | `APIError` de `better-auth/api`, **pas** `AppError`                               |

## 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

```bash theme={null}
cd apps/api
make test-unit    # aucune dépendance
make test         # unit + intégration (exige Postgres + Redis)
```

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`.
