HALO CRM research
Real and working
Domain 5 · money · ~2,500 LOC

Payment log

Merges four sources into one reconciliation ledger where some rows are derived (keyed by sourceKey) and others stored; confirmations attach to either, and soft-deletes stay findable under a Deleted status so they can be undone.

What it is and how it feeds the rest

Mechanically

Merges four sources into one reconciliation ledger where some rows are derived (keyed by sourceKey) and others stored; confirmations attach to either, and soft-deletes stay findable under a Deleted status so they can be undone.

How it connects

The settlement view over both invoicing domains. Largest single page component at 871 LOC.

Pages

  • src/pages/PaymentLog.tsx

Components

  • src/components/payment-log/

Convex modules

  • paymentLog.ts

Tables

  • paymentLogEntries
  • paymentLogConfirmations
  • recurringExpenses

Findings that touch this domain

high All money is float64; 2 rounding calls in 11,274 LOC, none in invoicing/referrals/payroll

convex/schema.ts:103,132,153,393,703

high No append-only history in 56 tables; customStatusHistory is customs-only

convex/schema.ts

The decision — what we do here

TRANSPLANT — his 871-LOC hand-rolled ledger → real double-entry engine. Preserve every existing operator capability; keep or replace the UI based on the simplest complete implementation. Highest-value block.

Repos we analyzed for this domain

LIFT flash-oss/medici

Double-entry ledger engine (Node/TS). Port behind PaymentLog; earnings = liability not revenue.

STUDY pgr0ss/pgledger

Postgres double-entry model — study, reimplement the account/journal shape in Convex.

WRAP formancehq/ledger

Programmable ledger as a service if the money core outgrows Convex.

LIFT dinerojs/dinero.js

Integer minor units + allocate() — kills the float/rounding bug across all money math.

LIFT = copy the code into the fork · WRAP = run underneath as a service · STUDY = architecture only. Verdicts from the OFM sourcing campaign.

Open questions

Research priority for this domain is medium. Agent findings splice in below this line and survive regeneration.