Ongoing

Cairn

Solo Developed aided by Claude Code CLI · 2026 · 8 min read

Built a private, self-hosted financial dashboard for tracking net worth, modelling FIRE projections, running rule-based financial insights, and setting financial goals — designed specifically for UK users with full Scottish tax band support.

View on GitHub →

Overview

Cairn is a personal finance dashboard I built because I wanted full visibility of my financial position without feeding my data into a third-party service. It tracks 11+ account types across pensions, ISAs, savings, property, and debt; models retirement and FIRE projections with adjustable return assumptions; runs a 14-rule financial advisor engine; includes a goals tracker; and features a Claude-powered AI copilot for natural language analysis of your overall position.

Problem

Most personal finance apps are cloud-hosted, subscription-based, and built for a generic audience. None of them modelled Scottish income tax bands correctly, none gave me the kind of rule-based insights I actually wanted (pension headroom, ISA allowance countdowns, salary sacrifice optimisation, carry-forward calculations), and all of them required me to hand over sensitive financial data to a third party. I wanted something self-hosted, private by default, and built around how UK personal finance actually works.

Constraints

  • All financial data had to stay on my own infrastructure — no third-party sync or cloud storage
  • It needed to handle the full range of UK account types: DC pensions, SIPPs, DB/final salary pensions, S&S ISAs, cash ISAs, property, mortgage, credit cards, loans, and custom accounts
  • Scottish income tax bands had to be modelled correctly for the salary sacrifice calculator
  • The AI copilot had to be safe to use — no personal identifiers sent to external APIs
  • It had to be deployable simply via Docker for easy self-hosting

Approach

I built Cairn as a Flask API backend with a React frontend, packaged into a single Docker image via a multi-stage build. The database is SQLite, which keeps it simple to back up and run without a separate database service. The financial advisor module is rule-based — 14 checks covering everything from ISA deadlines to pension carry-forward opportunities — and runs on every dashboard load. The AI copilot uses the Claude API but only sends numerical summaries, not account names or personal details. A cron job handles automated monthly snapshots for net worth history.

Key Decisions

SQLite over a dedicated database

Reasoning:

For a single-user self-hosted app, SQLite is the right call. It's a single file, trivially easy to back up, and removes the need for a separate database container. The performance ceiling is nowhere near a concern at this scale.

Rule-based financial advisor rather than AI-first

Reasoning:

Rules are transparent, predictable, and always available. I know exactly why I'm being told to top up my ISA or look at salary sacrifice. The AI copilot is a useful addition on top, not a replacement for deterministic logic.

Send only numerical summaries to the Claude API

Reasoning:

The whole point of self-hosting is that sensitive data stays home. The AI copilot gets total values and ratios — enough to give useful commentary — but no account names, institutions, or personal identifiers.

Multi-stage Docker build combining Node and Python

Reasoning:

A single image that builds the frontend assets and then serves everything through Flask keeps the deployment simple. One compose file, one container, one port.

Design for local network use

Reasoning:

Token-based auth with hashed passwords is appropriate for a home network app. Not every self-hosted tool needs to be hardened for public internet exposure, and keeping the security model honest avoids a false sense of safety.

FIRE scenarios rather than a single projection

Reasoning:

Lean, Regular, and Fat FIRE use different safe withdrawal rates (5%, 4%, 3.5%) and give a more honest picture of the range of outcomes. A single number would feel artificially precise for something this speculative.

Tech Stack

  • Python 3
  • Flask
  • Gunicorn
  • SQLite
  • React
  • Vite
  • Docker / Docker Compose
  • Claude API (Anthropic)
  • Bank of England API
  • Werkzeug (PBKDF2 auth)

Result & Impact

  • Self-hosted via Docker
    Deployment
  • 11+ (pensions, ISAs, savings, property, debt, and more)
    Account types supported
  • FIRE planner, salary sacrifice, debt payoff, mortgage scenarios, carry-forward calculator, goals tracker
    Financial tools

Cairn replaced a scattered set of finance mobile apps with a proper dashboard that gives me a complete, private view of my financial position. The monthly snapshots make progress tangible, the rule-based advisor surfaces things I'd otherwise miss or defer, and the FIRE projections give a concrete sense of where things are heading. The goals tracker makes individual targets feel less abstract.

Learnings

  • Rule-based systems age better than they're given credit for. Clear, auditable logic is more trustworthy for financial decisions than a black box, even an intelligent one.
  • SQLite is genuinely the right database for most self-hosted personal projects. The temptation to reach for Postgres is usually premature.
  • Multi-stage Docker builds that combine frontend and backend into one image dramatically simplify self-hosted deployment — one compose file is much easier to maintain than an orchestrated multi-service stack.
  • Designing privacy constraints upfront (what goes to the API, what stays local) is much easier than retrofitting them later.
  • Offering multiple FIRE scenarios rather than a single projection is more honest — it surfaces how sensitive the outcome is to your assumptions about spending and withdrawal rate.

What it is

Cairn is a private financial dashboard I built and run on my own infrastructure. It tracks my full financial position — pensions, ISAs, savings, property, mortgage, credit cards — takes monthly snapshots to chart net worth over time, and runs a rule-based financial advisor that surfaces actionable insights on every load.

Beyond the core dashboard, it includes:

  • A FIRE planner with Lean, Regular, and Fat FIRE scenarios, a Coast FIRE calculator, and a drawdown simulator
  • A goals tracker for named financial targets linked to net worth or specific account types
  • A tax year summary panel covering ISA contributions, pension contributions, personal allowance status, and a £100k+ taper warning
  • A salary sacrifice calculator with accurate Scottish and rUK tax bands
  • A carry-forward pension calculator for three-year historical unused allowance calculations
  • A debt payoff planner (avalanche vs snowball) and a mortgage scenario modeller
  • A Claude-powered AI copilot for natural language analysis of your position
  • A Bank of England base rate display for live context

The name comes from the idea of building something one stone at a time.

Why I built it

Most personal finance apps are cloud-hosted, subscription-based, and built for a broad audience that doesn’t include Scottish taxpayers, SIPP holders, or people who want their financial data to stay on their own hardware.

I was managing things across a variety of mobile finance apps. That’s fine for a while, but it doesn’t give you centralised financial projections, it doesn’t surface what you should be doing, and it doesn’t keep a comprehensive history you can actually look back on.

How it works

The backend is a Flask API serving a React frontend, packaged into a single Docker image via a multi-stage build. The database is SQLite — a single file that’s trivial to back up and requires no separate database service.

On the dashboard, you get a live view of all accounts, the current net worth, a snapshot history chart (stacked by asset category with a target line), and the financial advisor panel. The advisor runs 14 rule-based checks every time the page loads:

  • ISA allowance usage and days remaining in the tax year
  • Pension contribution headroom against the annual allowance
  • Carry-forward pension opportunities from the previous three years
  • Salary sacrifice opportunities based on current income
  • Debt prioritisation and emergency fund status
  • Mortgage rate alerts and acceleration opportunities
  • Net worth velocity (how quickly things are moving)
  • Personal allowance taper warning for income approaching £100k

These are deterministic rules, not model outputs. The logic is transparent and the results are predictable. Insights are filterable by category — Savings, Debt, Pension, Property, Tax.

FIRE planning

The FIRE planner projects retirement across three scenarios using different safe withdrawal rates:

  • Lean FIRE — 5% SWR, minimal spending
  • Regular FIRE — 4% SWR, the standard assumption
  • Fat FIRE — 3.5% SWR, more comfortable spending

For each scenario it calculates the target pot size, years-to-FIRE based on current net worth and monthly savings rate, and whether Coast FIRE has already been reached. A separate drawdown simulator lets you project how long a retirement pot will last given a customisable retirement age, spending level, and State Pension start date. Defined benefit pension income is factored in separately.

Goals tracker

Named financial targets — each with an amount, target date, and emoji — can be linked either to overall net worth or to a specific account type balance. Progress is tracked as a percentage with days remaining, and achieved goals get a badge. It’s a small feature, but it makes individual targets feel concrete rather than abstract.

The AI copilot

The Claude-powered copilot sits alongside the rule-based advisor and lets you ask natural language questions about your financial position. The important detail is what it doesn’t receive: no account names, no institutions, no personal identifiers — only numerical summaries. Totals, ratios, and projections are enough for useful commentary, and keeping it that way means the self-hosted privacy model holds.

Deployment

Cairn runs via Docker Compose. The multi-stage Dockerfile builds the React frontend and then hands off to Gunicorn serving the Flask app with static assets included. One image, one container, one port. A cron job inside the container handles the automated monthly snapshots. It’s hosted on a Ubuntu virtual server alongside a number of other Docker containers managed via Portainer.

For home network use, token-based auth with PBKDF2-hashed passwords and 7-day sessions is the right level of security. If you wanted to expose it externally, you’d put it behind a reverse proxy with HTTPS and something like Authelia in front — but for a local-only tool, keeping the security model honest is better than over-engineering it.

Accounts can be reordered via drag-and-drop, filtered by type, and searched by name. A full JSON export and import is available for backups and migration. Dark and light themes are supported and persisted in localStorage.