Skip to content
Docs

Command palette

Jump to a page or search the docs.

Changelog

Loan

How a car's financing (M-Financiamento) keeps its balance as an append-only history, books interest and fees to the ledger, never counts principal as an expense, and opens or edits a Loan from the app.

Markdown

What it does

A Loan finances one car (RF07, US07). The loan row holds the fixed terms: lender, amount financed (principal_minor), currency, rate and term. What is still owed is the ★ loan_snapshot series, and what the Loan costs is ★ ledger_entry rows of kind loan_interest and loan_fee, which count in total cost (TCO). Principal is never an expense (RN05): what was repaid is only the amount financed minus the latest balance, which builds equity.

A car shows its newest Loan, the last one recorded. M-Compra opens one from the amount financed (Acquisition); M-Financiamento opens one for a car without a balance owed.

Procedures

ProcedureWhoFailures
loan.get { vehicleId }Members of the OrganizationNOT_FOUND (car)
loan.create { id, vehicleId, principalMinor, startDate, lender?, rate?, termMonths? }Members of the OrganizationINPUT_VALIDATION, NOT_FOUND (car), BAD_REQUEST (not in the garage, start in the future), CONFLICT (a balance owed, id)
loan.updateTerms { loanId, lender, rate, termMonths }Members of the OrganizationINPUT_VALIDATION, NOT_FOUND (Loan)
loan.updateBalance { id, loanId, balanceMinor, asOf, interestMinor?, feesMinor? }Members of the OrganizationINPUT_VALIDATION, NOT_FOUND (Loan), BAD_REQUEST (car not in the garage, date before the start or in the future), CONFLICT (id)

Each answers the car and its newest Loan as loan.get does: the latest balance and its date, the history (oldest first, at most 60), principal paid, interest and fees (as they stand after corrections, since the start), and the payments made. Payments are the monthly payment days reached from the start to the latest balance, at most the term ("22/48").

A rate is basis points of its period: { bp: 690, period: "year" } is "6.9% APR", { bp: 119, period: "month" } is "1,19% a.m.". The app picks the period the market quotes (a month in Brazil, a year elsewhere) and the owner can switch it.

Update balance

loan.updateBalance writes a new snapshot and, when entered, the interest and fees paid since the last update as entries dated the balance's date in the car's open Ownership Period. A backdated balance joins the history in date order; the latest balance is the newest date's. A zero balance pays the Loan off, after which a new one can be opened.

Offline and idempotency (RNF04)

The client generates the Loan's id and the snapshot's id. Sending one again answers the Loan as it stands and writes nothing more; an id that names another car's Loan or another Loan's snapshot is CONFLICT.

Data and isolation

loan has row-level security by Active Organization and only its terms are updatable; loan_snapshot and ledger_entry are append-only for every role. No audit_log event is written: the ★ rows are the trail, and amounts never go to logs (RNF07).

App

M-Financiamento (screen-M-Financiamento, route /loan/[vehicleId]) shows the balance in negative with its history line, principal with payments made, interest and fees, the rate, the RN05 note and "Update balance" (atualizar-saldo). The More menu edits the terms, or opens a new Loan once one is paid off; a car without a Loan offers Add loan. The vehicle profile's Loan balance card opens it. autofolio://dev/M-Financiamento opens the seeded M3.

Key files

Edit on GitHubDocumentation is in English.

We use essential cookies to make our app work. With your consent, we also use optional cookies to improve your experience. Read our Cookie Policy and Privacy Policy.