Files

seiche-server

Backend Fastify 5 (TypeScript strict, Node 22 via tsx). Sert l'API /api/* et, en production, le front prébuildé (SEICHE_PUBLIC_DIR) sur le même port — zéro CORS, 1 conteneur.

Scripts

Script Rôle
pnpm dev Serveur en watch sur http://localhost:8787 (défauts config)
pnpm start Serveur en mode prod (idem, sans watch)
pnpm setup Crée le compte admin initial (idempotent ; SEICHE_ADMIN_USERNAME / SEICHE_ADMIN_PASSWORD, mdp ≥ 12 car.)
pnpm db:generate drizzle-kit generate — génère les migrations dans drizzle/
pnpm test Vitest (API injectée, SQLite :memory:) — 30 tests
pnpm typecheck tsc --noEmit

Les migrations sont appliquées automatiquement au boot (migrate() de Drizzle, dossier drizzle/).

Structure

src/
├── main.ts        # boot : dataDir, DB + migrations, listen, shutdown propre
├── app.ts         # buildApp (trustProxy, logger, plugins, routes)
├── config.ts      # toutes les variables d'env (voir .env.example racine)
├── validation.ts  # schémas Zod partagés
├── setup.ts       # création idempotente du compte admin
├── auth/          # password (argon2id), session + CSRF, rate-limit
├── routes/        # auth, external, health
├── db/            # client libsql (WAL) + schema Drizzle
├── external/      # client du service REST externe (adaptateurs example/http)
└── drizzle/       # migrations versionnées (drizzle/)

API

Route Accès Rôle
GET /api/health public healthcheck
POST /api/auth/login rate-limit session httpOnly + cookie CSRF (double-submit)
POST /api/auth/logout · GET /api/auth/session session révocation / état de la session
GET /api/external/health · GET /api/external/items · POST /api/external/items session pont vers le service externe (adaptateurs example / http)

Erreurs : corps JSON { statusCode, error, message, code, ... } (le code machine est stable, le message ne fuit jamais les détails internes).

Tests

pnpm test

Les tests injectent Fastify (app.inject) avec une base :memory: par worker (tests/helpers.ts : makeConfig, openTestDb, cookies) — pas de dépendance au réseau.