Projet Niv. 4 — Dépenses
Le brief : le tracker de dépenses personnel — saisie en 3 secondes, catégories, budgets mensuels, graphiques, export CSV. Le projet DATA : votre SQL passe au niveau supérieur, et Drizzle entre en scène (le verdict du ch. 8.4 appliqué).
Ce que vous allez pratiquer
Le schéma multi-tables avec Drizzle (comptes, catégories, transactions, budgets — le seuil du ch. 8.4 est franchi), les agrégats sérieux (par mois, par catégorie, vs budget), victory-native pour les graphiques, l’export CSV (ch. 9.5), et le pavé numérique custom. Chapitres liés : 8.4, 8.3, 9.5, 4.5.
Les features
- La saisie éclair : ouvrir → pavé numérique custom → montant → catégorie (grille d’emojis) → fait. 3 secondes, PAS de formulaire.
- Catégories (CRUD, emoji, couleur) et comptes (espèces/carte — simple).
- Le mois en cours : total, par catégorie, la jauge vs budget (ProgressBar du kit !).
- Les graphiques : barres des 6 derniers mois, donut par catégorie (victory-native).
- Budgets mensuels par catégorie, avec l’alerte de dépassement (notification locale).
- Export CSV du mois/de l’année (fichier + share sheet).
L’architecture recommandée
- Drizzle d’entrée (la grille du ch. 8.4 : 4+ tables, schéma évolutif → l’ORM gagne) :
// db/schema.ts — l'esquisse
categories: { id, name, emoji, color }
accounts: { id, name }
transactions: { id, amountCents, categoryId, accountId, note?, spentAt } // ← CENTIMES
budgets: { id, categoryId, monthKey /* '2026-07' */, limitCents }Les centimes en INTEGER — la règle d’or de l’argent (jamais de flottants : 0.1+0.2 ≠
0.3 ; l’affichage divise par 100 au dernier moment, dans une fonction formatEuros de
lib/).
- Les requêtes du dashboard :
GROUP BY strftime('%Y-%m', …)pour les mois, la jointure budgets↔dépenses du mois (LEFT JOIN — les catégories sans budget existent), et lemonthKeytextuel qui esquive les pièges de fuseaux (le pattern du jour local, généralisé au mois). - Le pavé numérique custom : une grille de Pressable du kit (les claviers système sont trop lents pour la « saisie éclair ») — votre premier composant d’input original.
- victory-native (XL, sur Skia) pour les deux graphiques — l’occasion d’évaluer une lib selon les critères du ch. 1.4 avant adoption.
Les jalons
- Schéma Drizzle + migrations générées + seed de démo (3 mois de données réalistes).
- La saisie éclair (pavé + grille de catégories) — chronométrez-la réellement.
- Le dashboard du mois (agrégats + jauges budgets).
- Les graphiques (6 mois + donut).
- Budgets + l’alerte de dépassement (déclenchée À LA SAISIE qui dépasse).
- Export CSV + share + APK.
Critères de réussite
- La saisie d’une dépense prend < 5 s montre en main (le critère produit n°1)
- 5 000 transactions seedées : dashboard et graphiques instantanés (agrégats en SQL, pas en JS)
- 12,34 € + 45,67 € = 58,01 € EXACTEMENT (centimes entiers, pas de 58.009999)
- Le CSV s’ouvre proprement dans un tableur (séparateur, encodage UTF-8 BOM pour Excel, montants avec virgule locale — les VRAIS détails d’un export)
- Le mois bascule correctement le 1er (monthKey local)
- APK + VOS dépenses réelles pendant un mois
Pièges connus
- Le CSV français : Excel attend
;comme séparateur et une virgule décimale — l’option « séparateur » dans l’écran d’export est le vrai réglage utile (et le BOM UTF-8 pour les accents). - Le donut « autres » : au-delà de 6 catégories, regroupez — un donut à 14 tranches est illisible (le design de données fait partie du projet).
- L’alerte budget : à la SAISIE (synchrone, fiable), pas par vérification périodique en arrière-plan (complexité sans bénéfice — Android limite le background de toute façon).
💡 L’upgrade : les transactions récurrentes (loyer le 1er — un champ recurrence + la matérialisation au premier lancement du mois : un vrai problème de conception), et le widget de saisie sur l’écran d’accueil (module natif — le boss final du hors-SDK).