Skip to content

feat: dépenses récurrentes - #5

Merged
sylvainDNS merged 7 commits into
mainfrom
003-recurring-expenses
Sep 30, 2026
Merged

sylvainDNS merged 7 commits into
mainfrom
003-recurring-expenses

Conversation

@sylvainDNS

@sylvainDNS sylvainDNS commented Sep 27, 2026 •

Copy link
Copy Markdown
Owner

Résumé

Nouvelle notion de récurrence : on décrit une dépense une fois avec sa fréquence, et l'app ajoute toute seule une dépense ordinaire à chaque échéance. Version 0.3.0.

  • Création : case « Répéter cette dépense » dans le formulaire habituel (le formulaire est inchangé si elle n'est pas cochée). Fréquence Jour · Semaine · Mois · An, jour de la semaine ou du mois (le 1er, le 13…), résumé en direct de la règle et de la prochaine échéance. Pas de date de début dans le passé ; pas de date de fin.
  • Ajout automatique : Cron Trigger 5 23,5,11 * * * (23:05 UTC est toujours après minuit à Paris, 05:05 et 11:05 servent de relances). Une échéance manquée est rattrapée avec sa date d'origine ; jamais de doublon (index unique partiel + lot D1 transactionnel), une dépense générée supprimée n'est jamais recréée. Si l'échéance tombe le jour de la création, la dépense est ajoutée tout de suite.
  • Repérage : icône ↻ sur les dépenses générées, filtre « Récurrentes », carte repliable « Récurrences » au-dessus des filtres (état mémorisé par appareil), ligne « Récurrence » dans le détail d'une dépense.
  • Gestion : modifier (prochaines échéances seulement), désactiver / réactiver (sans rattrapage), supprimer (soft delete : les dépenses gardent leur icône et affichent « Récurrence supprimée »). Toute personne membre peut agir sur toute récurrence.
  • Pause « À revoir » : si la personne qui paie quitte le groupe (ou si le compte commun est désactivé), ou si plus personne ne participe, la récurrence est mise en pause sans rattrapage. Même chose pour un groupe archivé.
  • Répartition : une dépense générée est une dépense ordinaire (même moteur de parts, mêmes arrondis) ; la somme des soldes reste à 0.

Autres commits de la PR :

  • style(toasts) : Quiet Toast Rule (DESIGN.md + sidecar impeccable) : tous les toasts partagent une surface neutre, seule l'icône prend une couleur (succès et info en bleu, avertissement ambre, erreur rouge), les actions sont toujours bleues. Plus aucun toast vert : le vert reste réservé aux soldes.
  • SegmentedControl partagé : libellé accessible par item (« lun. » affiché, « lundi » lu), tailles compactes sm / xs pour tenir à 320 px, état désactivé.
  • docs(specs) : spec, design brief, plan, contrat API, quickstart et tâches dans specs/003-recurring-expenses/.

Migration

drizzle/migrations/0008_recurring_expenses.sql (additive) : tables recurring_expenses et recurring_expense_participants, colonnes nullables expenses.recurring_expense_id / recurrence_due_date et index unique partiel uq_expenses_recurrence_due.

Vérifications

  • pnpm test : 374 tests (calcul des dates, validation, planification de la tâche, invariant somme des soldes = 0, routes Hono via app.request(), composants)
  • tsc --noEmit et pnpm lint (aucune erreur, avertissements existants inchangés)
  • pnpm build et wrangler deploy --dry-run --env production (le worker exporte fetch et scheduled)
  • Détecteur impeccable : aucune remarque
  • Tâche programmée sur la D1 locale (wrangler dev --test-scheduled + /cdn-cgi/handler/scheduled) : rattrapage, idempotence, dépense supprimée non recréée, pause sautée
  • Cycle de vie complet via l'API réelle, soldes isValid et somme = 0
  • Parcours dans Chrome : 320 / 375 / 1280 px, clair et sombre, noms accessibles, retour du focus
  • Lecteur d'écran réel et prefers-reduced-motion non testés manuellement
  • Après déploiement : trigger 5 23,5,11 * * * visible dans le dashboard Workers et une ligne recurring_expenses.run dans les logs
  • Date de l'entrée 0.3.0 du changelog fixée au 2026-09-28

…ically

Recurrence model + migration 0008 (partial unique index one expense per échéance), shared calendar maths in src/lib/recurrence.ts (Europe/Paris), daily Cron Trigger 5 23,5,11 * * * with idempotent D1 batches, /recurring-expenses API (create/list/get/update/deactivate/reactivate/soft delete), UI: repeat block in the expense form, collapsible « Récurrences » card, recurrence detail, ↻ glyph, « Récurrentes » filter.
Every toast shares one neutral surface, only the icon takes a hue (success/info Steady Blue, warning amber, error red), actions always Steady Blue; rule recorded in DESIGN.md and the impeccable sidecar.
@github-actions

github-actions Bot commented Sep 27, 2026 •

Copy link
Copy Markdown

🚀 Preview deployed!

URL: https://42712059.faircount.pages.dev

- formatRecurrenceNote: replace the vague « Les mois plus courts… » with explicit per-day notes
  - Day 31: last day of the month for 30-day months and February
  - Day 30: 28 or 29 in February
  - Day 29 monthly and 29 February yearly: 28 February on non-leap years
- RecurrenceFields: frequency label « An » → « Année » (read as truncated)
- Update design brief and quickstart to match
…ions

- ExpenseForm, ExpenseDetail, RecurrenceDetail: dialog height capped to the viewport
- Header and action buttons stay fixed, the body scrolls
- ExpenseDetail actions row wraps, « Supprimer » no longer overflows at 320 px
@sylvainDNS
sylvainDNS force-pushed the 003-recurring-expenses branch from 03241f6 to 623a9c7 Compare September 30, 2026 16:16
@sylvainDNS
sylvainDNS merged commit 17105b5 into main Sep 30, 2026
2 checks passed
@sylvainDNS
sylvainDNS deleted the 003-recurring-expenses branch September 30, 2026 16:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant