Aller au contenu principal

Décisions d'Architecture (ADR)

Ce fichier documente les choix structurants du projet. Chaque décision inclut le contexte, la décision, les raisons, et les alternatives rejetées.

ADR-001 : FastAPI pour le backend

Date : 2026-02-21 Statut : Accepté

Contexte

Nous avions besoin d'un framework Python pour exposer une API REST consommée par 3 frontends Next.js différents (Discover, Career, Admin).

Décision

Nous utilisons FastAPI.

Pourquoi

  • Validation automatique des données via Pydantic
  • Génération automatique d'OpenAPI/Swagger (documentation API intégré)
  • Performances élevées grâce à l'async natif pour les opérations I/O
  • Léger et minimal comparé à Django

Alternatives rejetées

  • Django REST Framework : Trop de overhead pour un projet API-only. Utile si nous avions besoin du panneau admin Django.
  • Flask : Trop minimal, configuration manuelle pour la validation et la documentation.

Conséquences

  • Nous gérons nous-mêmes certaines choses que Django fait automatiquement (admin panel).
  • La documentation API est générée automatiquement → gain de temps.

ADR-002 : PostgreSQL via Supabase

Date : 2026-02-21 Statut : Accepté

Contexte

Nous avions besoin d'une base de données relationnelle et d'un système d'authentification.

Décision

Nous utilisons PostgreSQL via Supabase, avec une approche hybride.

Pourquoi

  • Supabase Auth : Gère directement email/password, reset password, sessions utilisateurs
  • PostgreSQL : Base de données relationnelle pour les données métier via SQLAlchemy
  • Row Level Security (RLS) : Sécurité des données au niveau base

Alternatives rejetées

  • Firebase : Verrouillage fournisseur, moins de contrôle sur les données.
  • Auth0 : Coût additionnel, nous préférons garder le contrôle.

Conséquences

  • Deux clients Supabase : normal (respecte RLS) et admin (bypass RLS pour opérations système).

ADR-003 : Migrations SQL brutes → Adoption d'Alembic

Date : 2026-02-21 Statut : Mis à jour

Contexte

Nous avons démarré avec des fichiers SQL bruts pour les migrations, ce qui fonctionnait pour un projet de petite taille. Cependant, avec 46+ tables et plusieurs développeurs, la traçabilité entre environnements est devenue un risque réel : désynchronisation entre staging et production, difficulté à reproduire un état exact, et risque d'erreur humaine sur les scripts manuels.

Décision

Nous adoptons Alembic avec une approche par migration initiale vide + stamp head :

  1. Première migration vide (61e524cfcce2_initial_state.py) avec upgrade() et downgrade() vides
  2. alembic stamp head marque cette migration comme appliquée sans exécuter de SQL
  3. Les futures modifications de schéma créent des migrations versionnées
  4. Les modèles SQLAlchemy sont créés progressivement, uniquement pour les tables nécessitant une migration — le projet utilisant le client Supabase natif directement

Pourquoi

  • Traçabilité : alembic current montre l'état exact de chaque environnement
  • Rollback possible : chaque migration peut être annulée
  • Onboarding simplifié : alembic upgrade head suffit pour mettre à jour la DB
  • Cohérence avec les bonnes pratiques : approche standard dans l'écosystème Python/SQLAlchemy

Alternatives rejetées

  • Garder les SQL bruts : Risque de désynchronisation entre environnements, pas de rollback facile.
  • Créer 46 modèles ORM immédiatement : Over-engineering inutile — nous n'utilisons pas SQLAlchemy ORM pour les opérations de données, seulement pour les migrations.

Conséquences

  • alembic current affiche l'état exact de chaque environnement
  • Chaque modification de schéma = fichier de migration versionné dans alembic/versions/
  • Limite connue : sans ORM complet, autogenerate nécessite de créer le modèle SQLAlchemy pour la table concernée avant de générer la migration
  • Le client Supabase natif reste utilisé pour toutes les opérations de données — Alembic gère uniquement les migrations de schéma

ADR-004 : Redis pour cache uniquement

Date : 2026-02-21 Statut : Accepté

Contexte

Nous avions besoin d'améliorer les performances des requêtes fréquentes.

Décision

Nous utilisons Redis uniquement pour le cache de performance, pas pour la gestion de sessions.

Pourquoi

  • Amélioration ~40x sur les endpoints dashboard (15-20s → 20-50ms)
  • JWT est stateless, pas besoin de sessions serveur
  • TTL configurable (3-10 min selon endpoint)
  • Fallback automatique vers Supabase si Redis unavailable

Alternatives rejetées

  • Sessions serveur : Incompatible avec notre architecture stateless JWT.
  • Memcached : Moins de fonctionnalités que Redis.

Conséquences

  • Pas de révocation de tokens possible (voir lacunes dans security-policy.md).

ADR-005 : Multi-repo (5 repos)

Date : 2026-02-21 Statut : Accepté

Contexte

Nous avons 3 applications frontend différentes + 1 backend + 1 doc.

Décision

Nous utilisons 5 repos GitHub séparés.

Pourquoi

  • Déploiement indépendant de chaque application
  • Équipes peuvent travailler séparément sur chaque frontend
  • CI/CD simplifié par projet

Alternatives rejetées

  • Monorepo : Plus complexe à configurer, deployments plus longs.

Conséquences

  • Nous devons maintenir des versions cohérentes entre les repos.
  • Le code partagé est dupliqué ou extrait dans des packages.

ADR-006 : Vercel (frontends) + Dokploy (backend)

Date : 2026-02-21 Statut : Accepté

Contexte

Nous avions besoin d'hébergement pour nos applications. Nous voulions une solution flexible et économique pour le backend.

Décision

  • Vercel : Pour les 3 frontends Next.js (Discover, Career, Admin)
  • Dokploy : Pour le backend FastAPI (sur notre propre VPS)
  • Cloudflare Pages : Pour la documentation Docusaurus

Pourquoi

  • Vercel : Optimisé pour Next.js, preview PRs automatiques, CDN global
  • Dokploy : Alternative auto-hébergée à Coolify/Railway, déployé sur notre VPS, contrôle total sur l'infrastructure
  • Cloudflare Pages : Hébergement gratuit pour sites statiques, protection via Cloudflare Access pour limiter l'accès

Alternatives rejetées

  • Railway : Solution cloud pratique mais nous avons privilégié l'auto-hébergement pour réduire les coûts.
  • Heroku : Plus cher, moins flexible.
  • Coolify : Alternative intéressante, Dokploy choisi pour sa simplicité.

Conséquences

  • Trois cibles d'hébergement distinctes : Vercel (frontends), Dokploy (backend), Cloudflare Pages (docs).
  • Nous gérons nous-mêmes le maintien à jour du serveur Dokploy (sécurité, mises à jour).
  • La documentation est protégée par Cloudflare Access — accès restreint aux utilisateurs autorisés.