# RUFFIN — household runway planner

A web app that tells you how long your money lasts and what to do about it. Same screens and math as the
Runway Excel template, plus login and cloud sync. No build step: it is plain HTML/CSS/JavaScript, so any
static host serves it.

```
index.html          the app shell
css/ruffin.css      styles (Mint Runway palette)
js/config.js        <-- the only file you edit to go live (Supabase keys, Stripe link, support email)
js/state.js         data model, local save, sample household
js/engine.js        all calculations (ported 1:1 from the workbook)
js/screens.js       every screen
js/ui.js            tables, cards, pills, charts, modals
js/import.js        Excel-template import, JSON backup
js/statements.js    Inbox: PDF/CSV/text statement reader, matching, posting (all in the browser)
js/ai.js            optional AI reader + email, talks only to YOUR workers below
worker/             two optional Cloudflare Workers: ai-extract.js (AI statement reader), send-plan.js (email the plan)
js/cloud.js         Supabase login + sync
js/lists.js         dropdown lists (banks, lenders, categories, currencies…)
js/keywords.js      default keyword → category rules
vendor/             xlsx (SheetJS), Chart.js, supabase-js — no CDN needed
supabase/schema.sql database tables + security rules
legal/              privacy + terms (edit the contact lines)
_headers            security headers for Cloudflare Pages
```

## Languages & countries
Settings → Language (12 languages; the Welcome screen has the picker too) and Country. Translations live in `lang/<code>.js` — one dictionary per language; `lang/en.keys.json` lists every key. Anything not translated shows in English. To find what's still English on a screen, open the browser console and run `RuffinI18n.exportMissing()` — it downloads a JSON of untranslated strings; translate the values and paste them into the language file. Country switches US-only features off (Retirement money tab, Social Security wording, US transition deadlines).

## Using it
- **/** opens the command bar anywhere: type `kroger 42.17` to log it, or any word to find entries, bills, debts, accounts, actions, screens. **H** hides every number.
- Hover any **ⓘ** for a one-line explanation. First visit to a screen shows a 3–5 step tour (replay from More ▾ → "Show me around").
- Log: **⑂** splits a row across categories; ✕ deletes with Undo, and deleted rows sit under "Deleted items" for 30 days. Inbox: "Undo this statement" reverses a post.
- Budget: "How often" turns a bill into a sinking fund (yearly 768 → 64/mo set aside). Subscriptions card shows the yearly total and a cancel link.
- Phone: open the site in Safari/Chrome → Share → **Add to Home Screen**. It installs like an app and works offline (service worker caches the shell).
- **Retirement money** tab: "If I tap it" (tax, penalty, lost growth, runway gained for one withdrawal), drawdown order, allocation check (is the next 18 months of cash in stocks?), runway history. Rules modelled: 10% penalty under 59½, Rule of 55, Roth contributions, HSA, capital gains. Set birth year + rates on Setup. Estimates — not tax advice.
- **Retire?** tab: can I stop at X, the number, earliest age at Current/Trimmed/Lean, levers, savings-by-age chart, year-by-year math. Starts from your Budget; needs your three Social Security numbers (ssa.gov → my Social Security statement). Rough by design.
- Debts: Avalanche (APR first) or Snowball (smallest first) toggle. Settings: Theme Auto/Light/Dark, currency symbols on/off (multi-currency: set your home currency and rates on Setup).
- Logo/mascot files live in `img/` and `icons/` — swap them to rebrand.
- Partner: Settings → Share with your partner (needs Supabase; run the updated `supabase/schema.sql`). Both sign-ins read and write the same plan.

## 0. Try it right now (no accounts)
Double-click `index.html`. Click **Load sample data**. Everything runs in the browser and saves to the browser.
Settings → *Import from the Excel template* reads a Runway_Template .xlsx/.xlsm (or the personal plan) so nothing is typed twice.
**Inbox** → drop a bank or card statement (PDF, CSV or pasted text). It is read in the browser, matched against your Log, and posted with one click; the account's balance and "reconciled through" date update.

## 1. Domain (≈ $10–15 / year)
Cloudflare → Domain Registration → Register → search `ruffin…` (e.g. `ruffinplan.com`, `getruffin.app`, `ruffin.money`). Buy it. Done.

## 2. GitHub (free) — where the code lives
1. github.com → Sign up.
2. New repository → name `ruffin` → Private → Create.
3. Upload this whole folder (drag-and-drop in the browser works: *uploading an existing file* → drop the folder contents).
   Do **not** upload `node_modules` if present.

## 3. Cloudflare Pages (free) — serves the site
1. dash.cloudflare.com → Workers & Pages → Create → Pages → **Connect to Git** → pick the `ruffin` repo.
2. Build settings: Framework preset **None**, Build command **(empty)**, Build output directory **/**. Save and Deploy.
3. You get `ruffin-xxx.pages.dev` in about a minute. Custom domains → add your domain → Cloudflare wires DNS automatically.
Every time you push a change to GitHub, the site updates itself.

## 4. Supabase (free) — login + cloud sync
1. supabase.com → Start your project → sign in with GitHub → New project (name `ruffin`, pick a region near you, set a database password and keep it somewhere safe).
2. Left menu **SQL Editor** → New query → paste the contents of `supabase/schema.sql` → Run.
3. **Authentication → URL Configuration**: Site URL = `https://your-domain` ; add `https://ruffin-xxx.pages.dev` to Redirect URLs.
4. **Project Settings → API**: copy *Project URL* and the *anon public* key into `js/config.js`:
   ```js
   supabaseUrl: "https://abcdefgh.supabase.co",
   supabaseAnonKey: "eyJhbGciOi...",
   ```
   Commit/push. The Settings screen now shows **Account & cloud sync** with sign-in.
5. Optional: Authentication → Providers → Email → turn **Confirm email** off while testing.

Free tier: 500 MB database, 50,000 monthly users. A plan document is ~50–200 KB, so thousands of users fit. Pro ($25/mo) adds daily backups.

## 5. Stripe — selling RUFFIN Pro
1. dashboard.stripe.com → Products → Add product "RUFFIN Pro" → price (e.g. $4/month or $29 one-time).
2. Payment Links → Create → pick the product → copy the link into `js/config.js` → `stripePaymentLink`.
3. The **Upgrade to Pro** button on Settings opens it. To gate features automatically, add a Stripe webhook that sets
   `profiles.is_pro` (table already exists) — that is a 20-line serverless function; do it when there are paying users.

## 6. Optional workers — AI statement reader and "Email me this plan"
Both are tiny Cloudflare Workers (free tier: 100k requests/day). Nothing is stored in them; they forward one request and return the answer.
1. `npm i -g wrangler` → `wrangler login`.
2. AI reader: `cd worker` → edit `wrangler.toml` (ALLOWED_ORIGIN = your site) → `wrangler deploy` → `wrangler secret put ANTHROPIC_API_KEY` (key from console.anthropic.com).
   Copy the worker URL into `js/config.js` → `aiExtractUrl`. The Inbox now shows **Read with AI** for PDFs the rules reader can't parse.
   What leaves the browser: the statement text with account/card numbers already redacted client-side. Cost ≈ 1–3¢ per statement.
3. Email: copy `wrangler.toml` to `wrangler-mail.toml` with `name = "ruffin-mail"`, `main = "send-plan.js"`, var `FROM = "RUFFIN <plan@your-domain>"` → `wrangler deploy -c wrangler-mail.toml` → `wrangler secret put RESEND_API_KEY` (resend.com, verify your domain).
   Copy the URL into `js/config.js` → `emailUrl`. Print plan gets an **Email me this page** button.

## 7. Resend (free) — nicer sign-in emails (optional)
Supabase sends auth emails itself (fine to start). For a custom sender: resend.com → verify your domain → Supabase → Authentication → SMTP settings.

## 8. Before you announce it
- Edit `legal/privacy.html` and `legal/terms.html` (contact email, prices).
- Set `supportEmail` in `js/config.js`.
- Test: Load sample data → sign in → open the site on your phone → same numbers.

## Costs at a glance
| Users | Monthly |
|---|---|
| you + friends | $0 (domain ≈ $12/yr) |
| a few hundred | $25 (Supabase Pro for backups) |
| thousands | $25–45 + Stripe fees per sale |

## Updating the app
Edit files → push to GitHub → Cloudflare redeploys. Bump `version` in `js/config.js` **and** `CACHE` in `sw.js` so installed phones fetch the new build.
