An append-only ledger and a rollup.

Ledger

AuditEntry is a ledger. The pay transition appends a row, and that row stays. AccountTotal is a rollup over paid invoices, summed by customer. Nothing writes the rollup. An update or a delete of a ledger row is query/ledger-mutation.

app ledgers "Ledgers" {}

entity Invoice {
  customer: text
  total:    money USD
  status:   enum draft, sent, paid

  workflow {
    initial Open
    states Open, Paid
    terminal Paid

    pay: Open -> Paid {
      do append AuditEntry { actor: customer, reason: "paid" }
    }
  }
}

entity AuditEntry ledger {
  actor:  text
  reason: text
}

entity AccountTotal rollup over Invoice sum total by customer where status == "paid"