Problème
Construire un outil de facturation conforme aux usages français (SIRET, TVA, FEC) en mode SaaS multi-tenant, avec abonnements Stripe et portail client public.
Contexte
Projet personnel, en production sur helios.staki.fr. Self-hosted sur VPS Hetzner via Coolify.
Stack technique
- Bun >= 1.3
- Next.js 15 (App Router, Server Components)
- TypeScript 5
- PostgreSQL 16 + Prisma 7
- NextAuth 5 (JWT)
- Stripe (subscriptions + credits)
- React 19 + Tailwind v4
- Puppeteer Core + @sparticuz/chromium
- Zod 4
- Supabase Storage
- Vitest 4 + fast-check
- GitHub Actions → Coolify (Hetzner)
Décisions techniques
- Multi-tenancy au niveau applicatif via `assertOwnership()` plutôt que Postgres RLS : plus simple à tester, contrôle total des règles d'accès.
- Server Actions qui retournent un `ActionState { status, message }` au lieu de throw — gestion d'erreurs uniforme côté client avec `useActionState`.
- PostgreSQL advisory lock sur les vérifications de quota d'abonnement pour éviter les TOCTOU sur les requêtes concurrentes.
- AES-256-GCM pour les secrets TOTP et les IBAN au repos, une seule `ENCRYPTION_KEY` qui contrôle tous les champs sensibles.
- Nonces CSP générés par requête dans le middleware, propagés via header `x-nonce` — tous les scripts inline doivent porter le nonce.
Difficultés
- Suppression GDPR-compliant : période de grâce de 30 jours + cron de purge protégé par `CRON_SECRET`, avec audit log de toutes les actions admin.
- Génération PDF en environnement serverless-like : Puppeteer Core + `@sparticuz/chromium` pour rester sous la limite mémoire du runtime Bun.
- Protection SSRF sur les webhooks sortants (validation IP + DNS resolve) — sinon un user pourrait pinguer le réseau interne du VPS.
Résultats
- En production sur helios.staki.fr, plans FREE / STARTER / PRO / ONE_SHOT actifs.
- API REST publique avec bearer tokens `hls_*`, panel admin (users, audit logs, broadcasts).
- ~55 fichiers de tests unitaires/intégration avec Prisma mocké.