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

188 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Feature Specification: Budget Tracker Core
**Feature Branch**: `003-budget-tracker-core`
**Created**: 2026-03-15
**Status**: Draft
**Input**: User description: "App web de suivi de budget personnel : suivi des revenus et dépenses, catégorisation, tableaux de bord, gestion de budgets par enveloppe, export CSV/PDF, historique mensuel, authentification utilisateur."
## User Scenarios & Testing *(mandatory)*
### User Story 1 - Saisie et consultation des transactions (Priority: P1)
En tant qu'utilisateur authentifié, je veux ajouter, modifier et supprimer des transactions (revenus ou dépenses) afin de maintenir un historique fidèle de mes mouvements financiers.
**Why this priority**: C'est le cœur fonctionnel de l'application. Sans la capacité d'enregistrer des transactions, aucune autre fonctionnalité (budget, graphiques, export) n'a de sens. Livrer uniquement cette story constitue déjà un journal financier minimaliste opérationnel.
**Independent Test**: Peut être testé indépendamment en ajoutant une transaction via le formulaire, en vérifiant son apparition dans la liste, puis en la modifiant et en la supprimant — sans aucune autre fonctionnalité active.
**Acceptance Scenarios**:
1. **Given** un utilisateur authentifié sur la page "Transactions", **When** il soumet le formulaire avec un montant (ex: 45,90 €), une date, un type "dépense" et une description, **Then** la transaction apparaît en tête de liste avec le bon montant, la bonne date et le bon type.
2. **Given** une transaction existante, **When** l'utilisateur clique sur "Modifier" et change le montant à 50,00 €, **Then** la liste affiche immédiatement le montant mis à jour et le solde courant est recalculé.
3. **Given** une transaction existante, **When** l'utilisateur clique sur "Supprimer" et confirme la suppression, **Then** la transaction disparaît de la liste et le solde est recalculé en conséquence ; la transaction reste présente en base (soft-delete) et n'est plus visible dans l'interface.
4. **Given** un formulaire de saisie, **When** l'utilisateur soumet sans montant ou avec un montant négatif, **Then** un message d'erreur explicite est affiché et aucune transaction n'est créée.
---
### User Story 2 - Tableau de bord avec solde et résumé mensuel (Priority: P2)
En tant qu'utilisateur authentifié, je veux voir en un coup d'œil mon solde courant, le total de mes revenus et dépenses du mois, ainsi qu'un graphique de répartition des dépenses par catégorie, afin de comprendre rapidement ma situation financière.
**Why this priority**: Le tableau de bord transforme les données brutes en information utile. Il constitue la page d'accueil naturelle de l'application et justifie la valeur perçue de l'outil dès la première visite. Dépend de P1 (transactions existantes) mais peut être rendu statique avec des données de seed.
**Independent Test**: Peut être testé indépendamment en pré-chargeant une base avec des transactions de test et en vérifiant que les KPIs et graphiques affichent des valeurs cohérentes avec les données injectées.
**Acceptance Scenarios**:
1. **Given** un utilisateur avec des transactions en mars 2026, **When** il accède au tableau de bord, **Then** il voit le solde courant (revenus dépenses depuis l'origine), le total des revenus du mois, le total des dépenses du mois et le solde net du mois.
2. **Given** un utilisateur avec des dépenses réparties sur 3 catégories, **When** il consulte le tableau de bord, **Then** un graphique en camembert ou en barres affiche la répartition des dépenses par catégorie pour le mois courant, avec les montants et pourcentages visibles au survol.
3. **Given** un utilisateur sans transaction ce mois-ci, **When** il consulte le tableau de bord, **Then** les KPIs affichent 0 € et le graphique affiche un état vide avec un message d'invitation à saisir des transactions.
4. **Given** un utilisateur sur le tableau de bord, **When** il navigue vers le mois précédent via les contrôles de navigation, **Then** tous les KPIs et graphiques se mettent à jour pour refléter la période sélectionnée.
---
### User Story 3 - Catégorisation des transactions (Priority: P3)
En tant qu'utilisateur authentifié, je veux assigner chaque transaction à une catégorie (alimentation, transport, loisirs, etc.) et gérer mes propres catégories personnalisées, afin d'analyser mes dépenses par poste.
**Why this priority**: La catégorisation enrichit les transactions et débloque les analyses (graphiques, budgets par enveloppe). Les catégories par défaut permettent un onboarding rapide ; la personnalisation répond aux besoins individuels. Dépend de P1.
**Independent Test**: Peut être testé indépendamment en créant une catégorie personnalisée, en l'assignant à une transaction, et en vérifiant que la transaction apparaît bien filtrée par cette catégorie.
**Acceptance Scenarios**:
1. **Given** un utilisateur sur la page "Catégories", **When** il crée une catégorie "Abonnements" avec une couleur et une icône, **Then** la catégorie est disponible dans le sélecteur lors de la création/modification d'une transaction.
2. **Given** une catégorie utilisée par au moins une transaction, **When** l'utilisateur tente de la supprimer, **Then** un avertissement l'informe que X transactions utilisent cette catégorie et lui propose de les réassigner avant suppression.
3. **Given** un utilisateur sur la liste des transactions, **When** il filtre par catégorie "Alimentation", **Then** seules les transactions de cette catégorie sont affichées, avec le total filtré visible.
4. **Given** un nouveau compte utilisateur, **When** il accède pour la première fois à l'application, **Then** un ensemble de catégories par défaut (Alimentation, Transport, Logement, Loisirs, Santé, Revenus) est déjà disponible.
---
### User Story 4 - Gestion des budgets par enveloppe (Priority: P4)
En tant qu'utilisateur authentifié, je veux définir un budget maximum mensuel par catégorie (ex : 300 € pour "Alimentation") et visualiser ma consommation en temps réel, afin de respecter mes objectifs de dépenses.
**Why this priority**: La gestion budgétaire est la fonctionnalité de pilotage financier. Elle différencie l'application d'un simple journal de comptes. Nécessite P1 et P3 pour être utile.
**Independent Test**: Peut être testé indépendamment en créant un budget pour une catégorie, en ajoutant des transactions dans cette catégorie et en vérifiant que la barre de progression reflète le bon taux de consommation.
**Acceptance Scenarios**:
1. **Given** un utilisateur sur la page "Budgets", **When** il crée un budget de 300 € pour la catégorie "Alimentation" pour mars 2026, **Then** une carte budget apparaît avec une barre de progression à 0 % et le plafond affiché.
2. **Given** un budget "Alimentation" de 300 € et 180 € de dépenses déjà enregistrées dans cette catégorie ce mois-ci, **When** l'utilisateur consulte la page "Budgets", **Then** la barre de progression indique 60 % (180/300 €), avec le montant restant affiché (120 €).
3. **Given** un budget dont les dépenses dépassent le plafond, **When** l'utilisateur consulte la page "Budgets", **Then** la barre de progression passe au rouge, le dépassement est affiché en négatif (ex : 30 €) et une alerte visuelle attire l'attention.
4. **Given** un budget défini pour mars 2026, **When** avril 2026 commence, **Then** le système crée automatiquement un nouveau budget pour avril avec le même plafond, ou invite l'utilisateur à reconduire ses budgets.
---
### User Story 5 - Historique mensuel navigable (Priority: P5)
En tant qu'utilisateur authentifié, je veux naviguer mois par mois dans mon historique de transactions, afin de retrouver et analyser mes dépenses passées.
**Why this priority**: La navigation temporelle est essentielle pour le suivi sur le long terme. Elle complète les fonctionnalités de base sans en être un prérequis. Dépend de P1.
**Independent Test**: Peut être testé indépendamment en naviguant vers un mois passé contenant des transactions seed et en vérifiant que seules les transactions de ce mois s'affichent avec les bons totaux.
**Acceptance Scenarios**:
1. **Given** un utilisateur sur la page "Transactions", **When** il clique sur "< Mois précédent", **Then** la liste affiche uniquement les transactions du mois précédent, avec le sélecteur de période mis à jour.
2. **Given** un utilisateur sur un mois passé, **When** il clique sur "Mois suivant" jusqu'au mois courant, **Then** les données du mois courant s'affichent correctement.
3. **Given** un utilisateur souhaitant aller à une date précise, **When** il sélectionne "Janvier 2025" dans le sélecteur de mois, **Then** la liste de transactions et les statistiques correspondantes s'affichent instantanément.
---
### User Story 6 - Export des données (Priority: P6)
En tant qu'utilisateur authentifié, je veux exporter mes transactions en CSV ou en PDF pour un mois donné ou pour toute la période, afin de les utiliser dans un tableur ou de les archiver.
**Why this priority**: L'export est une fonctionnalité de sortie de données sans dépendance critique sur les autres features. Elle répond à un besoin de portabilité et de conformité (déclaration fiscale, remboursements). Dépend de P1.
**Independent Test**: Peut être testé indépendamment en déclenchant un export CSV pour le mois courant et en vérifiant que le fichier téléchargé contient les colonnes et données attendues.
**Acceptance Scenarios**:
1. **Given** un utilisateur avec des transactions en mars 2026, **When** il clique sur "Exporter CSV" pour mars 2026, **Then** un fichier `transactions_2026-03.csv` est téléchargé avec les colonnes : date, description, catégorie, type, montant.
2. **Given** un utilisateur souhaitant un export PDF, **When** il clique sur "Exporter PDF" pour mars 2026, **Then** un fichier `rapport_2026-03.pdf` est généré avec le résumé mensuel (solde, totaux), le graphique de répartition et le détail des transactions.
3. **Given** un mois sans aucune transaction, **When** l'utilisateur tente un export, **Then** un message lui indique qu'il n'y a pas de données à exporter et aucun fichier n'est généré.
4. **Given** un export en cours, **When** le fichier dépasse 10 000 lignes, **Then** l'export est déclenché en tâche de fond et l'utilisateur est notifié (ou redirigé vers un lien de téléchargement) à la fin du traitement.
---
### User Story 7 - Authentification utilisateur (Priority: P7)
En tant qu'utilisateur, je veux créer un compte et me connecter de façon sécurisée, afin que mes données financières soient privées et isolées des autres utilisateurs.
**Why this priority**: L'authentification est un prérequis à l'isolation des données en mode multi-utilisateurs. En mode instance unique (un seul utilisateur), elle peut être différée. Placée en P7 car l'ensemble des fonctionnalités P1P6 peut être développé et testé avec un utilisateur fictif en seed.
**Independent Test**: Peut être testé indépendamment en créant un compte, en se déconnectant, en tentant d'accéder à une route protégée (redirection attendue vers login), puis en se reconnectant.
**Acceptance Scenarios**:
1. **Given** un visiteur non authentifié, **When** il accède à n'importe quelle route protégée, **Then** il est redirigé vers la page de connexion.
2. **Given** un formulaire d'inscription, **When** l'utilisateur saisit un email valide et un mot de passe d'au moins 8 caractères, **Then** son compte est créé, il est automatiquement connecté et redirigé vers le tableau de bord.
3. **Given** un utilisateur avec un compte existant, **When** il se connecte avec ses identifiants corrects, **Then** un token JWT est émis, stocké côté client, et il est redirigé vers le tableau de bord.
4. **Given** un utilisateur connecté, **When** son token expire ou qu'il clique sur "Déconnexion", **Then** le token est invalidé, la session est détruite et il est redirigé vers la page de connexion.
5. **Given** deux utilisateurs distincts avec leurs propres transactions, **When** chacun consulte son tableau de bord, **Then** aucun ne voit les données de l'autre.
---
### Edge Cases
- Que se passe-t-il si l'utilisateur saisit un montant avec plus de 2 décimales (ex : 10,999 €) ? → arrondi à 2 décimales côté API avant stockage en centimes.
- Comment le système gère-t-il un montant de 0 € ? → rejeté avec un message d'erreur (une transaction à 0 n'a pas de sens métier).
- Que se passe-t-il si l'utilisateur change la devise en cours de route ? → la devise est fixée par instance (paramètre de configuration), pas modifiable par transaction.
- Que se passe-t-il lors de la suppression d'un compte utilisateur ? → soft-delete du compte ; les données associées sont conservées 30 jours avant purge définitive.
- Comment le système gère-t-il une date de transaction dans le futur ? → autorisée (prévisionnel), affichée avec une mention "À venir" dans la liste.
- Que se passe-t-il si deux utilisateurs soumettent simultanément une modification sur la même transaction ? → la dernière écriture gagne (last-write-wins) ; la cohérence est garantie par les transactions ACID PostgreSQL.
- Que se passe-t-il si le budget d'une catégorie est supprimé alors que des transactions y sont rattachées ? → les transactions subsistent sans budget associé ; elles n'apparaissent plus dans la vue "Budgets" mais restent visibles dans "Transactions".
- Comment le système gère-t-il un export PDF avec plus de 500 transactions ? → génération asynchrone côté serveur avec lien de téléchargement différé.
- Que se passe-t-il si PostgreSQL est indisponible ? → l'API répond 503 Service Unavailable avec un message générique ; aucune donnée partielle n'est exposée.
## Requirements *(mandatory)*
### Functional Requirements
- **FR-001**: Le système DOIT permettre à un utilisateur authentifié de créer, lire, modifier et supprimer (soft-delete) des transactions financières.
- **FR-002**: Chaque transaction DOIT obligatoirement contenir : un montant (> 0), une date, un type (revenu ou dépense), et une catégorie.
- **FR-003**: Les montants DOIVENT être stockés en centimes (entiers) pour éviter les erreurs d'arrondi en virgule flottante.
- **FR-004**: Le système DOIT calculer et exposer le solde courant de l'utilisateur (somme des revenus somme des dépenses non supprimées depuis l'origine).
- **FR-005**: Le système DOIT permettre de filtrer les transactions par période (mois/année), par catégorie et par type.
- **FR-006**: Le système DOIT fournir un tableau de bord mensuel exposant : solde courant, total revenus du mois, total dépenses du mois, solde net du mois, répartition des dépenses par catégorie.
- **FR-007**: Le système DOIT permettre à un utilisateur de créer, modifier et supprimer des catégories personnalisées avec un nom, une couleur et une icône facultative.
- **FR-008**: Le système DOIT fournir un ensemble de catégories par défaut pré-chargées pour tout nouveau compte (Alimentation, Transport, Logement, Loisirs, Santé, Revenus).
- **FR-009**: La suppression d'une catégorie utilisée par des transactions DOIT être bloquée jusqu'à réassignation ou suppression des transactions associées.
- **FR-010**: Le système DOIT permettre de définir un budget maximum mensuel par catégorie (couple catégorie × mois).
- **FR-011**: Le système DOIT calculer en temps réel le taux de consommation de chaque budget (dépenses de la catégorie sur le mois / plafond défini).
- **FR-012**: Le système DOIT alerter visuellement l'utilisateur lorsqu'un budget est dépassé (taux > 100 %).
- **FR-013**: Le système DOIT permettre la navigation mensuelle dans l'historique des transactions et des budgets.
- **FR-014**: Le système DOIT permettre l'export des transactions d'une période donnée au format CSV avec les colonnes : date, description, catégorie, type, montant (en euros).
- **FR-015**: Le système DOIT permettre l'export d'un rapport mensuel au format PDF incluant le résumé financier, le graphique de répartition et le détail des transactions.
- **FR-016**: Le système DOIT gérer l'authentification des utilisateurs via email + mot de passe avec émission d'un token JWT.
- **FR-017**: Toutes les routes de l'API DOIVENT être protégées par authentification à l'exception des endpoints d'inscription et de connexion.
- **FR-018**: Les données de chaque utilisateur DOIVENT être strictement isolées : aucun utilisateur ne peut accéder aux données d'un autre.
- **FR-019**: Le système DOIT exposer une API REST documentée (OpenAPI/Swagger) pour l'ensemble des fonctionnalités.
- **FR-020**: Le système DOIT être déployable via `docker compose up` sans configuration manuelle au-delà du fichier `.env`.
### Key Entities
- **User** : Compte utilisateur. Attributs : `id`, `email`, `hashed_password`, `created_at`, `deleted_at`. Un utilisateur possède des transactions, des catégories et des budgets.
- **Transaction** : Mouvement financier unitaire. Attributs : `id`, `user_id`, `amount_cents` (entier), `type` (income | expense), `date`, `description`, `category_id`, `created_at`, `updated_at`, `deleted_at`.
- **Category** : Classification d'une transaction. Attributs : `id`, `user_id` (null pour les catégories système), `name`, `color`, `icon`, `created_at`, `deleted_at`. Une catégorie appartient à un utilisateur ou est une catégorie globale partagée.
- **Budget** : Enveloppe de dépense mensuelle par catégorie. Attributs : `id`, `user_id`, `category_id`, `month` (YYYY-MM), `limit_cents` (entier), `created_at`, `updated_at`. Relation : un budget est lié à une catégorie et à un mois calendaire.
- **ExportJob** *(optionnel — exports asynchrones larges)* : Traçabilité des exports générés. Attributs : `id`, `user_id`, `type` (csv | pdf), `period`, `status` (pending | done | error), `file_url`, `created_at`.
## Success Criteria *(mandatory)*
### Measurable Outcomes
- **SC-001**: Un utilisateur peut saisir une transaction complète (montant, date, catégorie, type, description) en moins de 30 secondes depuis la page principale.
- **SC-002**: Le tableau de bord se charge et affiche des données à jour en moins de 2 secondes pour un compte comportant jusqu'à 10 000 transactions.
- **SC-003**: 100 % des calculs de solde, totaux et taux de consommation de budget sont couverts par des tests unitaires passants.
- **SC-004**: La couverture de tests sur le dossier `services/` (logique métier backend) est supérieure ou égale à 80 %.
- **SC-005**: L'ensemble de l'application (backend + frontend + base de données) démarre correctement via `docker compose up` en moins de 5 minutes sur une machine vierge disposant de Docker.
- **SC-006**: Tous les endpoints API répondent avec les codes HTTP corrects (200/201 pour les succès, 400/422 pour les erreurs de validation, 401 pour les accès non authentifiés, 404 pour les ressources introuvables) — vérifiable via les tests d'intégration.
- **SC-007**: Un export CSV pour un mois contenant jusqu'à 1 000 transactions se génère et se télécharge en moins de 5 secondes.
- **SC-008**: Zéro donnée d'un utilisateur A n'est accessible depuis le compte d'un utilisateur B, vérifié par des tests d'intégration dédiés à l'isolation.
- **SC-009**: Le tableau de bord affiche un graphique de répartition des dépenses par catégorie lisible pour 1 à 15 catégories distinctes.
- **SC-010**: L'interface est utilisable sur desktop (≥ 1280 px) et sur mobile (≥ 375 px) sans défilement horizontal ni éléments tronqués sur les vues principales (tableau de bord, transactions, budgets).