- Framework: Next.js 16 (App Router, Turbopack)
- UI primitives: @base-ui/react (headless components)
- CSS: Custom SMACSS-derivative framework (
src/styles/) - Database: SQLite via better-sqlite3
- Auth: JWT sessions with httpOnly cookies
- Icons: lucide-react
- Charts: Recharts
- i18n: Custom locale system with React context
- AI: Claude CLI via stdin pipe (Opus model)
- Real-time: Server-Sent Events (in-process EventBus)
- Finance data: YNAB REST API
- Bank sync: Synci REST API (income polling)
src/
app/ # Next.js app router pages
(app)/ # Authenticated app pages
api/ # API routes
chat/ # Chat messages, reactions, typing
synci/ # Synci bank sync (accounts, sync)
ynab/ # YNAB sync, transactions, accounts
heatmap/ # Spending heatmap data
summary/ # AI financial summary
login/ # Public login page
components/
ui/ # Reusable UI components
layout/ # App shell, sidebar, FAB
dashboard/ # Dashboard components
chat/ # Chat interface
shared/ # Shared components (add expense dialog)
lib/
auth.ts # JWT session management
db.ts # SQLite database + schema init + migrations
event-bus.ts # In-memory pub/sub for SSE
use-events.ts # Client-side SSE hook
daily-budget.ts # Segment-based cash flow simulation
household.ts # Shared household settings helpers
matching.ts # YNAB payee matching engine
transaction-utils.ts # Transfer detection helpers
date-utils.ts # Date formatting
locale-context.tsx # React context for i18n
ynab-context.tsx # React context for YNAB data
ai/
finance-advisor.ts # Claude CLI integration for Dougie
claude-image.ts # Claude vision for receipts
default-prompts.ts # Default AI prompt templates
ynab/
client.ts # YNAB REST API client (read + create)
i18n/
en.ts, fi.ts # Translation files
styles/
theme.css # CSS custom properties (light/dark)
base.css # Resets, typography
animations.css # Keyframes
state.css # State classes
layout.css # App shell, sidebar, FAB, PWA safe areas
modules/ # Per-component CSS modules
index.css # Single entry point
middleware.ts # Auth middleware with exemptions
data/ # SQLite database (gitignored)
docs/ # Documentation
users— user accounts with locale, budget shareuser_linked_accounts— per-user linked YNAB spending accountshousehold_settings— shared key-value settingstransactions— YNAB transactions (shared, unique on ynab_id)recurring_bills— monthly bills with is_priority flagbill_amount_history— bill amount tracking per monthbill_manual_status— manual paid/unpaid overrides per monthincome_sources— income sources with expected dayincome_amount_history— income amount tracking per monthdebt_overrides— interest rate, payment, priority overridesinvestment_overrides— contribution, return, ticker overridessubscriptions— recurring subscriptions with brand styling and priorityaccount_notes— per-account notes for AI contextsavings_goals— savings targets with progresspayee_matches— YNAB payee patterns with optional amount rangemonthly_matches— matched transactions per source per monthchat_messages— shared chat history with image thumbnailschat_reactions— emoji reactions on chat messageschat_last_seen— per-user read trackingtyping_status— real-time typing indicatorstransactions_last_seen— per-user transaction read trackingdaily_budget_history— daily budget and spending for savings streaknet_worth_snapshots— daily net worth historymonthly_snapshots— monthly income/expenses/categories for trendsai_summaries— cached AI summaries per locale (shared across users)synci_processed— tracks processed Synci transaction IDsynab_accounts— cached YNAB accounts with closed statusynab_categories— cached YNAB categories per monthynab_month_budget— cached YNAB month budget dataticker_cache— cached stock/fund ticker data
- YNAB sync fetches accounts, transactions (10 months), month budget
- Data persisted to local SQLite tables
- Auto-match runs against payee patterns
- Deleted YNAB transactions removed from local DB
- Closed accounts marked in ynab_accounts
- Net worth and monthly snapshots saved
- SSE broadcasts
sync:completeanddata:updatedto all clients - Dashboards, heatmap, and chat re-fetch from local DB
Segment-based cash flow simulation (src/lib/daily-budget.ts):
- Spans from today to next income event (wraps across month boundary)
- Builds segments between income events
- Subtracts obligations (bills, debts) due in each segment
- Savings goal deducted from last segment
- Daily budget = tightest segment's pool / days
- Must-pay priority items always subtracted regardless of auto mode
- Non-priority items optionally included based on settings
Claude CLI invoked via spawn with Opus model. Features:
- Dougie (chat advisor) — full conversation with financial context, priority awareness, conservative advice
- AI summary — cached, shared across users, reads from local DB
- Debt suggestion — one-shot advice, shared cache
- Receipt parsing — Claude vision extracts amounts, payees, dates, accounts
- Transaction categorization — AI picks YNAB category for new expenses
Polls Synci REST API every 30 minutes via systemd timer:
- Fetches transactions for mapped bank accounts
- Matches positive amounts against income source patterns
- Creates real YNAB transaction with proper ID
- Updates local account balance
- Marks income as received in monthly_matches
- Deduplicates via synci_processed table
- User submits credentials to
POST /api/auth/login - Server validates against SQLite, returns JWT in httpOnly cookie
- Middleware checks JWT on every request
- Exempted:
/api/auth,/api/events,/api/synci/sync(cron secret) - Unauthenticated requests redirect to
/login
- Module root:
.card,.button,.dialog - Sub-elements:
.card-header,.card-title - Layout:
.l-app-shell,.l-sidebar,.l-page-container - State:
.is-active,.is-disabled,.is-paid,.is-priority - Variants:
[data-variant="outline"],[data-size="sm"] - Overrides use compound selectors:
.card.metric-card