Adds a full pensions feature: SIPP/workplace DC/LISA account metadata,
contribution recording with relief-at-source/net-pay/salary-sacrifice
gross calculations, state pension tracker, annual allowance monitor,
and LISA summary. Pension contributions feed into the tax report
(RAS gross totals, allowance used). Includes two Alembic migrations,
backend service/schema/API, and full frontend pensions page with
cards for allowance, state pension, LISA, and retirement projection.
Also fixes CSRF cookie secure flag (must be false for HTTP deployments)
and extends tax schemas/service to expose pension data in the report.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Salary and other income marked is_recurring=True were being returned
alongside expense subscriptions. Added type='expense' filter so only
outgoing recurring transactions appear.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- DEMO_MODE=true env flag: disables password changes and backup endpoints (403),
exposes GET /demo/status for frontend detection
- Auto-seed on first startup: creates demo user (demo@mymidas.app / demo123)
with 6 months of transactions, investments, budgets, subscriptions, and tax
payslips; takes a pg_dump snapshot immediately after for hourly restore
- Hourly reset: resetter Alpine container with cron restores DB from snapshot
and purges uploaded attachments every hour on the hour
- Frontend: amber demo banner on all pages, login page shows credentials,
password change disabled with notice, backups section replaced with notice
- demo/ directory: self-contained docker-compose.yml (ports 4001/8091),
.env.example, reset.sh, and step-by-step Portainer DEPLOY.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Recurring service: auto-detects direct debits/subscriptions from CSV imports
using frequency analysis; manual toggle in transaction detail drawer
- Subscriptions page (/subscriptions): groups recurring payments with monthly
cost equivalents, next-payment badges, and re-scan trigger
- UK Tax page (/tax): payslips/P60 entry, income tax + NI + CGT + dividend tax
calculations, configurable rate tables per tax year (pre-seeded 2024/25 and
2025/26), editable in-app so Budget changes need no rebuild
- Migration 0006: tax_rate_configs, tax_profiles, payslips, manual_cgt_disposals
with RLS; seeds 2025/2026 rate configs for existing users
- Chart tooltip fix: all Recharts tooltips now use TOOLTIP_STYLE constant so
they render correctly across all dark/light themes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Users can now create, edit, and delete custom categories from Settings → Categories. System categories (45 built-in) are shown read-only. Backend adds update_category() and delete_category() service functions; frontend has a new categories API module and a full CRUD section in SettingsPage with filter tabs, colour picker, and delete confirmation.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add budget editing: updateBudget() API, edit button on budget cards,
BudgetFormModal adapted for create/update (category locked on edit)
- Remove permanently-broken POST /auth/totp/verify stub and its unused
TOTPVerifyRequest schema
- Wire getHoldingTransactions() to AssetDetail page — transaction history
table now shows above the candlestick chart, sorted newest-first
- Fix multi-currency net worth in account_service: account balances are
now converted to base_currency via ExchangeRate table before summing
- Replace silent bare pass exception handlers with logger.warning() in
transactions.py (OCR/AI pipeline) and price_feed_service.py (search)
— ValueError in date/number regex parsing left silent (control flow)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- OCR pipeline: Tesseract (images) + pdfplumber (PDFs) → AI text prompt →
rule-based regex fallback; works with any text model, not just vision models
- Scan Receipt toolbar button parses a photo and pre-fills the transaction form;
receipt image is automatically attached to the created transaction
- AI settings page: provider, API key (AES-256-GCM encrypted), custom URL,
model, and per-user debug toggle that gates the OCR/AI debug panel
- Fix CSRF cookie secure=False so HTTP deployments work; add 7-day max_age
- Fix attachment_refs missing from _to_response (attachments never appeared in UI)
- Fix multipart boundary lost when Content-Type was set manually in axios calls
- nginx: raise client_max_body_size to 15 MB, add 120s proxy timeout for OCR
- Migration 0005: add ai_debug boolean to users table
- Update README and CLAUDE.md with AI scanning docs and architecture notes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Backend returns raw AI text alongside parsed fields
- Drawer shows expandable "Raw AI response" section when result has empty fields
- Scan Receipt shows raw response inline if no fields were extracted
- Helps diagnose model output issues without needing server logs
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- POST /settings/ai/test sends a minimal text prompt to verify the provider
- Returns ok/message — maps HTTP status codes to human-readable explanations
- 405 → "URL pointing at wrong place, check custom URL has no path suffix"
- 401 → invalid key, 404 → wrong path, 429 → rate limited, etc.
- Test button appears once a key is saved; result shown inline below buttons
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New backend endpoint POST /transactions/parse-receipt (file upload, no existing txn needed)
- Refactored AI call logic into shared _call_ai_parse helper (no duplication)
- Scan Receipt button in transactions toolbar → file picker → AI parse → pre-filled form
- TransactionFormModal accepts initialValues prop to pre-populate fields from receipt
- "Fields pre-filled from receipt" banner shown in form when AI-populated
- Scan error displayed inline with dismiss button
- Supports JPEG, PNG, WebP, PDF (Anthropic) or images (OpenAI)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Settings → AI: optional base URL and model name fields
- Defaults to Anthropic/OpenAI public APIs when left blank
- Custom URL enables Open WebUI, LM Studio, Ollama, and any OpenAI-compatible endpoint
- Parse endpoint uses custom base URL and model if configured
- Migration 0004: ai_base_url + ai_model columns on users
- OpenAI provider label updated to "OpenAI-compatible"
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Settings → AI: configure Anthropic or OpenAI provider with encrypted API key
- Sparkle button on each attachment in transaction drawer sends image/PDF to AI
- AI extracts merchant, amount, date, description, category hint
- "Apply to transaction" button patches the transaction with parsed fields
- Anthropic supports images and PDFs; OpenAI supports images only
- API key stored AES-256-GCM encrypted in users table (migration 0003)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Phase 3 — Investments:
- Multi-currency support: holdings track purchase currency, FX rates convert to base for totals
- Capital gains report using UK Section 104 pool method, grouped by tax year
- Capital Gains tab added to Reports page
Phase 5 — Polish & Hardening:
- Mobile-responsive layout: bottom nav, sidebar hidden on mobile, logo in TopBar, compact header buttons, hover-only actions now always visible on touch
- Backup system: encrypted GPG backups via backup.sh, nightly scheduler job, admin API (list/trigger/download/restore), Settings UI with drag-to-restore confirmation
- Docker entrypoint with gosu privilege drop to fix bind-mount ownership on fresh deployments
- OWASP fixes: refresh token now bound to its session (new refresh_token_hash column + migration), CSRF secure flag tied to environment, IP-level rate limiting on login, TOTPEnableRequest Pydantic schema replaces raw dict
- AES-256-GCM key rotation script (rotate_keys.py) with dry-run mode and atomic DB transaction
- CLAUDE.md added for AI-assisted development context
- README updated: correct reverse proxy port, accurate backup/restore commands, key rotation instructions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
New first-tab report showing a full breakdown of where money sits:
- Three KPI cards: total assets, total liabilities, net worth
- Proportional stacked bars showing asset and liability composition
- Side-by-side account lists grouped by type (Cash, Savings, ISAs,
Investments, Pension, Crypto vs Credit Cards, Loans, Mortgages)
- Backend endpoint GET /api/v1/reports/balance-sheet with typed schema
- Balance Sheet is now the default tab on the Reports page
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>