Uses Anthropic claude-sonnet-4-6 server-side to explain the semantic meaning
of code diffs in the budget app domain (paychecks, bills, financing, actuals).
Input validation rejects empty or oversized (>50KB) diffs. Tests mock the
Anthropic client via direct method replacement (same pattern as db.pool.query).
Nightshift-Task: semantic-diff
Nightshift-Ref: https://github.com/marcus/nightshift
one-time-expenses: POST validation (paycheck_id/name/amount), DELETE, PATCH paid toggle.
config: GET (defaults for missing keys), PUT (transaction, ignores unknown keys).
summary: GET monthly (zeros when no paychecks, full aggregates), GET annual (per-month breakdown).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Tests cover remainingPeriods pure function (single/split plans, boundary
cases), GET/POST/GET:id/PUT/DELETE /api/financing, and
PATCH /api/financing-payments/:id/paid including auto-close when fully paid.
Uses mid-month dates in pure function tests to avoid UTC timezone boundary issues.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Set up Vitest for both server (Node + Supertest) and client (jsdom + React
Testing Library). Extract Express app into app.js for testability. Add example
tests covering bills validation, bills route CRUD, ThemeContext, and App nav
rendering. Update CLAUDE.md with testing docs and requirement to write tests
with features.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- PATCH paycheck-bills/:id/paid: variable bills now preserve amount_override
rather than overwriting it with b.amount (which may be null/0). Fixed bills
continue to lock in b.amount on paid and clear on unpaid.
- generatePaychecks: revert gross/net protection — refresh always updates
gross/net from current settings as originally intended.
- CLAUDE.md: remove gross/net protection note; add td approve sub-agent rule.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace new Date(date_string) + getFullYear/getMonth with direct string
parsing (split('-').map(Number)) so month comparisons are never shifted
by UTC offset. Affects both buildVirtualPaychecks and generatePaychecks.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Migration 004: adds start_date column to financing_plans (DEFAULT CURRENT_DATE)
- generatePaychecks: skips financing plans whose start_date is after the target month
- buildVirtualPaychecks: same start_date guard for virtual previews (already applied)
- generatePaychecks upsert: preserves gross/net when paycheck has any paid bills
- financing.js POST/PUT: accept and store start_date
- Financing.jsx: add Start Date field to create/edit form (defaults to today)
- CLAUDE.md: document start_date guard and paid-paycheck refresh protection
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Data model:
- Migration 003: financing_plans and financing_payments tables
- Plans track total amount, due date, paycheck assignment (1, 2, or split)
- Payments linked to paycheck records, one per period
Payment calculation:
- Auto-calculated: (total - paid_so_far) / remaining_periods
- Split plans halve the per-period amount across both paychecks
- Recalculates each period as payments are made
Financing page (/financing):
- Create/edit/delete plans with name, amount, due date, paycheck assignment
- Progress bar showing paid vs total
- Overdue badge when past due with remaining balance
- Paid-off plans moved to a separate section
Paycheck view:
- New Financing section per column with payment checkbox
- Overdue badge on individual payments
- Running paid/total shown in bill meta
- Financing payments included in remaining balance calculation
- Auto-closes plan and reloads when fully paid off
- Lazy generation works: first interaction generates paycheck and payment records
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Migration 002: variable_amount boolean column on bills (default false)
- Bills form: 'Variable amount' checkbox; amount field becomes optional
'Typical amount' when checked; table shows 'varies (~$X)' and a 〜 badge
- Paycheck view: variable bills show a pencil edit button to enter the
month's actual amount, stored as amount_override on paycheck_bills
- New PATCH /api/paycheck-bills/:id/amount endpoint
- Lazy generation still works: setting an amount on a virtual paycheck
generates it first then saves the override
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- GET /api/paychecks returns virtual data (id: null) without writing to
DB when no records exist for the month
- First interaction (bill toggle, OTE add, actual add) lazily calls
POST /api/paychecks/generate to persist the paycheck
- New PATCH /api/paychecks/:id to update gross and net
- Regenerate/refresh button syncs gross/net from current Settings
- Inline pencil edit for gross/net on each paycheck column header
- 'preview' badge and info banner shown for unsaved months
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Monthly Summary:
- Spending breakdown donut (bills / variable / one-time)
- Variable spending by category bar chart
- Added actuals.by_category to /api/summary/monthly response
Annual Overview:
- Income vs. spending grouped bar chart
- Surplus/deficit bar chart (green/red per month)
- Stacked variable spending by category across all months
- New /api/summary/annual endpoint (single DB round trip for full year)
- AnnualOverview now uses /api/summary/annual instead of 12 parallel calls
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
pg returns DATE columns as JS Date objects which serialize to ISO
timestamps, causing split('-') to produce NaN for the day portion.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The ./server bind mount overwrites /app/server including node_modules
installed during the Docker build. Running npm install on startup
ensures deps are present after the volume mount.
Also reverts the node_modules named-volume workaround in favor of
this cleaner approach (requires node installed locally for non-Docker dev).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
GET /api/summary/monthly returns income, bills, actuals,
and one-time expense totals. Summary page shows stat cards
and a breakdown table with surplus/deficit.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
API for expense categories and actuals with full CRUD.
Paycheck view shows actuals section and includes them in
remaining balance calculation.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
API for adding, removing, and marking one-time expenses paid.
Paycheck view supports inline add form and paid/delete actions.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Auto-generates paycheck records from config and active bills.
GET /api/paychecks auto-generates if month not yet created.
Idempotent generation preserves existing paid status.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Full REST API for bill definitions with validation.
Bills page supports add, edit, toggle active, and delete.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
GET/PUT /api/config for pay dates and amounts.
Settings page fetches and saves configuration.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All tables per PRD data model with default config seeds.
Migration runner tracks applied migrations in DB.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sets up the full monorepo structure with:
- Multi-stage Dockerfile (client-build + production stages)
- docker-compose.yml for production, docker-compose.dev.yml overlay for development
- Express server (port 3000) with pg pool, health route, and SPA static file serving
- React 18 + Vite client with react-router-dom v6, nav bar, and placeholder page components
- .env.example with PostgreSQL and app config
- Empty db/migrations/ directory for future migrations
- CLAUDE.md updated with development workflow commands
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>