Add server-persisted entry drafts (snap-and-finish-later workflow) #21
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Let users save a partial entry — expense, income, or asset purchase — and complete it later, with the date and BTC/fiat price locked at the moment of capture rather than at submission time. The workflow people actually use: "I bought groceries for €40 just now but I don't have time to fill in the description, account, etc. — let me snap a draft and finish it tonight." Optionally attach a receipt photo at the same time (see #11 for attachments).
The webapp already has a localStorage-only draft notion. That's fragile (lost on browser clear, doesn't cross devices, can't be resumed in the LNbits ext UI). This issue proposes promoting drafts to a real server-persisted resource.
Why the price snapshot matters
Without snapshotting at capture time, sats cost basis drifts to whenever the user happens to finish the draft. Example: user spends €40 at lunch when 1 BTC = €100k (so €40 ≈ 40,000 sats), opens the draft that evening when 1 BTC = €90k (so €40 ≈ 44,444 sats), and the submission records the wrong sats equivalent. That ~10% drift is small for groceries, large for a 24-hour delay during volatility, and huge over multi-day deferrals. The cost-basis-at-the-time-of-the-event is the auditable truth; the cost-basis-at-the-time-the-user-finished-typing is not.
So the draft needs to capture at minimum:
captured_at— wall-clock timestamp (server side, immutable).btc_price_snapshot— sats-per-fiat-unit, per supported fiat currency. Pulled from the same exchange-rate source the entry endpoints use.Everything else (description, account, exact amount) is filled in optionally and edited freely until the user submits.
Proposed data model
New table in the libra extension DB (Fava holds finalized entries; drafts are pre-Fava):
A separate
entry_draftstable mirrors the per-table pattern already inmigrations.py.Proposed endpoints
POST/api/v1/draftsentry_typeandfiat_currency; server fillscaptured_atandbtc_price_snapshot.GET/api/v1/draftsGET/api/v1/drafts/{id}PATCH/api/v1/drafts/{id}captured_atandbtc_price_snapshotstay locked.DELETE/api/v1/drafts/{id}POST/api/v1/drafts/{id}/submitentry_type, forward to the matching/entries/expense//entries/income//entries/assetflow using the draft's captured price, then delete the draft on success.Auth:
require_invoice_key(same as the entry endpoints). Drafts are per-user; one user can't see or touch another user's drafts.Proposed frontend (webapp and LNbits ext)
PATCHthe draft (or on blur / dialog close). Saves are a happy path that don't lock the UI.Composition with #11 (attachments)
Once #11 lands, drafts get an
attachments: list[str]field that's populated via the same image upload flow as final entries. On submit, the attachments carry over into the finalized entry. Until #11 lands, drafts are text-only and the user adds the receipt photo at submission time on a final entry — degraded but workable.The dependency is one-directional: #11 doesn't need drafts; drafts works without #11 (just no photo). They ship independently and compose.
Open questions
(currency, price)pair at creation. If the user changes their mind about which currency the transaction was in after capture, should they have to discard and start a new draft? Probably yes — changing currency mid-draft invalidates the snapshot's whole point./submitendpoint accept payload overrides that take precedence over the stored draft fields? Probably no — that obscures the "draft as snapshot" mental model. If a user wants different values they should PATCH first./submitand becomes a pending entry.Severity / priority
Quality-of-life and correctness — drafts is the difference between accurate same-day expense tracking and "I'll get to it later" entropy. The price snapshot in particular addresses a real correctness bug for any non-instant submission. Cost is moderate: new table, ~5 endpoints, a UI section on Record, dialog plumbing for Save Draft / Resume.
Related: #11 (receipt attachments — drafts will use the same attachment mechanism), #20 (asset purchase entry — third entry type that needs draft support).