Files
budget-tracker/.specify/memory/research.md
T

5.1 KiB

Recherche & Décisions Techniques — Budget Tracker

Authentification

  • Décision : JWT (tokens access 15min + refresh 7j) via python-jose + passlib[bcrypt]
  • Rationale : stateless, compatible SPA React, aucune session serveur à gérer, facile à dockeriser
  • Alternatives :
    • Session cookies (plus simple mais couplé au serveur, complexe en CORS)
    • OAuth2 externe / Keycloak (overkill pour usage personnel)
    • FastAPI-Users (bibliothèque haut niveau — ajoute de la magie, préférence pour la transparence)

Base de données

  • Décision : PostgreSQL 16
  • Rationale : ACID natif (critique pour données financières), types UUID, ENUM, support transactionnel, standard de l'industrie
  • Alternatives :
    • SQLite (suffisant en dev, mais limité en concurrence et types)
    • MySQL (moins bon support UUID/ENUM natif)

ORM & Migrations

  • Décision : SQLAlchemy 2.0 (mode async) + Alembic
  • Rationale : async natif pour FastAPI, migrations versionées et réversibles, mature et bien documenté
  • Alternatives :
    • Tortoise ORM (async natif mais moins mature, moins d'intégrations)
    • SQLModel (wrapper SQLAlchemy+Pydantic — moins de contrôle sur les modèles)
    • Prisma (Node.js uniquement)

Framework Backend

  • Décision : FastAPI 0.111+
  • Rationale : OpenAPI/Swagger auto-généré (conforme principe I de la Constitution), validation Pydantic intégrée, async natif, typage strict
  • Alternatives :
    • Django REST Framework (sync-first, plus lourd)
    • Flask (pas d'async natif, validation manuelle)

Framework Frontend

  • Décision : React 18 + TypeScript + Vite
  • Rationale : écosystème riche, SPA adaptée à une app de gestion, typage fort réduit les erreurs sur les montants financiers
  • Alternatives :
    • Next.js (SSR inutile pour usage authentifié perso)
    • Vue 3 (viable mais écosystème plus réduit)

Styling Frontend

  • Décision : Tailwind CSS 3 + shadcn/ui
  • Rationale : utilitaires CSS rapides, shadcn/ui fournit composants accessibles (formulaires, modales, tableaux) sans dépendance lourde
  • Alternatives :
    • MUI / Ant Design (plus lourds, style moins personnalisable)
    • CSS Modules (trop verbeux pour une SPA)

Graphiques Frontend

  • Décision : Recharts
  • Rationale : composants React purs (pas de D3 direct), bon support responsive, Tailwind-compatible, léger (~180 ko gzip)
  • Alternatives :
    • Chart.js + react-chartjs-2 (moins idiomatic React, state management externe)
    • Nivo (très complet mais plus lourd, over-engineering pour 2 types de graphiques)
    • Victory (moins maintenu)

Gestion d'état Frontend

  • Décision : TanStack Query (React Query) v5
  • Rationale : cache serveur, invalidation automatique après mutations (soldes recalculés), gestion loading/error intégrée — évite un store global Redux pour des données essentiellement serveur
  • Alternatives :
    • Redux Toolkit (overkill, état global inutile si les données viennent de l'API)
    • SWR (moins de fonctionnalités sur les mutations)
    • Zustand (utile pour état local UI uniquement, complémentaire)

Export CSV

  • Décision : module csv Python stdlib
  • Rationale : aucune dépendance additionnelle, suffisant pour colonnes tabulaires de transactions, streaming possible via StreamingResponse FastAPI
  • Alternatives :
    • pandas (overkill, dépendance lourde)

Export PDF

  • Décision : WeasyPrint
  • Rationale : rendu HTML→PDF côté serveur, templates Jinja2 réutilisables, CSS support correct, rendu fidèle
  • Alternatives :
    • ReportLab (API bas niveau, verbeux pour des tableaux)
    • pdfkit (dépendance système wkhtmltopdf, difficile à dockeriser)
    • Reportlab + xhtml2pdf (moins stable)

Stockage des montants

  • Décision : entiers en centimes (amount_cents INTEGER)
  • Rationale : conforme au principe II de la Constitution — élimine toute erreur d'arrondi IEEE 754 sur les opérations financières (ex : 0.1 + 0.2 ≠ 0.3 en float)
  • Règle : la conversion euros↔centimes se fait uniquement aux frontières (serialisation Pydantic et affichage React)

Soft Delete

  • Décision : champ deleted_at TIMESTAMP NULL sur Transaction et Category
  • Rationale : conforme au principe II (tracabilité historique), permet l'audit et la restauration éventuelle
  • Implémentation : filtre WHERE deleted_at IS NULL systématique dans les requêtes ; index partiel recommandé

Conteneurisation

  • Décision : Docker Compose (backend + frontend + PostgreSQL)
  • Rationale : conforme au principe V de la Constitution, reproductibilité dev/prod, un seul docker compose up
  • Structure :
    • backend/ — image Python 3.12-slim
    • frontend/ — build Vite servi par Nginx
    • db/ — PostgreSQL 16 officiel

Tests Backend

  • Décision : pytest + httpx (client async) + pytest-asyncio + base de données de test dédiée
  • Rationale : conforme au principe III (80% coverage services/), tests d'intégration sur vraie BDD (pas de mock SQLAlchemy)
  • Alternatives :
    • unittest (moins expressif)
    • mocks SQLAlchemy (rejeté — risque de divergence mock/prod)