Skip to content

Development

brookie edited this page Nov 10, 2026 · 5 revisions

Development

How the code is organized and how to work on it.

Contents

Setup

git clone https://github.com/brookisme/financial_planner.git
cd financial_planner
pixi install -e dev        # Python, Node, pytest…
pixi run -e dev test-all

Repository layout

src/financial_planner/
  schema.py        pydantic models for every config section
  config.py        merge config/*.yaml, validate, save sections (comments kept)
  sources.py       CSV parsing: column mapping, date/amount detection, inspect
  rules.py         categorization rules and precedence
  summary.py       data window, category totals, child timelines, the web payload
  state.py         .financial_planner/state.json
  server.py        FastAPI app and JSON API (localhost only)
  launcher.py      remembered plan, desktop shortcuts
  cli.py           the financial_plan command
  templates/       blank plan for `init`
  web/             BUILT frontend (committed so users don't need Node)
web/
  src/model.ts     all projection math (pure functions, no DOM)
  src/ui/*.ts      one module per section, settings and categorize
  src/main.ts      loading and routing
  test/            vitest tests for model.ts
examples/demo/     fictional demo plan
scripts/           make_demo_data.py, frame_screenshots.py
tests/             pytest

Architecture

  • Python owns the data: reading config and CSVs, categorizing, averaging, validating and saving settings. It sends the browser one JSON payload.
  • TypeScript owns the interaction and the projections, so sliders respond instantly. The math is isolated in model.ts and tested on its own.
  • State (page edits, saved budgets, presets) goes back to the server and is stored in the plan folder.
  • Config saves go through the same pydantic validation as loading, so invalid YAML never reaches disk.

The API

All under /api, on 127.0.0.1 only. Requests that change anything need the header X-Financial-Planner: 1.

Method Path Purpose
GET /api/payload Everything the main page needs.
GET /api/config Raw merged config, owning files, validation error, data files.
PUT /api/config/{section} Validate and save one section.
GET /api/transactions All transactions with category and how it was set; rules; categories.
POST /api/rules/preview What a candidate rule would match / change.
POST /api/rules Add a rule (row rules replace older ones for the same row).
GET / POST /api/files List / upload CSVs in data/.
GET /api/inspect?file=… Columns, sample and guesses for a CSV.
POST /api/sources/preview Parse files with unsaved source settings.
GET / PUT /api/state, /api/state/{ui|budgets|presets|scenarios} Page state, saved budgets (and picker choices), return / inflation presets. scenarios is kept for older plans.

Frontend

pixi run -e dev web-build   # type-check + bundle into src/financial_planner/web/
cd web && npx tsc --noEmit  # type-check only (or: pixi run -e dev web-check)
cd web && node build.mjs --watch

Run the app against the demo (pixi run demo) and reload after a rebuild. Commit the built files in src/financial_planner/web/ with source changes.

Tests

pixi run -e dev test        # pytest: config, sources, rules, summary, server, CLI
pixi run -e dev web-test    # vitest: forecast math

The forecast math is tested against closed-form results and hand calculations; add a test with any change to model.ts.

Demo data

scripts/make_demo_data.py writes deterministic, fictional CSVs (a card with debit/credit columns and a checking account with a signed amount column):

pixi run -e dev demo-data

Never commit real data. .gitignore refuses CSVs outside the demo and test fixtures.

Screenshots

Take wiki screenshots from the demo plan only (never a real plan), in light mode, then give them some room around the edges, a gray border and rounded corners so they stand out on light and dark pages:

python scripts/frame_screenshots.py ../financial_planner.wiki/assets/*.png \
  --skip app-icon.png menu-bar-icon.png

Images that are already framed are left alone, so it's safe to run on the whole folder. Frame the new screenshots as taken; framing an already framed one would add a second frame.

Code style

  • Python: PEP 8 (100 columns), type hints, Google-style docstrings, module sections in the order Imports / Constants / Public / Internal, BSD 3-Clause header.
  • TypeScript: the Google TypeScript style guide, same section order and license header.

Releasing

Publishing to PyPI (and the desktop app downloads) is a copy-paste checklist on the Releasing page. The short version:

pixi run -e dev test-all
pixi run -e dev publish-test   # TestPyPI
pixi run -e dev publish        # PyPI

Clone this wiki locally