You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
-[VIJ-24](https://linear.app/vijaypmworkspace/issue/VIJ-24/moneymirror-ops-run-neon-alter-for-statement-label-columns-nickname) — **Todo** — run Neon `ALTER TABLE` for label columns if missing (`apps/money-mirror/schema.sql`).
**Repo:**[experiments/linear-sync/issue-009.json](experiments/linear-sync/issue-009.json) — `tasks` map + `last_sync_mode` updated for manual Phase 2 issue creation (not a full `/linear-sync` pipeline run).
14
+
15
+
**Update (same day):** Full **Sprint 1–3** (VIJ-26–28, Done), **Sprint 4 / Backlog** (VIJ-25), **Epics A–H** (VIJ-29–36, Done) created in Linear and mirrored in [project-state.md](project-state.md) § MoneyMirror PM roadmap — Linear map.
MoneyMirror is a mobile-first PWA AI financial coach for Gen Z Indians (₹20K–₹80K/month). Users sign in with Neon Auth email OTP, upload a password-free Indian bank-account or credit-card statement PDF, and Gemini 2.5 Flash parses and categorizes each transaction into needs/wants/investment/debt/other. The "Mirror moment" reveals the gap between self-reported spend from onboarding and actual spend from the statement. An advisory engine fires up to 5 consequence-first nudges, and a weekly recap email is sent by a Vercel cron fan-out every Monday at 8:00 AM IST. The primary North Star proxy is second-month statement upload rate (≥60%).
-**Frontend**: Next.js 16 App Router (RSC by default, `"use client"` for interactive panels). Key pages: `/` (landing), `/onboarding` (5-question flow), `/score` (Money Health Score reveal), `/dashboard` (Overview with perceived vs actual + categories, **Insights** tab for AI nudges, **Upload** tab, statement picker + month filter, URL `?statement_id=`).
12
12
-**Backend**: Next.js API routes under `src/app/api/`. Neon Auth for session auth, Neon Postgres for persistence, Gemini 2.5 Flash for PDF parse + categorization, Resend for weekly recap emails, PostHog for server-side telemetry.
13
-
-**Database**: Neon Postgres. 4 tables: `profiles`, `statements`, `transactions`, `advisory_feed`. `profiles` persists monthly income and perceived spend; `statements`now tracks `institution_name`, `statement_type`, and optional credit-card due metadata. All monetary values are stored as `BIGINT` in paisa (₹ × 100) to avoid float precision errors.
13
+
-**Database**: Neon Postgres. 4 tables: `profiles`, `statements`, `transactions`, `advisory_feed`. `profiles` persists monthly income and perceived spend; `statements` tracks `institution_name`, `statement_type`, optional credit-card due metadata, optional `nickname`, `account_purpose`, `card_network` for multi-account labelling. All monetary values are stored as `BIGINT` in paisa (₹ × 100) to avoid float precision errors.
14
14
-**AI Integration**: Gemini 2.5 Flash via `@google/genai`. Used for: (1) PDF text → structured bank-account or credit-card statement JSON, (2) transaction category normalization. The statement-parse route currently enforces a 25s timeout and returns JSON 504 on timeout.
-**Error tracking**: Sentry via `@sentry/nextjs` (`sentry.server.config.ts`, `sentry.edge.config.ts`, `src/instrumentation.ts`, `src/instrumentation-client.ts`). Uses `NEXT_PUBLIC_SENTRY_DSN` plus org/project/auth token vars as in app `README.md` / `.env.local.example`.
16
17
17
18
## Key Files
18
19
@@ -24,7 +25,9 @@ MoneyMirror is a mobile-first PWA AI financial coach for Gen Z Indians (₹20K
24
25
|`src/app/api/dashboard/advisories/route.ts`| Authenticated GET — returns advisory_feed rows for the current user via the active Neon session cookie. |
25
26
|`src/app/api/cron/weekly-recap/route.ts`| Master cron: scheduled GET entrypoint for Vercel Cron; accepts Bearer `CRON_SECRET` or local `x-cron-secret`, paginates users in 1000-row batches, and fans out to the worker via Promise.allSettled. |
26
27
|`src/app/api/cron/weekly-recap/worker/route.ts`| Worker: sends Resend email per user. Returns HTTP 502 on failure so master counts it correctly. |
27
-
|`src/lib/advisory-engine.ts`| Fires 5 advisory types based on spend ratios and thresholds. Writes to `advisory_feed` table. |
28
+
|`src/lib/advisory-engine.ts`| Rule-based advisories (perception gap, subscriptions, food, no investment, debt ratio, high Other bucket, discretionary mix, avoidable estimate, CC minimum-due risk). |
29
+
|`src/lib/format-date.ts`| UTC-safe date labels for statement periods (no raw ISO in UI). |
30
+
|`src/app/api/statements/route.ts`| Authenticated GET — list processed statements for picker + month filter. |
28
31
|`src/lib/scoring.ts`| Computes Money Health Score (0–100) from 5 onboarding question responses. |
29
32
|`src/lib/statements.ts`| Defines statement types, parser prompts, metadata validation, and shared display labels for bank-account and credit-card uploads. |
30
33
|`src/lib/pdf-parser.ts`| Extracts raw text from PDF buffer using `pdf-parse`. Uses `result.total` (not `result.pages?.length`) for page count — v2 API. |
@@ -33,21 +36,22 @@ MoneyMirror is a mobile-first PWA AI financial coach for Gen Z Indians (₹20K
33
36
## Data Model
34
37
35
38
-**profiles**: One row per user. `id` = Neon Auth user id (TEXT). Stores `monthly_income_paisa`, `perceived_spend_paisa`, `target_savings_rate`, `money_health_score`.
36
-
-**statements**: One per uploaded PDF. Tracks `institution_name`, `statement_type` (`bank_account` or `credit_card`), statement period, optional card due metadata, and `status`. Status never set to `processed` before `transactions` child insert succeeds.
39
+
-**statements**: One per uploaded PDF. Tracks `institution_name`, `statement_type` (`bank_account` or `credit_card`), statement period, optional card due metadata, optional `nickname` / `account_purpose` / `card_network`, and `status`. Status never set to `processed` before `transactions` child insert succeeds.
37
40
-**transactions**: Many per statement. All amounts in paisa (BIGINT). `category` CHECK: `needs | wants | investment | debt | other` (lowercase).
38
41
-**advisory_feed**: Advisory nudges generated per statement. `trigger` identifies which advisory type fired.
| POST |`/api/statement/parse`| Neon session cookie | Upload PDF plus `statement_type` and optional `nickname`, `account_purpose`, `card_network`|
48
+
| GET |`/api/dashboard`| Neon session cookie | Rehydrate processed statement + advisories; optional `?statement_id=` for a specific upload |
49
+
| GET |`/api/statements`| Neon session cookie | List all processed statements for the user |
50
+
| GET |`/api/dashboard/advisories`| Neon session cookie | Fetch advisory_feed rows for user |
51
+
| POST |`/api/onboarding/complete`| Neon session cookie | Save onboarding income, score, and perceived spend to profiles |
52
+
| GET |`/api/cron/weekly-recap`|`authorization: Bearer <CRON_SECRET>` or local `x-cron-secret`| Scheduled master fan-out |
53
+
| POST |`/api/cron/weekly-recap/worker`|`x-cron-secret` header | Worker: send one recap email; returns 502 on failure |
54
+
| ALL |`/api/auth/[...path]`| — | Neon Auth passthrough |
51
55
52
56
## Things NOT to Change Without Reading First
53
57
@@ -61,11 +65,11 @@ MoneyMirror is a mobile-first PWA AI financial coach for Gen Z Indians (₹20K
61
65
62
66
## Known Limitations
63
67
64
-
-Statement history browsing not yet implemented — dashboard always shows the latest processed statement. `GET /api/dashboard` accepts `?statement_id=` as a future extension point.
68
+
-Cross-month trend comparison and aggregated “all accounts” rollups are not implemented (single-statement view with picker only).
65
69
- Password removal stays manual outside the app. Password-protected PDFs are rejected with a clear retry message.
66
70
- Inbox ingestion from email is not implemented. Users must manually download the PDF and upload it.
67
71
- PDF parsing reliability depends on the PDF being text-based (not scanned/image). Scanned PDFs return 400.
68
72
- Rate limit for uploads is 3/day per user (in-memory, resets on server restart) — not durable across deployments.
69
73
- Weekly recap email only triggers if the user has at least one processed statement. New users without statements are silently skipped.
70
74
- Share button (`navigator.share`) is hidden on desktop browsers — only rendered when Web Share API is available.
71
-
-Current automated validation count is 45 tests across route and library coverage.
75
+
-Run `npm test` in `apps/money-mirror` for current library and API test counts.
Run the full contents of [`schema.sql`](/Users/vijaysehgal/Downloads/02-Portfolio/ai-product-os/apps/money-mirror/schema.sql) against your Neon database.
76
+
Run the full contents of [`schema.sql`](./schema.sql) against your Neon database.
74
77
75
78
Tables created:
76
79
@@ -170,7 +173,7 @@ Returns the advisory subset for the authenticated user and statement.
170
173
171
174
### `GET /api/cron/weekly-recap`
172
175
173
-
Fan-out master route that finds all users with processed statements and triggers worker jobs. This is the scheduled entrypoint configured in [`vercel.json`](/Users/vijaysehgal/Downloads/02-Portfolio/ai-product-os/apps/money-mirror/vercel.json).
176
+
Fan-out master route that finds all users with processed statements and triggers worker jobs. This is the scheduled entrypoint configured in [`vercel.json`](./vercel.json).
174
177
175
178
**Auth**: `authorization: Bearer <CRON_SECRET>` from Vercel Cron. Local/manual triggering may also use `x-cron-secret: <CRON_SECRET>`.
0 commit comments