Commit Graph
15 Commits
Author SHA1 Message Date
jeremy bayseandClaude Sonnet 5 5352f39887 Make SuiviCPT an installable PWA
Adds what iOS/Android need to treat the site as an installable app
from Safari's "Add to Home Screen": a manifest.json, apple-touch-icon
set generated from the existing logo mark (scripts/generate-icons.mjs,
sharp as a dev dependency), and the apple-mobile-web-app-* meta tags
iOS Safari requires since it ignores manifest.json entirely.

The service worker is deliberately minimal — this app shows live
financial data, so navigations always hit the network first. It only
caches enough to serve offline.html when there's no connection, not a
full offline-first app shell.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-03 11:03:37 +02:00
jeremy bayseandClaude Sonnet 5 6a776b0042 Hide top nav on mobile, add "Plus" sheet to bottom tab bar
The top nav (logo + hamburger) was still sm:hidden-only on its inner
sections but the <nav> element itself had no breakpoint class, so it
kept rendering as an empty-looking bar above the new bottom tab bar.
Hide the whole element below sm and drop the now-dead hamburger/Alpine
toggle and its responsive menu, since nothing renders it anymore.

Account/settings links (Profile, Foyer, Catégories, Récurrences,
Log Out) that used to live in that hamburger now live in a "Plus"
slide-up sheet on the bottom tab bar. Logging out needed a real route
since the sheet isn't a Livewire component and can't call the
Volt navigation component's method directly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-02 11:23:24 +02:00
jeremy bayseandClaude Sonnet 5 d97cc41ee2 Add mobile bottom tab bar and redesign mobile dashboard
Import the Finlio Mobile design: a fixed bottom tab bar
(Accueil/Plan/Suivi/Flux) replaces the duplicated links in the mobile
hamburger menu, and the dashboard gets a mobile-first layout — hero
"reste à dépenser" card, revenus/épargne tiles, and a spending-by-
category list with progress bars — built from the same $sections data
the desktop tables use. Desktop dashboard is untouched.

The hero card uses a fixed dark background (independent of the
light/dark token swap) so its white text holds contrast in both
themes, matching how the existing -fill tokens are documented.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-02 11:16:44 +02:00
jeremy bayseandClaude Sonnet 5 a77be2dfba Fix intermittent chart rendering on dashboard and flux
window.Chart is set by app.js, a deferred module script whose
execution isn't ordered relative to Livewire's own script that fires
alpine:init. When Livewire won the race, Alpine's x-init called
new Chart() before window.Chart existed, silently failing with no
console output and leaving the canvas blank. Retry init() until
window.Chart is available instead of assuming it's ready.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-02 11:04:59 +02:00
jeremy bayseandClaude Sonnet 5 52ebb9bc83 Apply Finlio cream/terracotta design system
Re-theme dashboard, suivi, plan, and flux pages plus nav from the
claude.ai/design import: warm cream/terracotta/olive palette, pill
nav/buttons/inputs, Caprasimo display font for headings. Dark mode
variant derived to hold the existing WCAG AA contrast ratios since
the import only specified light.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-01 21:21:17 +02:00
jeremy bayseandClaude Sonnet 5 97dc7cdb2a Allow editing an existing transaction
Desktop reuses the add-form with a Modifier link per row; mobile gets
a "Dernières opérations" list under the quick-entry form since no
table exists there.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-01 08:37:50 +02:00
jeremy bayseandClaude Sonnet 5 9114bb2e8d Track who paid each depense, with a "Commun" (shared) fallback
Adds a "payé par" field to transactions and recurring transactions:
either a household member or null (shared/common expense). No per-
member account balances — this is purely a "who paid" label, the
household's overall balance is unchanged and unaffected by any
filtering.

- paid_by_user_id nullable FK on transactions and recurring_transactions
- Suivi: "payé par" selector on both entry forms (desktop dropdown,
  mobile buttons), a filter above the transaction table, a "payé par"
  column, and a summary tile showing this month's depenses grouped
  by payer (including Commun)
- Recurring transactions carry paid_by_user_id onto the transaction
  they generate when confirmed
- Running balance is computed from all transactions regardless of
  the payer filter, so it never gets skewed by the active filter

11 new Pest tests (assignment, common fallback, non-member rejection,
filter isolation from the balance calc, per-payer summary, recurring
propagation). 69/69 total pass, Pint clean, verified end-to-end on
production data (desktop + mobile, test row created and removed).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-01 08:24:14 +02:00
jeremy bayseandClaude Sonnet 5 5ef655d16f Add "reste à dépenser" tile to the dashboard
Shows the total remaining depense budget for the selected period,
above the breakdown table — reuses the totals.reste figure already
computed per section, no new query.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-26 13:41:48 +02:00
jeremy bayseandClaude Sonnet 5 1b3906ade2 Show remaining budget in mobile category buttons
Each category button now displays "X € restants" below the name,
alongside the existing progress gauge and percentage — so the user
sees both how much of the budget is used and how much is left
without leaving the entry form. Remaining is floored at 0 to match
the gauge's 100% cap.

categoryProgress now returns a ['pct', 'remaining'] pair per category
instead of a bare percentage; tests updated accordingly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-26 12:55:44 +02:00
jeremy bayseandClaude Sonnet 5 613220f43a Add budget progress gauge inside mobile category buttons
Each depense/epargne category button on the mobile quick-entry form
now shows a fill bar plus percentage of its monthly budget already
tracked, so the user sees at a glance which categories are close to
their limit while picking one. Categories without a budget defined
in Plan show no gauge (avoids a misleading 0%). Capped at 100% —
overspend detail already lives on the dashboard's "Manque" column.

3 new Pest tests for the percentage calculation (normal, capped,
no-budget cases). 61/61 tests pass, Pint clean, verified on mobile
against production data.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-26 12:48:29 +02:00
jeremy bayseandClaude Sonnet 5 5861fc49fc Replace Laravel scaffold logo with a finance-themed mark
The app still shipped the default Laravel cube icon. New mark is a
coin outline crossed by a rising trend line — ties the app's subject
(money) to its purpose (tracking growth over time). Stroke-based
single-color design inherits currentColor from the caller's text-*
class, so it drops into the existing light/dark tokens without a
separate variant.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-26 12:18:34 +02:00
jeremy bayseandClaude Sonnet 5 25363adde9 Trust reverse proxy headers to fix mixed-content asset URLs
Behind the prod TLS-terminating proxy, Laravel only saw the internal
HTTP hop and generated http:// URLs for Vite assets, which browsers
block as mixed content on an https:// page (suivicpt.trankil.net).

Configured trustProxies in bootstrap/app.php to honor X-Forwarded-*
headers, defaulting to trust any upstream (TRUSTED_PROXIES env var
to restrict to a specific IP if the app is ever reachable directly
over HTTP). .env.production reference updated with the real APP_URL
and the new TRUSTED_PROXIES setting.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-26 11:43:29 +02:00
jeremy bayseandClaude Sonnet 5 b78c314569 Add recurring transactions with monthly confirmation flow
New "Récurrences" section lets users define recurring depense/epargne
models (name, category, default amount, day of month). Nothing is
created automatically: from the day a recurrence is due, it appears
as a pending proposal in Suivi (desktop + mobile) with an editable
amount, so variable bills (electricity, etc.) can be adjusted before
confirming. Dismissing a proposal skips it for the current month
without creating a transaction, and it reappears the following month.

- recurring_transactions table (household/category scoped, active flag,
  last_generated_year/month to prevent duplicate generation)
- transactions.recurring_transaction_id nullable FK to trace origin
- RecurringTransactionPolicy mirrors CategoryPolicy tenant scoping
- 10 new Pest tests covering CRUD, tenant isolation, and the
  pending/confirm/dismiss lifecycle across month boundaries (travelTo)

58/58 tests pass, Pint clean, verified end-to-end against production
data (test recurrence created and cleaned up).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-26 09:10:16 +02:00
jeremy bayseandClaude Sonnet 5 674c43afea Upgrade Laravel 11 to 12 to patch CRLF injection CVE-2026-48019
The default email validation rule was vulnerable to CRLF injection
(GHSA-5vg9-5847-vvmq) in all 11.x releases with no backport available.
Upgraded to v12.64.0, the first patched line for this branch.

All 50 Pest tests pass unchanged, Pint clean, composer audit reports
no advisories. No application code changes needed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 22:55:49 +02:00
jeremy bayseandClaude Sonnet 5 d8dc57a5df Initial commit: SuiviCPT personal finance tracker
Laravel 11 + Livewire 3/Volt + Alpine.js + Tailwind app for household
budget planning, transaction tracking, and financial dashboards.

- Multi-tenant households with member invites
- Plan: monthly/yearly budget per category with overrides
- Suivi: transaction log with running balance (desktop + mobile quick-entry)
- Dashboard: budget vs tracked breakdown + Chart.js donuts
- Flux: Sankey diagram of income allocation
- WCAG 2.1 AA color tokens, dark mode, accessible tables/forms
- 50 Pest tests

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 22:39:42 +02:00