Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,37 @@
# Changelog

## 2026-04-06 — MoneyMirror: E2E documentation pass, `CODEBASE-CONTEXT` refresh, verification

**App:** `apps/money-mirror`

**What:** Refreshed [`apps/money-mirror/CODEBASE-CONTEXT.md`](apps/money-mirror/CODEBASE-CONTEXT.md) for post–issue-010 hardening: idempotent schema upgrades (`src/lib/schema-upgrades.ts`, `scripts/apply-schema-upgrades.ts`), boot-time DDL (`src/lib/run-schema-upgrade-on-boot.ts`, `src/instrumentation.ts`), Postgres error helpers (`src/lib/pg-errors.ts`) and `SCHEMA_DRIFT` JSON responses, `WebVitalsReporter`, Playwright (`playwright.config.ts`, `e2e/`). README **Docs** section links [`docs/PERFORMANCE-REVIEW.md`](apps/money-mirror/docs/PERFORMANCE-REVIEW.md) and [`docs/SCHEMA-DRIFT.md`](apps/money-mirror/docs/SCHEMA-DRIFT.md).

**Verification (local):** `npm run lint`, `npm run test` (81/81), `npx playwright install chromium`, `npm run test:e2e` (2/2, from `apps/money-mirror`); `npm run check:all` (repo root); `npm run db:upgrade` (success — Neon via `.env.local`).

**Learnings / corrections:** (1) **`db:upgrade` script shape** — an initial version used top-level `await`, which breaks `tsx`/`esbuild` execution; wrapping the script in `main()` fixed `npm run db:upgrade` (see earlier 2026-04-06 changelog entry). (2) **Schema drift vs “app bug”** — Neon DBs created before Phase 3 columns can throw Postgres `42703` (undefined column); API routes return `code: SCHEMA_DRIFT` with `SCHEMA_UPGRADE_HINT` so operators run `npm run db:upgrade` or rely on auto DDL on server boot (unless `MONEYMIRROR_SKIP_AUTO_SCHEMA=1`). (3) **No PM-pasted mistake list in this session** — additional bullets can be appended to `project-state.md` Decisions Log under the same date if needed.

---

## 2026-04-06 — MoneyMirror: `db:upgrade` + schema drift API hints

**App:** `apps/money-mirror`

**What:** Idempotent `npm run db:upgrade` (`scripts/apply-schema-upgrades.ts`, shared `applyIdempotentSchemaUpgrades` in `src/lib/schema-upgrades.ts`) adds `merchant_key` + partial index and statement label columns when missing. `GET /api/transactions` and `GET /api/insights/merchants` return `code: SCHEMA_DRIFT` with upgrade instructions on Postgres undefined-column errors; Transactions tab and `MerchantRollups` surface `detail` for that code. Dev dependency: `tsx`.

**Follow-up:** `runAutoSchemaUpgradeOnBoot` (`src/lib/run-schema-upgrade-on-boot.ts`) runs the same DDL from `instrumentation.ts` on Node server start when `DATABASE_URL` is set (opt out with `MONEYMIRROR_SKIP_AUTO_SCHEMA=1`). UI shows a single PM-friendly paragraph for `SCHEMA_DRIFT` (no duplicated title + hint). **Docs:** `docs/SCHEMA-DRIFT.md` (RCA + local verification).

**Fix:** `scripts/apply-schema-upgrades.ts` — wrap in `main()` (no top-level `await`) so `tsx`/`esbuild` can run `npm run db:upgrade`.

---

## 2026-04-06 — MoneyMirror: perf hardening, E2E smoke, launch checklist (post–issue-010)

**App:** `apps/money-mirror`

**What:** `next/font` (Inter + Space Grotesk); `WebVitalsReporter` + optional `NEXT_PUBLIC_POSTHOG_*`; viewport `maximumScale: 5`; Playwright smoke (`e2e/`, `test:e2e`); lazy Gemini on Insights (`/api/dashboard` fast path); scope-keyed dashboard refetch; dev-only transaction 500 `detail`; `dev:loopback` + README note for `uv_interface_addresses` dev noise. Docs: `docs/PERFORMANCE-REVIEW.md`, `experiments/results/production-launch-checklist-010.md`. **Linear:** ops follow-up comment on **VIJ-37** (does not reopen pipeline).

---

## 2026-04-05 — MoneyMirror Phase 3 T4 (VIJ-41): facts-grounded AI coaching

**App:** `apps/money-mirror`
Expand Down
4 changes: 4 additions & 0 deletions apps/money-mirror/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,7 @@ next-env.d.ts

# Sentry Config File
.env.sentry-build-plugin

# Lighthouse (generated locally; see docs/PERFORMANCE-REVIEW.md)
/docs/lighthouse-report.report.html
/docs/lighthouse-report.report.json
46 changes: 27 additions & 19 deletions apps/money-mirror/CODEBASE-CONTEXT.md

Large diffs are not rendered by default.

66 changes: 48 additions & 18 deletions apps/money-mirror/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,22 +51,25 @@ cp .env.local.example .env.local

Fill in these values:

| Variable | Required | Description |
| ------------------------- | -------- | ------------------------------------------------------------------- |
| `DATABASE_URL` | Yes | Neon Postgres connection string |
| `NEON_AUTH_BASE_URL` | Yes | Base URL for your Neon Auth project |
| `NEON_AUTH_COOKIE_SECRET` | No | Optional only if Neon explicitly gives one for your project/runtime |
| `GEMINI_API_KEY` | Yes | Google AI Studio API key |
| `RESEND_API_KEY` | Yes | Resend API key |
| `POSTHOG_KEY` | Yes | Server-side PostHog key |
| `POSTHOG_HOST` | Yes | PostHog host URL |
| `NEXT_PUBLIC_APP_URL` | Yes | Public app URL used in recap links |
| `CRON_SECRET` | Yes | Shared secret for cron routes |
| `NEXT_PUBLIC_SENTRY_DSN` | No | Client Sentry DSN — optional locally if you skip browser reporting |
| `SENTRY_AUTH_TOKEN` | Yes\* | \*Required for production builds that upload source maps to Sentry |
| `SENTRY_ORG` | No | Optional locally — used by Sentry CLI / webpack plugin for releases |
| `SENTRY_PROJECT` | No | Optional locally — same as above |
| `CI` | No | Optional CI build flag |
| Variable | Required | Description |
| ------------------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `DATABASE_URL` | Yes | Neon Postgres connection string |
| `NEON_AUTH_BASE_URL` | Yes | Base URL for your Neon Auth project |
| `NEON_AUTH_COOKIE_SECRET` | No | Optional only if Neon explicitly gives one for your project/runtime |
| `GEMINI_API_KEY` | Yes | Google AI Studio API key |
| `RESEND_API_KEY` | Yes | Resend API key |
| `POSTHOG_KEY` | Yes | Server-side PostHog key |
| `POSTHOG_HOST` | Yes | PostHog host URL |
| `NEXT_PUBLIC_POSTHOG_KEY` | No | Same key as `POSTHOG_KEY` — enables client `web_vital` (CWV) events |
| `NEXT_PUBLIC_POSTHOG_HOST` | No | Defaults to `https://app.posthog.com` if unset |
| `NEXT_PUBLIC_APP_URL` | Yes | Public app URL used in recap links |
| `CRON_SECRET` | Yes | Shared secret for cron routes |
| `NEXT_PUBLIC_SENTRY_DSN` | No | Client Sentry DSN — optional locally if you skip browser reporting |
| `SENTRY_AUTH_TOKEN` | Yes\* | \*Required for production builds that upload source maps to Sentry |
| `SENTRY_ORG` | No | Optional locally — used by Sentry CLI / webpack plugin for releases |
| `SENTRY_PROJECT` | No | Optional locally — same as above |
| `CI` | No | Optional CI build flag |
| `MONEYMIRROR_SKIP_AUTO_SCHEMA` | No | Set to `1` to skip automatic idempotent DDL on server boot (`instrumentation.ts`); default is to run when `DATABASE_URL` is set |

### 3. Create Neon project and enable Neon Auth

Expand All @@ -81,6 +84,18 @@ Fill in these values:

Run the full contents of [`schema.sql`](./schema.sql) against your Neon database.

**Already have a DB from before Phase 2 / Phase 3?** Your `transactions` table may be missing `merchant_key` (and related indexes), which breaks the Transactions tab and merchant insights. From this app directory, with `DATABASE_URL` in `.env.local`:

```bash
npm run db:upgrade
```

That runs idempotent `ALTER TABLE … ADD COLUMN IF NOT EXISTS` and `CREATE INDEX IF NOT EXISTS` statements (same as the tail of `schema.sql`). Safe to run multiple times.

**Automatic upgrades on server start:** When the Node server boots (`next dev` / `next start` / Vercel), MoneyMirror runs the same idempotent DDL once if `DATABASE_URL` is set and `MONEYMIRROR_SKIP_AUTO_SCHEMA` is not `1`. After pulling new code, **restart the dev server** so this runs; you usually do not need a separate migration step for missing `merchant_key` on Neon.

Full **root cause, verification steps, and opt-out** for schema drift: [`docs/SCHEMA-DRIFT.md`](./docs/SCHEMA-DRIFT.md).

Tables created:

- `profiles`
Expand Down Expand Up @@ -118,6 +133,19 @@ First-run failure looks like:
- `Error: DATABASE_URL is required.`
- `Error: NEON_AUTH_BASE_URL is required`

**Dev server: `uv_interface_addresses` / `getNetworkHosts` warning** — In some restricted environments Next may log an unhandled rejection while resolving the LAN URL; the app often still serves on `http://localhost:3000`. Use `npm run dev:loopback` to bind only to `127.0.0.1` and avoid that code path, or run the dev server outside a sandbox.

## Testing

| Command | What it runs |
| ------------------ | -------------------------------------------------------------------------- |
| `npm run test` | Vitest — API routes, libs, parsers |
| `npm run test:e2e` | Playwright — builds, serves on port **3333**, smoke-tests `/` and `/login` |

First-time E2E setup: `npx playwright install chromium`. See [`docs/PERFORMANCE-REVIEW.md`](./docs/PERFORMANCE-REVIEW.md) for Lighthouse and performance notes.

Optional: set `NEXT_PUBLIC_POSTHOG_KEY` (same project as `POSTHOG_KEY`) to send **Core Web Vitals** (`web_vital` events) from the browser.

## API

### `POST /api/onboarding/complete`
Expand Down Expand Up @@ -179,7 +207,7 @@ Returns all processed statements for the authenticated user, sorted by creation

### `GET /api/dashboard`

Returns the full dashboard state for the authenticated user (Overview aggregates + generated advisories + optional `coaching_facts` Layer A JSON + Gemini-enriched `narrative` / `cited_fact_ids` on each advisory when AI succeeds).
Returns the full dashboard state for the authenticated user (Overview aggregates + generated advisories + optional `coaching_facts` Layer A JSON). **Does not** call Gemini — responses are fast for Overview and Transactions. Rule-based advisory copy is returned immediately.

**Auth**: Neon Auth session cookie required.

Expand All @@ -190,7 +218,7 @@ Returns the full dashboard state for the authenticated user (Overview aggregates

### `GET /api/dashboard/advisories`

Same query parameters as `GET /api/dashboard`. Returns `{ advisories, coaching_facts }` (same shapes as the parent dashboard payload).
Same query parameters as `GET /api/dashboard`. Returns `{ advisories, coaching_facts }`. This endpoint runs the **Gemini coaching narrative** step (can take up to ~9s) and is what the **Insights** tab calls after the fast dashboard load.

**Auth**: Neon Auth session cookie required.

Expand Down Expand Up @@ -345,6 +373,8 @@ Intentional error route to verify Sentry server-side capture (`SentryExampleAPIE
## Docs

- [`docs/COACHING-TONE.md`](./docs/COACHING-TONE.md) — Coaching language guide: consequence-first nudge patterns, Layer A facts-only numerics, Gemini narrative guardrails, tone constraints for advisory copy.
- [`docs/PERFORMANCE-REVIEW.md`](./docs/PERFORMANCE-REVIEW.md) — Performance review notes (fonts, lazy Insights path, Web Vitals, Lighthouse).
- [`docs/SCHEMA-DRIFT.md`](./docs/SCHEMA-DRIFT.md) — Schema drift RCA, `SCHEMA_DRIFT` API behavior, `db:upgrade` vs boot-time DDL.

## Current scope

Expand Down
Loading
Loading