bus-loans — loan register, amortization, and posting outputs (SDD)
bus-loans — loan register, amortization, and posting outputs
Introduction and Overview
Bus Loans maintains loan master data and event logs as schema-validated repository data, generates amortization schedules, and produces posting suggestions for loan activity.
Requirements
FR-LOAN-001 Loan registry. The module MUST store loan contracts and events as schema-validated datasets with stable identifiers. Acceptance criteria: loan rows validate against schemas and reference counterparties and accounts.
FR-LOAN-002 Amortization outputs. The module MUST generate amortization schedules and posting outputs for the journal. Acceptance criteria: outputs reference the originating loan identifiers and vouchers.
NFR-LOAN-001 Auditability. Loan corrections MUST be append-only and traceable to original records. Acceptance criteria: schedules and events remain reviewable in repository history.
NFR-LOAN-002 Path exposure via Go library. The module MUST expose a Go library API that returns the workspace-relative path(s) to its owned data file(s) (loan register, event datasets, and their schemas). Other modules that need read-only access to loan raw file(s) MUST obtain the path(s) from this module’s library, not by hardcoding file names. The API MUST be designed so that future dynamic path configuration can be supported without breaking consumers. Acceptance criteria: the library provides path accessor(s) for the loan datasets; consumers use these accessors for read-only access; no consumer hardcodes loan file names outside this module.
System Architecture
Bus Loans owns the loan datasets and generates schedules and posting suggestions. It relies on bus accounts and bus entities for reference data and integrates with the journal and reporting workflows.
Key Decisions
KD-LOAN-001 Loan records are repository data. Loan contracts, events, and schedules are stored as datasets for auditability and exportability.
KD-LOAN-002 Path exposure for read-only consumption. The module exposes path accessors in its Go library so that other modules can resolve the location of loan datasets for read-only access. Write access and all loan business logic remain in this module.
Component Design and Interfaces
Interface IF-LOAN-001 (module CLI). The module exposes bus loans with subcommands init, add, event, and amortize and follows BusDK CLI conventions for deterministic output and diagnostics.
The init command creates the baseline loan register and event datasets and schemas when they are absent. If all owned loan datasets and schemas already exist and are consistent, init prints a warning to standard error and exits 0 without modifying anything. If the data exists only partially, init fails with a clear error to standard error, does not write any file, and exits non-zero (see bus-init FR-INIT-004).
The add command records a new loan contract in the loan register. It accepts --loan-id <id>, --counterparty <entity-id>, --principal <amount>, --start-date <YYYY-MM-DD>, --maturity-date <YYYY-MM-DD>, --interest-rate <percent>, --principal-account <account-id>, --interest-account <account-id>, and --cash-account <account-id> as required parameters, and it accepts --name <text>, --rate-type <fixed|variable>, --payment-frequency <monthly|quarterly|yearly>, and --desc <text> as optional parameters. When --rate-type is omitted, the rate is treated as fixed; when --payment-frequency is omitted, the schedule assumes monthly payments.
The event command appends an event record that references the loan contract and produces posting output when applicable. It accepts --loan-id <id>, --date <YYYY-MM-DD>, --type <disbursement|repayment|interest|fee|adjustment>, and --amount <amount> as required parameters, and it accepts --principal <amount>, --interest <amount>, --fees <amount>, --desc <text>, --voucher <voucher-id>, and --cash-account <account-id> as optional parameters. When allocation fields are omitted, the module derives allocation deterministically from the loan contract terms.
The amortize command generates amortization schedules and posting output for a specific period. It accepts --period <period> as a required parameter and --loan-id <id> and --post-date <YYYY-MM-DD> as optional parameters. When --loan-id is omitted, the command scopes to all loans; when --post-date is omitted, the posting date is the last date of the selected period.
Interface IF-LOAN-002 (path accessors, Go library). The module exposes Go library functions that return the workspace-relative path(s) to its owned data file(s) (loan register and event datasets and their schemas). Given a workspace root path, the library returns the path(s); resolution MUST allow future override from workspace or data package configuration. Other modules use these accessors for read-only access only; all writes and loan logic remain in this module.
Usage examples:
bus loans init
bus loans add --loan-id LN-100 --counterparty ACME-BANK --principal 250000 --start-date 2026-01-01 --maturity-date 2031-01-01 --interest-rate 4.5 --principal-account "Long-term loans" --interest-account "Interest expense" --cash-account "Bank"
bus loans event --loan-id LN-100 --date 2026-01-01 --type disbursement --amount 250000 --voucher V-2026-0001
bus loans amortize --period 2026-02
Data Design
The module reads and writes loan register and event datasets in the loans area, with JSON Table Schemas stored beside each CSV dataset. Master data owned by this module is stored in the workspace root only; the module does not create or use a loans/ or other subdirectory for its datasets and schemas.
Other modules that need read-only access to loan datasets MUST obtain the path(s) from this module’s Go library (IF-LOAN-002). All writes and loan-domain logic remain in this module.
Assumptions and Dependencies
Bus Loans depends on reference data from bus accounts and bus entities and on the workspace layout and schema conventions. Missing datasets or schemas result in deterministic diagnostics.
Security Considerations
Loan data is repository data and should be protected by repository access controls. Evidence references remain intact for auditability.
Observability and Logging
Command results are written to standard output, and diagnostics are written to standard error with deterministic references to dataset paths and identifiers.
Error Handling and Resilience
Invalid usage exits with a non-zero status and a concise usage error. Schema or reference violations exit non-zero without modifying datasets.
Testing Strategy
Unit tests cover loan validation and amortization logic, and command-level tests exercise init, add, event, and amortize against fixture workspaces.
Deployment and Operations
Not Applicable. The module ships as a BusDK CLI component and relies on the standard workspace layout.
Migration/Rollout
Not Applicable. Schema evolution is handled through the standard schema migration workflow for workspace datasets.
Risks
Not Applicable. Module-specific risks are not enumerated beyond the general need for deterministic loan data handling.
Suggested extensions (loan-payment classifier from bank rows)
The module does not classify arbitrary bank rows into principal vs interest. Financing-style bank payments (lenders, installments) are today handled via manual split or custom code. A suggested extension, implemented in bus-journal or by integration with this module, is loan-profile–aware handling so a bank payment produces deterministic posting proposals with principal vs interest/fee split (lender payment profiles, fixed or schedule-based split, or “all to liability” fallback). When adopted, the bus-journal and/or bus-loans SDD will specify the new interfaces and behavior, and module docs will document profiles, split policy, and proposal output. See the loan-payment classifier suggested capability in the bus-journal SDD.
Glossary and Terminology
Loan event: an append-only record of loan activity such as disbursement or repayment.
Amortization schedule: derived records allocating principal and interest over time.