Main moved on by 27 commits since this branch forked, including three schema steps of its own (budget folders, placement, nested bills). Resolutions worth knowing: - The anchored-model migration becomes 10 -> 11; main's 7 -> 10 run first. - Main's nextUnconfirmedOccurrenceOnOrAfter walked the calendar grid for every cost, which would have shown the slot-model "next due" for an anchored bill in the budget tree. Both walks are now generators and the lookup dispatches on anchoring, like occurrencesOf. - A folder's "Bills due" summed only occurrences, and an anchored bill's charges are never occurrences, so a charged phone plan read as 0 due. budgetTree now adds an anchored bill's charges in the month. - Main's RecurringSection (with RecurringSplitEditor) supersedes this branch's split editor; the anchoring rules are ported onto it: start-date validation via startDateNeedsDay, month precision hidden for lastCharge, the anchoring control locked once a cost has charges. - PurchaseDialog keeps main's placement control. The "Recurring cost" select replaces main's "Unlink from bill" checkbox, since "None" does the same. A bill created from the dialog nests under its post like one from Settings. - Dropped main's "bounded projection ignores invalid confirmations" test: it exercised slot confirmations on a lastCharge cost, which no longer exist. Co-Authored-By: Claude Opus 5.5 <[email protected]>
6.4 KiB
Executable File
Product
Platform
web
Users
One person: the owner of the money, managing their own budget. They are leaving a spreadsheet, so they already know their own categories, already think in months, and value speed of entry over guidance. They tolerate rough edges in exchange for the tool doing exactly what they mean.
Confirmed permanently single-user. One person, one browser, one dataset. There are no accounts, no second role, and no shared or household use planned.
Product Purpose
Envelope budgeting for a single person, replacing a spreadsheet.
Money is divided each month into named envelopes ("posts"). Unspent allocation carries into the next month; overspending carries forward as debt. The app answers two questions at a glance: how much is left in this envelope, and did I overspend.
Success is that the owner stops maintaining a spreadsheet, and that a month's purchases can be entered fast enough not to be a chore.
Positioning
Two things a general budgeting app does not do:
- Envelope rollover is the whole model, not a feature. Every figure derives from one left-fold across months, so a balance is always the honest consequence of every prior month.
- The data never leaves the browser and never needs an account. IndexedDB is the only store. That is a deliberate product position, not a missing backend.
Operating Context
The owner records spending after the fact, often in batches — a grocery trip is twenty lines entered in one sitting, not twenty separate visits. Income arrives monthly and varies, so it is entered per month rather than assumed.
Purchases frequently belong to more than one envelope (food bought at a social event), and larger purchases are spread across several months deliberately rather than absorbed by one.
Money is handled in DKK, USD and EUR, with DKK as the base.
Capabilities and Constraints
Confirmed and in place:
- Nested budget folders organize posts, bills, and optionally individual purchases. A single-post bill starts beneath that post but can be moved independently. Folder Bills due reports scheduled bill prices for the selected month; posts alone hold envelope balances. A purchase's separate row never changes which posts its splits charge.
- Posts (envelopes) with monthly allocation, created and archived by the owner. Posts are archived, never deleted, because purchases reference them.
- A post with no applicable allocation rule still records spending and shows its balance, but is not labelled overspent. An explicit zero allocation is a budget rule and can be overspent.
- Allocation is either a fixed amount or a percentage of that month's income.
- A purchase can be split across several posts, by percentage or by fixed amounts, and can also be spread across future months as a payment plan. The two compose.
- A purchase may have no post. It remains visible in its month and counts in Spent, while leaving envelope balances unchanged.
- Per-month income, entered directly, varying month to month.
- Multi-currency (DKK/USD/EUR) against a user-maintained exchange-rate table, with an optional on-demand fetch that fails soft and is never required.
- JSON export/import and ODS (spreadsheet) export, both generated in the browser.
- Offline-capable installable PWA. Currently deploys as one static artifact to both GitHub Pages (under a subpath) and a self-hosted Docker image.
- Recurring costs — a bill that repeats every N months, every N days, or
every N weeks on a weekday, split across posts like any purchase. A cost is
anchored one of two ways:
calendarholds a fixed grid of due dates, so paying two months at once still leaves nothing due until the one after; a cost anchored to its last charge has no grid at all and can be charged any number of times in one cycle, its next due date always one cycle after whichever charge was most recent — a phone plan that recharges early when its data runs out is the case this exists for. Each due date on the calendar model is a projected occurrence the owner confirms into a real purchase; a recurring cost can also be tagged onto a purchase, or created from one, while it is being entered, rather than only from Settings. The month view shows what is still expected alongside a second, projected balance per post, so a known bill is visible before it is paid without touching the reconciled figure a bank statement is checked against.
Terminology: an envelope is called a post. A finance plan is a purchase spread across months. An override is a one-month exception to a post's allocation. A recurring cost is a bill expected to repeat; each due date it projects is an occurrence; confirming an occurrence turns it into a real purchase.
Undecided: nothing outstanding at the product level.
Brand Commitments
The product is called Budget 2.0. No logo, wordmark, or brand assets exist, and none have been commissioned.
Evidence on Hand
None, and none may be invented. This is a personal tool: there are no customers, testimonials, case studies, usage statistics, press, pricing, or third-party integrations. Any future surface must not manufacture them.
The only real content is the owner's own budget data, which never leaves their browser and is therefore never available as example material. Illustrative data must be visibly synthetic.
Product Principles
- Over-budget is always allowed. The app reports the truth and never blocks, clamps, or hides overspending. A negative balance is a normal value.
- Changing an allocation must never destroy history. Adjusting what a post gets going forward leaves what it got before intact and still visible.
- Splitting a purchase across posts must stay easy. It is a routine act, not an advanced feature, and must not be buried behind extra steps.
- The data stays portable and in the owner's hands. Export is always available and always complete; nothing traps a budget inside the app.
- Entry speed is a feature. Recording a month of spending is the most repeated act in the product, and friction there is the reason spreadsheets get abandoned.
Accessibility & Inclusion
No condition-specific requirement was established by the owner. The existing implementation holds itself to WCAG AA contrast, visible keyboard focus, and respecting reduced-motion preferences; keyboard-first entry is a stated goal of the fast-entry flow rather than only an accessibility accommodation.