Skip to content

Architecture Decision Records

Contexte

Le projet "Gamers ERP" nécessite une API robuste pour gérer des utilisateurs, des abonnements, et des exports comptables/bancaires. L'application doit être maintenable, testable, et supporter potentiellement plusieurs types de bases de données (dev/prod). Il est nécessaire de définir une stratégie claire pour l'exposition de l'API, la sécurité, et l'accès aux données.

Décisions

1. Approche "Contract-First" avec OpenAPI

Nous utilisons la spécification OpenAPI (openapi.yaml) comme source unique de vérité pour notre API.

  • Pourquoi : garantit que la documentation est toujours à jour avec le code.
  • Implémentation : génération automatique du routeur Express et des types TypeScript via @nahkies/openapi-code-generator.
  • Validation : la validation des entrées (Schema Validation) est déléguée aux validateurs générés (Zod).

2. Architecture en couches et organisation des handlers

Nous adoptons une architecture en couches pour séparer les responsabilités. Les handlers sont organisés par niveau d'accès :

  • API Layer (/api) : définition des contrats et routage.
  • Handler Layer (/src/handler) : orchestration des requêtes HTTP.
  • S'occupe du parsing, de la validation HTTP et du formatage de la réponse.
  • Délégué la logique métier au Service Layer.
  • /public : routes ouvertes (ex: création de compte).
  • /authenticated : routes nécessitant une connexion simple.
  • /admin : routes réservées aux administrateurs.
  • Service Layer (/src/service) : Contient la logique métier pure (Business Logic).
  • Orchestre les opérations complexes.
  • Utilise les repositories pour l'accès aux données.
  • Indépendant du framework HTTP (Express).
  • Middleware Layer (/src/middleware) : fonctions transverses (Auth, Logs, Securité des routes).
  • Repository Layer (/src/repository) : abstraction de l'accès aux données.
  • Database Layer (/src/database) : implémentations concrètes (Drizzle ORM).

3. Stratégie d'authentification : Bearer JWT

Nous utilisons des JSON Web Tokens (JWT) transmis via l'en-tête Authorization: Bearer.

  • Pourquoi :
  • Stateless : le serveur ne stocke pas de session en mémoire, idéal pour la scalabilité.
  • Standard : compatible avec tout type de client (Web, mobile, tiers).
  • Sécurité :
  • les mots de passe sont hachés avec bcrypt avant stockage.
  • les mots de passe ne sont jamais renvoyés dans les réponses API.

4. Abstraction de la base de données

Nous utilisons le pattern Repository pour découpler la logique métier de la base de données. Les Services utilisent ces repositories pour accéder aux données.

  • Interface : UserRepository, SubscriptionRepository, etc.
  • Implémentations :
  • InMemory...Repository : pour les tests et le développement local (SQLite en mémoire).
  • Postgres...Repository : pour la production (PostgreSQL via Drizzle ORM).

5. Sécurité centralisée des routes

La gestion des droits d'accès est centralisée dans un middleware de sécurité piloté par une configuration (src/config/routes.config.ts).

  • Pourquoi : éviter d'éparpiller les vérifications if (user.isAdmin) dans chaque handler.
  • Implémentation : le middleware secureRouteMiddleware intercepte chaque requête, consulte ROUTE_RULES pour déterminer le niveau d'accès requis (public, authenticated, admin), et valide le token JWT en conséquence.

Bénéfices

  • Tests facilités par l'injection de dépendances.
  • Logique métier protégée des détails d'implémentation HTTP ou SQL.
  • Documentation API claire et interactive (Swagger UI) disponible par défaut.

Points de vigilance

  • Légère complexité ajoutée par l'étape de génération de code (npm run generate).
  • Nécessité de maintenir la synchro entre openapi.yaml et le code (le build échoue si désynchronisé, ce qui est une sécurité).