2.3 KiB
2.3 KiB
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.