Sharing financial data is a core capability, but traditional exports are broken. Today we built a sharing system that prioritizes links over exports, scoping over exposure, and privacy over convenience.
Why Sharing Matters
Personal finance is rarely personal. We share with partners for household budgeting, accountants for tax preparation, lenders for loan applications, and ourselves across devices.
Traditional exports (CSV, PDF) are problematic:
- No control after export β Once sent, the file lives forever
- All or nothing β Hard to share just the relevant subset
- Static snapshots β Outdated the moment they're created
- Manual redaction β Error-prone and tedious
Links solve these problems. A link can be scoped, time-limited, and revoked. The viewer sees exactly what you want them to see, nothing more.
Design Decision: Snapshot Mode
When creating a shared view, we faced a choice between live mode (link reflects current view) and snapshot mode (link captures the view at share time). We chose snapshot mode.
Predictability
When you share something, you know exactly what you're sharing. Live mode could surprise you if the underlying view changes.
Safety
Changing a view shouldn't accidentally expose more data to an existing share. Each share is a deliberate act with explicit scope.
Auditability
The share record captures what was shared, when, and with what constraints. No ambiguity about what a link revealed.
The tradeoff is that updating a share requires creating a new one. We accept this because sharing should be an intentional action, not an ambient state.
Scope Constraints: Data Minimization
Every share includes explicit scope constraints:
// Required dateRange // Limits the temporal window // Optional Allowlists allowedAccounts // Limits which accounts included allowedCategories// Limits which categories included // Redaction Options excludeTransfers // Hide internal money movements hideMemos // Redact transaction descriptions hidePayees // Anonymize who you paid hideAccountNames // Replace with generic labels
These constraints are applied during payload generation, not just in the UI. The share payload only contains the scoped, filtered, potentially anonymized data. Raw workspace data never leaves the local database.
Privacy Model: What Gets Shared?
The SharedViewPayload is carefully curated:
Included
- Share title and viewer message
- View configuration (type, columns)
- Pre-computed, scoped results
- Summary statistics
Never Included
- Workspace ID or name
- Internal account/category IDs
- Data outside scoped range
- Raw workspace database
This is the principle of data minimization: share only what's necessary for the recipient to see what you want them to see.
Local-First Sharing: Offline Bundles
Our local-first philosophy creates an interesting challenge: how do you share without a server?
Edge Publishing (when available)
Store the payload in a KV store at the edge, serve via /s/[shareId] route. Fast, simple URLs.
Offline Bundles
Embed the entire payload in the URL hash or a downloadable JSON file. Works without any server infrastructure. Self-contained and permanent.
Offline bundles have a beautiful property: they're self-contained. The recipient can view the share even if our servers disappear. The data is in the link itself.
Revocation and Expiry
Every share can have automatic expiration or immediate manual revocation:
- Expiration β Automatic deactivation after N days
- Revocation β Immediate manual deactivation
- Clear feedback β Expired links show "unavailable" with no data rendered
For offline bundles, expiration is checked client-side. A revoked bundle can still be opened if someone saved it, but the app warns about expiration. This is a tradeoff of offline-first: we can't reach into someone's downloaded file to delete it.
Security Guardrails
Shared views are read-only by design:
// The viewing interface has: β No edit capabilities β No mutation endpoints β No access to underlying workspace β Only pre-computed payload // Share ID security: format: nanoid(21) // Cryptographically random guessable: false // No information leakage validated: true // Malformed IDs rejected early
The Share Dialog: Explicit Privacy
The sharing UI makes privacy explicit, not hidden in advanced settings:
1. Select a view to share
2. Configure scope (date range, anonymization)
3. See summary of what will be shared
4. Create share with full awareness of exposure
What We Learned
- Sharing is a feature, not a side effect β It deserves its own primitive, not just an export function
- Privacy requires explicit design β Default to minimal exposure, require intentional opt-in for more
- Local-first doesn't mean isolated β You can share without servers by putting data in the link
- Revocation matters β The ability to take back a share is as important as creating one
What's Next
With views, rules, and sharing in place, we have a complete financial management system. The foundation is solid:
- LedgerService as the source of financial truth
- QueryEngine for read-only view execution
- Rules Engine for controlled automation
- Shareable views for collaboration
Links over exports isn't just a technical choiceβit's a philosophy. Your financial data is yours. When you share it, you should control exactly what gets shared, for how long, and with whom.
Traditional exports hand over a copy forever. Links let you share access, not ownership.
β The Accelerate Finance Team