An open API service indexing awesome lists of open source software.

https://github.com/breezinstein/future-sight

Self-hosted, household-shared investment & wealth scenario planner β€” project net worth, model what-if events, compare scenarios. React 19 + Express 5 + SQLite, single Docker container.
https://github.com/breezinstein/future-sight

docker finance homelab household personal-finance react scenario-planning self-hosted sqlite typescript wealth-planner

Last synced: 28 days ago
JSON representation

Self-hosted, household-shared investment & wealth scenario planner β€” project net worth, model what-if events, compare scenarios. React 19 + Express 5 + SQLite, single Docker container.

Awesome Lists containing this project

README

          

# πŸ”­ Future Sight

A self-hosted, household-shared **investment and wealth scenario planner**. Project net worth over time, model "what-if" events (lump sums, withdrawals, rate changes), and compare alternative scenarios side-by-side. Built for couples and families who've outgrown spreadsheets.

> Inspired by the [`homedash`](https://github.com/breezinstein/homedash) project for self-hosted homelab UX.

---

## ✨ Features

### 🏠 Household collaboration
- Multi-user with role-based access (**owner**, **editor**, **viewer**)
- Shared plans, activity log of who changed what
- Lightweight email + password auth, sessions stored in SQLite

### πŸ“Š Scenario planning
- One **base** scenario per household + unlimited "what-if" clones
- Clone any scenario to fork your future
- Side-by-side **comparison view** with overlay charts and diff tables at 5/10/20-year horizons

### πŸ’° Buckets & contributions
- Investment "pots" with configurable expected return, currency, target amount, and target date
- Variable contribution schedules over time (monthly / quarterly / annual)
- 16 Lucide icons for visual identification

### πŸ“… Event-driven modelling
- **Cash-flow events**: one-off deposits, withdrawals, contribution changes
- **Rate-change events**: override a bucket's return from a date forward
- **Recurring events** with cadence + end date
- Toggle events on/off for sensitivity testing without deleting

### πŸ“ˆ Historical tracking
- Record actual balances per bucket over time
- Compare projected vs. actual on the dashboard with drift indicator
- CSV import of historical actuals

### 🌍 Multi-currency
- Each bucket has its own currency
- Live FX conversion to the plan's base currency via **[frankfurter.app](https://frankfurter.app)** (ECB-backed, no API key)
- Local cache with 6-hour TTL on latest rates; historical rates cached forever

### 🎨 Design
- Dark-first, Linear-inspired aesthetic
- Inter typography with tabular figures throughout
- Generated UI from a Stitch design brief; tokens locked in `src/index.css`

---

## πŸš€ Quick start

### Option 1: Pre-built image from GitHub Container Registry (recommended)

```bash
docker run -d \
--name future-sight \
-p 3002:3002 \
-v future-sight-data:/app/data \
-e SESSION_SECRET="$(openssl rand -hex 32)" \
--restart unless-stopped \
ghcr.io/breezinstein/future-sight:latest
```

Or with Docker Compose:

```yaml
services:
future-sight:
image: ghcr.io/breezinstein/future-sight:latest
container_name: future-sight
restart: unless-stopped
ports:
- "3002:3002"
volumes:
- future-sight-data:/app/data
environment:
- NODE_ENV=production
- SESSION_SECRET=change-me-to-a-random-string
- ALLOW_REGISTRATION=true
volumes:
future-sight-data:
driver: local
```

Open and create your first account.

Images are published for **linux/amd64** and **linux/arm64** (Raspberry Pi 4+, Apple Silicon, etc.).

### Option 2: Build from source

```bash
git clone https://github.com/breezinstein/future-sight.git
cd future-sight
docker compose up -d --build
```

### Option 3: Local development

```bash
npm install
npm run dev
```

This starts both:
- Backend API on http://localhost:3002
- Vite dev server on http://localhost:5174 (with proxy to the API)

Open .

### Option 4: Production build (no Docker)

```bash
npm install
npm run build
NODE_ENV=production PORT=3002 SESSION_SECRET= npm start
```

Open .

---

## πŸ›  Tech stack

| Layer | Choice |
|---|---|
| Frontend | React 19, TypeScript, Tailwind CSS 4, Vite |
| Charts | Recharts |
| Forms | react-hook-form + zod |
| Icons | lucide-react |
| Dates | date-fns |
| Backend | Node 20, Express 5 (ESM) |
| Database | SQLite via `better-sqlite3` (WAL mode) |
| Auth | bcrypt + express-session + connect-sqlite3 |
| FX | [frankfurter.app](https://frankfurter.app) (ECB-backed) |
| Testing | Vitest |
| Deploy | Single Docker container, multi-stage build |

---

## πŸ—„οΈ Data model

```
users
plans (created_by) ──┬── plan_members (role)
└── scenarios (is_base, cloned_from)
β”œβ”€β”€ buckets (currency, return, target)
β”‚ β”œβ”€β”€ contribution_schedules
β”‚ └── actuals
└── events (cash-flow & rate-change)
fx_cache audit_log
```

All updates to plan / scenario data bump a `version` counter on the plan for cheap polling-based sync between household members (homedash-style).

---

## πŸ” Security notes

- Passwords hashed with **bcrypt** (cost 12).
- Sessions stored server-side in `data/sessions.db`. The cookie holds only an opaque session ID.
- Set `TRUST_PROXY=true` when running behind a TLS-terminating reverse proxy so secure cookies are issued.
- Lock down new account registration with `ALLOW_REGISTRATION=false` (the bootstrap user can still be created when the user table is empty).
- The frankfurter.app API is the only external dependency. Disable network egress if you don't need multi-currency.

---

## πŸ§ͺ Tests

```bash
npm test # run the projection engine tests
npm run test:watch # watch mode
```

The projection engine has 11 tests covering compounding, contributions, deposits, withdrawals, rate changes, and milestone detection.

---

## πŸ“œ API reference (selected)

```
POST /api/auth/signup # create user + default plan + base scenario
POST /api/auth/login
POST /api/auth/logout
GET /api/auth/me

GET /api/plans # list my plans
POST /api/plans # create plan
GET /api/plans/:id # plan + members + scenarios
GET /api/plans/:id/activity # audit log
GET /api/plans/:id/members
POST /api/plans/:id/members
POST /api/plans/:id/compare # multi-scenario comparison

GET /api/plans/:id/scenarios
POST /api/plans/:id/scenarios
GET /api/scenarios/:id
PATCH /api/scenarios/:id
DELETE /api/scenarios/:id
POST /api/scenarios/:id/clone
GET /api/scenarios/:id/projection
GET /api/scenarios/:id/export?type=actuals|events|contributions

POST /api/scenarios/:id/buckets
GET /api/buckets/:id
PATCH /api/buckets/:id
DELETE /api/buckets/:id
POST /api/buckets/:id/contributions
POST /api/buckets/:id/actuals
POST /api/buckets/:id/actuals/import

POST /api/scenarios/:id/events
PATCH /api/events/:id
DELETE /api/events/:id

GET /api/fx/currencies
GET /api/fx/rate?base=USD&quote=EUR
```

---

## πŸ“ Project layout

```
future-sight/
β”œβ”€β”€ server/
β”‚ β”œβ”€β”€ index.js # Express entry
β”‚ β”œβ”€β”€ db/
β”‚ β”‚ β”œβ”€β”€ database.js # better-sqlite3 setup + WAL
β”‚ β”‚ └── schema.sql # tables, indexes, triggers
β”‚ β”œβ”€β”€ lib/
β”‚ β”‚ β”œβ”€β”€ auth.js # bcrypt, session middleware
β”‚ β”‚ β”œβ”€β”€ audit.js # audit log writer
β”‚ β”‚ β”œβ”€β”€ projection.js # projection engine
β”‚ β”‚ β”œβ”€β”€ fx.js # frankfurter.app + cache
β”‚ β”‚ └── csv.js # tiny CSV parser/emitter
β”‚ └── routes/ # auth, plans, scenarios, buckets, events, ...
β”œβ”€β”€ src/
β”‚ β”œβ”€β”€ App.tsx # router
β”‚ β”œβ”€β”€ main.tsx # ReactDOM + providers
β”‚ β”œβ”€β”€ index.css # Tailwind 4 @theme tokens
β”‚ β”œβ”€β”€ api/ # typed fetch client
β”‚ β”œβ”€β”€ components/ # AppLayout, Sidebar, BucketEditor, EventEditor, ...
β”‚ β”œβ”€β”€ context/ # AuthContext, ToastContext
β”‚ β”œβ”€β”€ hooks/
β”‚ β”œβ”€β”€ lib/format.ts # currency/date helpers
β”‚ β”œβ”€β”€ pages/ # Dashboard, ScenarioDetail, ScenarioCompare, ...
β”‚ └── types.ts # shared types
β”œβ”€β”€ tests/
β”‚ └── projection.test.js # projection engine tests
β”œβ”€β”€ data/ # SQLite DB + sessions DB (mounted volume in Docker)
β”œβ”€β”€ Dockerfile
β”œβ”€β”€ docker-compose.yml
└── entrypoint.sh
```

---

## πŸ—ΊοΈ Roadmap / nice-to-haves

These are intentionally out of scope for v1 but would be useful next steps:

- [ ] Email-based household invites (vs. requiring the member to sign up first)
- [ ] CSV column-mapping wizard (currently expects fixed column names)
- [ ] Server-Sent Events for live sync between concurrent editors
- [ ] Daily-snapshot backups with retention policy
- [ ] Inflation toggle (real vs. nominal projections)
- [ ] Tax modelling
- [ ] Bank/brokerage account sync (explicitly out of scope per design)

---

## πŸ“„ License

MIT.