Day 8: Links Over Exports

sharing privacy views local-first

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