- Change idx_financing_plans_active to partial index (WHERE active = true)
to avoid useless B-tree index on low-cardinality boolean column
- Scope timingMiddleware to /api routes only (was globally registered,
which caused noise from static asset requests)
- Add unit tests for timing middleware (5 tests covering: next() call,
timing log format, SLOW warning threshold, fast-request path, status code)
Nightshift-Task: perf-regression
Nightshift-Ref: https://github.com/marcus/nightshift
62 client tests now passing across 8 test files. Handles duplicate text in
stat cards vs summary tables using getAllByText, and error states via ok:false
mock responses to trigger component-level error messages.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Export ordinal/formatCurrency/formatPayDate for direct testing. Tests cover
pure function formatting, virtual/saved rendering, preview banner, error state,
month navigation (including year wrap), bill display, remaining balance, and
gross/net amounts. Uses vi.useFakeTimers({ toFake: ['Date'] }) to control
current date without faking setTimeout (which would break RTL's waitFor).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>
This migration was part of the financing start_date feature (119d53c) but
was not staged by the previous agent.
Co-Authored-By: Claude Opus 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>
- CSS custom properties design system with full light/dark themes
- ThemeContext with localStorage persistence and system preference detection
- Theme toggle button in nav (moon/sun icon)
- Modern Inter font, card-based layout, sticky nav
- All pages restyled with CSS classes instead of inline styles
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sub-agents must never call td commands directly. Concurrent writes
from parallel agents corrupt the SQLite database. Only the
orchestrator manages td task lifecycle.
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>
Mounting ./server:/app/server overwrote the npm-installed node_modules
from the Docker build. Named volumes for server/client node_modules
shadow the bind mount so installed packages are preserved.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
.dockerignore prevents node_modules and dist from leaking into the
build context, which could silently overwrite npm-installed packages.
Forced no-cache rebuild confirms dotenv and all deps install cleanly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Dockerfile: add COPY db/ /app/db/ so migrations are available at
runtime (server/src/db.js requires ../../db/migrations at startup)
- vite.config.js: fix dev proxy port from 3001 to 3000 to match
server's default PORT
Docker build passes; server starts and connects to DB correctly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Monthly summary:
- GET /api/summary/monthly returns income, bills, actuals, one-time
expense totals and surplus/deficit for a given month
- MonthlySummary page shows stat cards and breakdown table
Annual overview:
- AnnualOverview page fetches all 12 months in parallel via Promise.all
- Year navigation, summary cards, monthly table with totals row
- Fix: normalize nested API response to flat fields expected by component
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>
Year-at-a-glance table with monthly income, bills, variable
spending, and surplus/deficit. Fetches all 12 months in parallel.
Summary cards show annual totals.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- One-time expenses: paid toggle, delete, and inline add form in
paycheck columns (wired to POST/DELETE/PATCH /api/one-time-expenses)
- Variable spending actuals section with category select, amount,
note, date fields; actuals included in remaining balance
- Both Phase 3 features fully integrated into PaycheckView
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>
Document commit-per-task, documentation hygiene, and td lifecycle requirements
for all agents working in this repo.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>