FAQ — technical
Q: How do I add a new posting rule?
A: Add a function to services/posting.py — takes a PostingInput, returns a
list of PostingLines. Register it in the dispatch dict at the bottom.
Balance invariant is enforced at insert; write a unit test that shapes an
input and asserts ΣDR = ΣCR.
Q: How do I add a new source (upstream broker)?
A: Four pieces:
brokers/<name>.py— HTTP client (auth, pagination, error retries).services/<name>_importer.py— map raw row →TransactionPayload.services/classify.py— add aclassify_<name>function.services/<name>_sync.py— loop customers, call the broker, callimport_<name>_batch, optionally recost.
Also: widen the source CHECK in a migration if the source name is new.
Q: How do I add a new endpoint?
A: Add a route to api/jobs.py (jobs) or a new module (reports). Match the
existing conventions: Depends(require_ledger_token) for reads,
Depends(require_admin_token) for writes, response_model=<Pydantic> always.
Q: Why is the ledger cost-only? Why not mark to market on the GL?
A: Correctness — MTM revenue hasn't crystallized, and posting it would breach
the trial balance if credited to an income account. Simplicity — the ledger's
job is to prove where the money is, not to speculate on unrealized value. MTM
lives on /v1/india/nav (reporting only).
Q: Why 1300 GlomoPay FX Receivable, not immediate revenue?
A: The FX-spread is earned when the order is paid but SETTLED when GlomoPay
pays out the merchant batch. 1300 holds the earned-but-unpaid margin; the
fx_spread_settle posting clears it to 1010.
Q: What's on the CoA that isn't posting?
A: 2110 Sec Liab - Bonds is dormant (no bonds ingested yet). 4020 Custody Fee Revenue is seeded but not yet firing.
Q: What if GlomoPay is unreachable?
A: Every India endpoint degrades gracefully:
- Treasury returns
configured=falsewith a warning. - Exceptions returns an empty snapshot with a warning.
- FX-margin returns
realized=Nonefor the priced remittances (still shows the assumed accrual). - Sync jobs skip the customer and report
customers_failedin the response.
Q: What if ViewTrade is unreachable?
A: NAV shows status=error per-customer with the error message. Ledger-recon
and Holdings-recon do the same. The scheduled recon check surfaces a warn
on the next cycle.
Q: How do I know the trial balance balances?
A: GET /v1/firm/trial_balance sums debit and credit per account; the
Category-A trial_balance_zero check runs on every recon cycle and turns
fail if it doesn't.
Q: How do I run a one-off sync for a single customer?
A: Pass customer_ids: ["cust-x"] in any sync job's request body.
Q: How do I reverse a transaction?
A:
curl -X POST -H "X-Ledger-Admin-Token: <TOKEN>" \
http://localhost:8078/v1/transactions/{txn_id}/reverse
Idempotent — a second call returns the existing reversal.
Q: What if I need to re-cost historical transactions?
A: recosted_at IS NULL is the filter. Set the column back to NULL manually
for the affected txns, then run POST /v1/jobs/recost.