Day 5: Views Are the New Reports

views queries declarative architecture

Reports are static. Exports are one-time. Dashboards are hard-coded. We needed something better: Viewsβ€”first-class primitives that ask questions of the ledger declaratively, repeatably, and safely.

The Insight

Yesterday we defined financial truth. Today we asked: How do you ask questions of that truth?

Traditional finance apps give you canned reports. "Spending by Category". "Income vs Expenses". "Monthly Summary". These are features, not primitives. They can't be customized, combined, or shared.

We realized: reports, dashboards, and exports are all just Views. Different ways of asking the same underlying question: "Show me transactions that match these filters, grouped this way, sorted this way."

Why Views Are Primitives

A View is not code. It's a declarative description of a financial perspective:

{
  name: "Spending by Category",
  type: "report",
  filters: [
    { field: "amount", operator: "lt", value: 0 },
    { field: "type", operator: "neq", value: "transfer" }
  ],
  grouping: { field: "categoryId" },
  sorting: [{ field: "amount", direction: "desc" }],
  columns: ["category", "amount"]
}

This is pure data. No callbacks. No code. No side effects. It describes what to query, not how to execute.

The View Primitive

Every View contains these fields:

Core Fields

name β€” Human-readable identifier
type β€” ledger | report | dashboard | custom
filters β€” Array of field/operator/value conditions
grouping β€” How to aggregate (category, account, month, type)
sorting β€” Order of results
columns β€” What to display

The QueryEngine

Views don't execute themselves. The QueryEngine takes a View definition and returns results:

1. Reads ONLY from LedgerService (no direct repo access)

2. Has NO side effects (pure function)

3. Returns DETERMINISTIC results (same input = same output)

4. Can be called at any time without changing data

This separation is crucial. Views describe intent. The QueryEngine executes intent against financial truth. Neither stores derived results.

Filter Operators

We defined a complete set of filter operators:

eq       // equals
neq      // not equals
gt, gte  // greater than (or equal)
lt, lte  // less than (or equal)
in, nin  // in array / not in array
between  // between two values (inclusive)
contains // string contains
isNull   // is null
isNotNull// is not null

These cover every use case we could imagine:

  • date between [start, end] β€” Date range queries
  • amount lt 0 β€” Expenses only
  • accountId in [a, b, c] β€” Multiple accounts
  • reconciledAt isNull β€” Unreconciled transactions

Built-in Views

Every workspace gets seeded with canonical Views:

πŸ“‹

All Transactions

Complete ledger sorted by date

πŸ“Š

Spending by Category

Expenses grouped by category

βš–οΈ

Income vs Expenses

Compare total inflow vs outflow

πŸ’°

Account Balances

Dashboard of all accounts

β­•

Unreconciled Transactions

Transactions that need verification

πŸ“…

Monthly Summary

Totals by month

These are NOT special cases. They're just View definitions that happen to be pre-created. They use the same QueryEngine as custom views. You can create identical views yourself.

Why This Enables Future Features

Because Views are pure data, they enable:

AI Integration

An AI can read a View definition, understand what it does, and suggest modifications. "Add a date filter for last 30 days" becomes a simple JSON update.

Shareable Links

A View can be serialized to a URL. Share "Spending by Category for December" as a link, not a file export.

Cross-Workspace Queries

Same View definition can run against different workspaces. Compare personal and business finances with the same query.

Template Library

Save and share View templates. "Best Views for Freelancers" becomes a collection of JSON objects.

What We Didn't Build

Constraints are features:

  • No charts β€” Tables only. Charts come later.
  • No mutations β€” Views are READ-ONLY. They don't change data.
  • No stored results β€” Views don't cache. They always reflect current truth.
  • No rules engine β€” Views query; they don't transform.

What We Built Today

  • View Primitive β€” Fully typed schema with filters, grouping, sorting, columns
  • Filter System β€” 12 operators covering all comparison types
  • QueryEngine β€” Pure, read-only executor against LedgerService
  • Built-in Views β€” 6 canonical views seeded for every workspace
  • Views UI β€” List, select, execute, render with table output
  • Create/Edit Views β€” Full CRUD with filter builder UI

Views are primitives, not features. They replace reports, dashboards, and exports with a single, composable abstraction. They describe financial questions declaratively. They execute deterministically against the ledger. They can be saved, shared, and re-run.

This is how you build for AI and sharing: make your queries pure data, not code.

β€” The Accelerate Finance Team