CIVICA/i — HOA / Community Association Management

SteelFrame X application operation manual  ·  ← back to Operation Manuals  ·  Sign On

CIVICA/i is a homeowner-association (HOA) / community-association management application: association and unit inventory, owner records, a recurring monthly assessment (dues) charge run and one-off special assessments, an owner receivables ledger, daily cash-receipt application, period-end delinquency aging with late fees and a lien ladder, code-violation and fine posting, reserve-fund transfers, and a balanced GL feed. The bulk of the application is ILE RPG driving keyed physical files (with one COBOL AR control report and one SQLRPGLE GL post over a DB2 for i table); the three CL job cycles orchestrate the batch programs. This manual is the reference for the operator who runs the online screens and the periodic cycles, and for the developer maintaining the application. It is grounded entirely in the committed source (hoa-app/src/sources.mjs, src/seed.mjs, and the test/cv_build.mjs / cv_cycle.mjs drivers). Everything runs in library CIVICA.

Contents

A. Overview & Architecture ↑ top

A.1 What it does

CIVICA/i manages the receivables life of a community association:

A.2 One-layer RPG-over-keyed-files design

Unlike a SQL-PL-centred application, CIVICA/i keeps its business logic in the RPG programs themselves, operating directly on keyed DDS physical files. The design has a few deliberate properties:

The benefit for operations: each cycle is a small, self-contained program driven from a CL wrapper, and every money movement lands both on the owner account (CVACCT.ABAL) and in the history trail, so a run's effect is fully reconstructable.

A.3 Component & flow

  SETUP/SEED             ONLINE                 BATCH (CL job cycles)
  ----------             ------                 ---------------------
  CVSETUP  (CRTxxx)      CVMENU (5250)          CVMONTH --> CVCHRUN   (assessment charge)
  CVREFLD  (seed)          opt 1 -> CVUNTIQ     CVDAILY --> CVCASHAP  (cash application)
                           opt 2 -> CVLEDIQ     CVPERIOD -> CVDELQ    (aging+fee+lien)
                                                          -> CVVFINE  (violation fines)
                                                          -> CVRESVTR (reserve transfer)
                                                          -> CVGLPST  (GL post)
                                                          -> CVARRPT  (AR control report)
            \                                  /
             \                                /
              v                              v
     CVACCT.ABAL  <-- raised by charge/fee/fine, lowered by cash --  the AR invariant
        |   \
        |    +--> CVLEDG  (owner AR open items: A/S/L/F charges, CHGOPEN reduced by cash)
        |    +--> CVHIST  (durable audit trail, one row per posting, derived key)
        +------> CVGLDIST (balanced DR/CR GL distribution)   CVRESV/CVRESVH (reserve)

A single posting event (say, the monthly charge run) flows: CVMONTH calls CVCHRUN → it walks each active assessment schedule, expands *ALL to the association's occupied units via CVUNTLF → writes a CVLEDG open-item and a CVHIST row (keyed off account+assessment id) → raises CVACCT.ABAL by the charge. The date each program processes for is a hard-coded period constant in the source (2026-09 for the charge run, 2026-09-25 for the period runs) rather than a control table — see the honest note in C.

A.4 Object inventory

ObjectTypeRole
CVASSOCPFAssociation (community) master.
CVUNITPFUnit master (composite key ASSOCID+UNITNO).
CVUNTLFLFUnits keyed by ASSOCID (assessment-expansion path).
CVOWNERPFOwner master.
CVASMTPFAssessment schedule (regular dues / special levy).
CVLEDGPFOwner AR open items (the receivables ledger).
CVLEDLFLFLedger keyed by CHGDUE (due-date aging path).
CVACCTPFUnit account: running ABAL + lien status.
CVRCPTPFCash receipts.
CVVIOLPFCode violations.
CVARCPFArchitectural requests.
CVRESVPFReserve fund (running RBAL + funding %).
CVRESVHPFReserve-transfer history.
CVHISTPFDurable audit trail (all posting programs).
CVGLDISTSQL tableGL distribution (DR/CR), created by RUNSQLSTM; index CVGLDACC.
CVUNTD / CVLEDD / CVMENUDDSPFUnit inquiry / ledger-subfile inquiry / menu display files.
CVAGEPPRTFDelinquency aging printer file.
CVREFLDRPGLEReference-data seeder.
CVCHRUNRPGLEMonthly assessment charge run.
CVCASHAPRPGLEDaily cash-receipt application.
CVDELQRPGLEPeriod aging + late fee + lien status.
CVVFINERPGLEPeriod violation-fine posting.
CVRESVTRRPGLEPeriod reserve-fund transfer.
CVGLPSTSQLRPGLEPeriod GL post (balanced DR/CR).
CVUNTIQ / CVLEDIQ / CVMENURPGLEUnit inquiry / ledger inquiry / menu drivers.
CVARRPTCBLLEILE COBOL AR control report.
CVSETUPCLPCreate every object / compile every program.
CVDAILY / CVMONTH / CVPERIODCLPThe three job-cycle wrappers.

The full object catalogue is 14 physical files + 2 logical files + 3 display files + 1 printer file + 1 SQL table (+ its index), driven by 10 RPG programs, 1 COBOL program and 4 CL programs, plus 1 seeder. Sections D and F expand each.

B. Online Transactions & Screens ↑ top

B.1 The command/entry line

CIVICA/i has no CICS transaction identifiers. On IBM i, each program is reached by name from a 5250 command-entry line (or a JOBQ/scheduler for the batch jobs). The operator equivalent of "type a transid and Enter" is "type a CALL command and Enter". Before invoking anything the job's library list must include CIVICA — the tested jobs run with LIBL = QSYS QGPL CIVICA QTEMP and CURLIB = CIVICA (each CL wrapper also issues its own ADDLIBLE LIB(CIVICA)).

To do thisType on the command line
Open the main menu (routes to the two inquiries)CALL CIVICA/CVMENU
Unit / owner inquiry directlyCALL CIVICA/CVUNTIQ
Owner-ledger inquiry (subfile) directlyCALL CIVICA/CVLEDIQ
Run the daily cash-application cycleCALL CIVICA/CVDAILY (or SBMJOB it)
Run the monthly assessment charge cycleCALL CIVICA/CVMONTH
Run the period-end cycle (aging→fines→reserve→GL→AR)CALL CIVICA/CVPERIOD
Rebuild all objects / recompileCALL CIVICA/CVSETUP then CALL CIVICA/CVREFLD

The batch drivers and the CL wrappers take no CALL parameters. Only the three inquiry programs (CVMENU, CVUNTIQ, CVLEDIQ) are interactive; the batch programs run to completion and each DSPLYs a one-line result banner (e.g. CVCHRUN CHARGED=8 SKIP=...).

B.2 The main menu & inquiry screens

Three interactive programs share the display files CVMENUD, CVUNTD and CVLEDD. All three exit on F3 (DDS CA03).

Main menu — CVMENU / CVMENUD

A two-option menu. Key 1 to call the unit/owner inquiry, 2 for the owner-ledger inquiry; any other non-blank option shows Invalid option.. Control returns here when the called inquiry exits.

CIVICA/i Main Menu 1. Unit / Owner Inquiry 2. Owner Ledger Inquiry Option . . . . : _ F3=Exit Enter=Select

Unit / owner inquiry — CVUNTIQ / CVUNTD (plain screen)

A non-subfile inquiry. The operator keys an association and a unit and presses Enter; the program CHAINs the unit (composite key ASSOCID+UNITNO), then the owner (CVOWNER on OWNERID) and the account (CVACCT on ACCTNO = ASSOCID || UNITNO), and shows the address, unit status, owner id/name, account balance (%editc(abal:'K')) and lien status. The status line message walks Unit not found.Unit found.Unit and account found. as each CHAIN succeeds.

Unit / Owner Inquiry - CIVICA/i Association . : A00001 Unit . . . . . : 0101 Address . . . : 1 MEADOWBROOK LANE #101 Status . . . . : O Owner ID . . . : W00001 Owner name . . : ALDEN, MARIA Account balance: 0.00 Lien status . : Unit and account found. F3=Exit Enter=Inquire

Owner-ledger inquiry — CVLEDIQ / CVLEDD (subfile screen)

The app's subfile screen. The operator keys a 10-byte account number (ASSOCID || UNITNO); the program shows the owner name, account balance and lien status, then loads a subfile (DDS record LSFL under control record LCTL, SFLPAG(5) per page, SFLSIZ(20), ROLLUP/ROLLDOWN) of the account's charge/open-item history — one row per CVLEDG charge with its sequence, type, description, amount, open balance and aging bucket. The subfile is cleared and reloaded on every enquiry pass (the *IN31 discipline: write LCTL with SFLCLR on, reload, then display), so a fresh account's items appear immediately.

Owner Ledger Inquiry - CIVICA/i Account number: A000010103 Owner . . . . : CORELLI, ANNA Account balance: 650.00 Lien status . : Seq Ty Description Amount Open Age 1 A MONTHLY HOA DUES 250.00 250.00 0 2 S ROOF SPECIAL ASSESSMENT 400.00 400.00 0 F3=Exit Roll=Page Enter=Inquire

Subfile columns (LSFL)

FieldType (DDS)Shows
SSEQ5S,0 outputLedger charge sequence (CHGSEQ).
STYPE1A outputCharge type: A regular, S special, L late fee, F fine.
SDESC25A outputCharge description (CHGDESC).
SAMT12A outputCharge as raised (CHGAMT, edited).
SOPEN12A outputOutstanding open amount (CHGOPEN, edited).
SAGE1A outputAging bucket 0/1/2/3 (CHGAGE).
The inquiries are read-only. There is no online option to post a charge, apply cash, raise a fine or edit a balance from a screen — all money movement happens through the batch programs (section C). The screens are for lookup and reconciliation, not maintenance.

B.3 Controls & audit workflow (no four-eyes maker–checker)

Honest statement: CIVICA/i does not model a four-eyes maker–checker / separate-authorization workflow. There is no "one user posts, a second user approves" step: charges, cash, fees, fines and reserve transfers are all applied directly by the batch programs. The manual documents the control model the application does have:

In sum, the control posture is durable audit + derived-key idempotency + a strict balance invariant + a balanced GL, rather than an approval workflow.

C. Batch Jobs & the Periodic Cycle ↑ top

CIVICA/i's processing runs as three CL job cycles rather than one monolithic nightly job: a daily cycle (cash application), a monthly cycle (assessment charge run), and a period-end cycle (aging + late fees + lien status, violation fines, reserve transfer, GL post, AR report). Each CL wrapper is parameterless: it does ADDLIBLE LIB(CIVICA), calls its program(s), and sends a completion banner.

Honest statement on dates. Unlike a control-table-driven design, each CIVICA/i batch program carries its processing date as a hard-coded constant in the source: the charge run posts for period 20260901 (WPERDT/WDUEDT), and the period runs use run date 20260925 (WRUNDT); CVGLPST's batch is 202609. There is no LNCTL-style control row to advance between runs. To process a different period you change these constants in the source and recompile — the cycles are demonstrated against a single fixed 2026-09 period. This is a documented simplification of the sample, not an operator-facing date knob.

C.1 Full batch program set

Program (CL cycle)PurposeFiles touchedResult banner (DSPLY)Frequency
CVCHRUN
(CVMONTH)
Post regular dues to every occupied unit + special assessments; raise ABAL. CVASMT (U), CVUNIT/CVUNTLF (I), CVACCT (U), CVLEDG (WA), CVHIST (WA). CVCHRUN CHARGED=n SKIP=m Monthly.
CVCASHAP
(CVDAILY)
Apply each unapplied receipt to its nominated charge; lower ABAL. CVRCPT (U), CVLEDG (U), CVACCT (U), CVHIST (WA). CVCASHAP APPLIED=n SKIP=m Daily.
CVDELQ
(CVPERIOD)
Age open charges into buckets; assess 10%-of-open late fee; set lien status. CVLEDG (U), CVACCT (U), CVHIST (WA). CVDELQ B0=.. B1=.. B2=.. B3=.. FEES=n Period.
CVVFINE
(CVPERIOD)
Fine open violations past cure period; mark them FINED; raise ABAL. CVVIOL (U), CVLEDG (WA), CVACCT (U), CVHIST (WA). CVVFINE FINED=n SKIP=m Period.
CVRESVTR
(CVPERIOD)
Transfer RPCT% of each association's collected cash into its reserve. CVRESV (U), CVHIST (WA), CVRESVH (O). CVRESVTR XFER=n SKIP=m Period.
CVGLPST
(CVPERIOD)
Post balanced DR/CR GL rows for the period's charges/fees/fines (incremental). CVHIST (I); SQL CVGLDIST (insert/select). CVGLPST BATCH=202609 ROWS=n Period.
CVARRPT
(CVPERIOD)
ILE COBOL AR control report over the ledger (reconciliation totals). CVLEDG (sequential read). CVARRPT RAISED/OPEN/ITEMS/OVERDUE Period.

File I/O legend: I=input, U=update, O=output, WA=write/add (output-add). The CL cycles wire these together: CVDAILY→CVCASHAP; CVMONTH→CVCHRUN; CVPERIOD→CVDELQ→CVVFINE→CVRESVTR→CVGLPST→CVARRPT.

C.2 Daily / monthly / period detail

Monthly — CVMONTH / CVCHRUN

For every active assessment schedule (ASMTSTAT='A'): a *ALL schedule walks every occupied unit in the association via CVUNTLF (vacant units are skipped), posting one CVLEDG open-item (CHGTYPE 'A' regular / 'S' special) per target account, writing a CVHIST row, and raising CVACCT.ABAL by the charge. A single-unit special assessment targets just that unit's account. A special assessment's instalment counter (ASMTPOST) advances once per run and is capped at ASMTINST; a regular assessment (ASMTINST 0) has no ceiling.

Expected DSPLY against the seeded book (Meadowbrook dues to 3 occupied units +
roof special on 0103 + Harborview dues to 4 units = 8 charges over 7 accounts):
  CVCHRUN CHARGED=8 SKIP=0    8 charges posted; A000010103 gets 2 (regular + special)

Per-account charge totals: A000010101/0102 250.00; A000010103 650.00 (250 dues + 400 roof, two ledger rows); A000020201–0204 320.00 each. Each ABAL rises from 0 by exactly its total.

Daily — CVDAILY / CVCASHAP

For every receipt with RCSTAT='U' (unapplied): CHAIN the nominated charge (composite key ACCTNO+RCCHGSQ), take min(receipt amount, open), reduce CHGOPEN (fully-applied → CHGSTAT='P'), lower CVACCT.ABAL by the amount applied, write a CVHIST 'P' row (negative amount), and stamp the receipt 'A' (fully applied) or 'P' (part-applied). An over-payment applies only what is owed; the remainder stays unapplied.

Expected DSPLY (RC000001 pays A000010101 dues 250.00 in full;
RC000002 pays 150.00 of A000010102's 250.00 open):
  CVCASHAP APPLIED=2 SKIP=0   A000010101 -> 0.00; A000010102 250.00 -> 100.00

Period — CVPERIOD chain

Five programs run in order:

Expected DSPLY across the period chain (seeded book, run date 2026-09-25):
  CVDELQ B0=0 B1=7 B2=0 B3=0 FEES=6   7 open charges 24d overdue -> bucket 1; 6 accounts fee'd
  CVVFINE FINED=1 SKIP=1              V1 (24d>10 cure) fined; V2 (5d, in cure) skipped
  CVRESVTR XFER=1 SKIP=1             Meadowbrook 400.00 cash x 10% = 40.00; Harborview no cash
  CVGLPST BATCH=202609 ROWS=4       DR receivable + 3 CR revenue lines, balanced
  CVARRPT ITEMS 00015               8 charges + 6 late fees + 1 fine = 15 ledger rows

Late-fee results: A000010102 → 110.00, A000010103 → 715.00, and each Harborview account 320.00 → 352.00 (all lien 'D'). A000010101 was fully settled before the close, so it earns no fee and its lien clears to blank — then later carries a 75.00 violation fine (0 → 75).

C.3 Ordering & dependencies

D. Data Files (data dictionary) ↑ top

All files are in library CIVICA, grounded in the DDS/SQL source in hoa-app/src/sources.mjs. Dates are stored as signed numerics in YYYYMMDD form (8S 0); money is packed decimal (11P 2); the account key ACCTNO is ASSOCID || UNITNO (10A) by construction.

CVASSOC — Association master (K ASSOCID)

FieldTypeMeaning
ASSOCID6AAssociation id (key), e.g. A00001.
ANAME30AAssociation name.
AADDR / ACITY30A / 20AAddress / city.
AUNITS5S 0Unit count (informational).
ASTAT1AA active.

CVUNIT — Unit master (K ASSOCID, UNITNO)

FieldTypeMeaning
ASSOCID / UNITNO6A / 4AOwning association + unit number (composite key).
UADDR30AUnit address.
USQFT6S 0Square footage.
UTYPE1AUnit type (e.g. C condo, T townhouse).
OWNERID6ACurrent owner of record (one per unit; blank if vacant).
USTAT1AO owner-occupied, R rented, V vacant.

CVUNTLF is a logical over CVUNIT keyed on ASSOCID alone (non-unique) so the charge run walks a whole association's units.

CVOWNER — Owner master (K OWNERID)

FieldTypeMeaning
OWNERID6AOwner id (key), e.g. W00001.
ONAME30AOwner name.
OPHONE14APhone.
OMAIL1AMail-preference flag (Y/N).
OSTAT1AA active.

CVASMT — Assessment schedule (K ASSOCID, ASMTID)

FieldTypeMeaning
ASSOCID / ASMTID6A / 5S 0Association + schedule id (key).
ASMTUNIT4A*ALL = every occupied unit; otherwise a specific unit number.
ASMTTYPE1AR regular (recurring dues), S special (levy).
ASMTDESC25ADescription (becomes the ledger CHGDESC).
ASMTAMT11P 2Amount charged each posting.
ASMTINST3S 0Instalment ceiling for a special (0 = unlimited, for regular).
ASMTPOST3S 0Instalments posted so far (advanced by the charge run).
ASMTSTAT1AA active (only active schedules are charged).

CVLEDG — Owner AR open items (K ACCTNO, CHGSEQ)

FieldTypeMeaning
ACCTNO / CHGSEQ10A / 5S 0Unit account + per-account charge sequence (key).
CHGTYPE1AA regular assessment, S special, L late fee, F violation fine.
CHGDT / CHGDUE8S 0Charge date / due date (assessments due the 1st of the period).
CHGAMT11P 2Charge as raised (never changed after posting).
CHGOPEN11P 2Outstanding amount (CHGAMT less cash applied).
CHGAGE1S 0Aging bucket stamped by CVDELQ: 0/1/2/3.
CHGDESC25AFree-text description.
CHGSTAT1AO open, P part/fully-applied (open reduced by cash).

CVLEDLF is a logical over CVLEDG keyed on CHGDUE, ACCTNO so the aging run reads oldest-due-first without sorting.

CVACCT — Unit account (K ACCTNO)

FieldTypeMeaning
ACCTNO10AOwner-account key = ASSOCID || UNITNO (key).
ASSOCID / UNITNO6A / 4AThe association and unit this account belongs to.
ABAL11P 2Running owner-ledger balance (the AR invariant).
LIENSTAT1A' ' none, D delinquent, N notice sent, L lien filed.

CVRCPT — Cash receipts (K RCPTNO)

FieldTypeMeaning
RCPTNO8AReceipt number (key), e.g. RC000001.
ACCTNO10AAccount the receipt pays.
RCCHGSQ5S 0The ledger charge sequence this receipt nominates.
RCDT8S 0Receipt date.
RCAMT / RCAPPL11P 2Receipt amount / amount actually applied.
RCSTAT1AU unapplied, A fully applied, P part-applied.

CVVIOL — Code violations (K VIOLNO)

FieldTypeMeaning
VIOLNO6S 0Violation number (key).
ACCTNO10AAccount fined.
VDT8S 0Reported date.
VCODE / VDESC4A / 30AViolation code / description.
VDAYS3S 0Cure period in days before a fine is assessed.
VFINEAMT11P 2Fine amount.
VSTAT1AO open, F fined, C cured/closed.

CVARC — Architectural requests (K ARCNO)

FieldTypeMeaning
ARCNO6S 0Request number (key).
ACCTNO10ARequesting owner's account.
ARDT / ARDESC8S 0 / 30ARequest date / description.
ARSTAT1AP pending, A approved, D denied.

Architectural requests are inventory only in this build — the file exists and is seeded/queryable, but no batch program posts money against it.

CVRESV / CVRESVH — Reserve fund + history

FieldTypeMeaning
CVRESV.ASSOCID6AAssociation (key, one reserve row each).
CVRESV.RBAL11P 2Running reserve balance.
CVRESV.RPCT5P 2Funding percent of collected cash transferred each period.
CVRESVH.ASSOCID / RSEQ6A / 5S 0Reserve-transfer history key.
CVRESVH.RDT / RAMT8S 0 / 11P 2Transfer date / amount.

CVHIST — Durable audit trail (K HSEQ)

FieldTypeMeaning
HSEQ8S 0Derived history key (unique; disjoint ranges per program — see F.2).
ACCTNO / HITEM10A / 10AAccount / item reference (account, violation no, or association).
HTYPE1AA/S charge, P payment, L late fee, F fine, V reserve transfer.
HDT / HAMT8S 0 / 11P 2Date / amount (payments carry a negative amount).
HREF / HMEMO8A / 25AReference / memo.

CVGLDIST — GL distribution (SQL, PK GLSEQ)

FieldTypeMeaning
GLSEQDECIMAL(8,0)Distribution sequence (PK).
GLBATCHDECIMAL(6,0)Batch (the period, e.g. 202609).
ACCTCHAR(9)GL account: 1400-OAR, 4100-ASMT, 4300-LATE, 4400-FINE.
DRCRCHAR(1)D debit / C credit.
AMTDECIMAL(11,2)Amount.
GLREF / GLDTCHAR(8) / DECIMAL(8,0)Reference / date.

Index CVGLDACC on (ACCT, DRCR) supports the incremental-post floor query and the reconciliation SELECTs.

Relationships

Seeded reference book (CVREFLD)

2 associations (Meadowbrook A00001, Harborview A00002), 9 units (2 vacant, 2 rented, 5 owner-occupied), 6 owners, 3 assessment schedules (Meadowbrook dues 250.00 + roof special 400.00 on 0103, Harborview dues 320.00), 7 unit accounts (one per occupied unit, zero balance), 2 reserve funds (Meadowbrook 10%, Harborview 8%).

E. Operations Runbook ↑ top

E.1 Day-in-the-life

  1. First-time / rebuild setup: CALL CIVICA/CVSETUP creates every object and compiles every program, then CALL CIVICA/CVREFLD seeds the reference book. Confirm the setup-complete banner and the seed counts (ASSOC=2 UNIT=9 OWNER=6 ASMT=3 ACCT=7).
  2. Post the month's assessments: SBMJOB CMD(CALL PGM(CIVICA/CVMONTH)); check CVCHRUN CHARGED=n SKIP=m and that each occupied account's ABAL rose by its dues (plus any special).
  3. Apply receipts as they arrive (daily): load CVRCPT rows (RCSTAT 'U', each naming an account + charge sequence), then SBMJOB CMD(CALL PGM(CIVICA/CVDAILY)); check CVCASHAP APPLIED=n and that balances fell by exactly what was applied.
  4. Look things up: CALL CIVICA/CVMENU → option 1 (unit/owner) or 2 (owner ledger subfile) for read-only inquiry and reconciliation.

Pre-checks: confirm the job's library list includes CIVICA; confirm the seed data is loaded (the inquiries show data). Post-checks: every batch program's DSPLY banner shows the expected count; the SKIP figure accounts for anything not processed (inactive schedule, already-applied receipt, vacant unit).

E.2 Period-end close

  1. Confirm the month's charge run and all daily cash runs have completed (open balances and collected cash are what aging/reserve will compute on).
  2. Load any code violations to be actioned into CVVIOL (RCSTAT 'O', with a cure period VDAYS).
  3. Submit the period cycle: SBMJOB CMD(CALL PGM(CIVICA/CVPERIOD)). It runs aging→fines→reserve→GL→AR and sends the period-end banner.
  4. Review the DSPLY banners and reconcile:
SELECT DRCR, SUM(AMT) FROM CIVICA.CVGLDIST GROUP BY DRCR;
-- total D must equal total C exactly; DR 1400-OAR = 4100-ASMT + 4300-LATE + 4400-FINE

Reconciling figures (the same ones the cycle test checks against a hand-derived oracle): DR Owner Receivable = assessments (2210.00) + late fees (203.00) + fine (75.00) = 2488.00; CR Assessment Revenue 2210.00, CR Late Fee 203.00, CR Fine 75.00. CVARRPT reports the full ledger: 8 charges + 6 late fees + 1 fine = 15 items.

E.3 Failure & re-run rules

Each batch program DSPLYs a result banner with a processed count and a SKIP count. The app's safety net is derived-key idempotency: re-running a program regenerates the same CVHIST key and the CHAIN(EN) guard refuses the duplicate.

SituationBehaviourAction
Charge run fails partwayAlready-charged accounts have their CVHIST row; the rest do not.Re-submit CVMONTH: charged accounts are skipped (SKIP rises), the rest catch up. Idempotent per period.
Re-run the same charge runAll keys already exist → every account skipped.Safe no-op; the special assessment's ASMTPOST does not advance twice.
Cash application re-runEach receipt already has its 20000000+ history row.APPLIED=0 SKIP=n; balances do not fall twice.
Aging/late-fee re-run (same run date)Each account already has its 30000000+ late-fee row.No double fee; buckets/lien status are re-stamped harmlessly.
Fine re-runFined violation is 'F' and already has its 40000000+ row.Never double-fined; still-in-cure violations remain open for a later run.
Reserve transfer re-runEach association already has its 50000000+ row.No second CVRESVH row; RBAL unchanged.
GL post re-runIncremental post: DR already booked is the floor.Adds no rows when nothing new has been charged (ROWS=0 effectively).
Whole CVPERIOD re-runEvery step idempotent.The CL chain is safely re-runnable end to end.
Because every money movement is written to CVHIST (and mirrored on CVACCT.ABAL and the CVLEDG open items), any cycle's effect is fully reconstructable after the fact for reconciliation and recovery. CVARRPT gives an independent COBOL total over the ledger to reconcile against the account balances.

F. Developer Reference ↑ top

The complete program surface, from hoa-app/src/sources.mjs. All objects are in library CIVICA. The RPG is a mix of fixed-form C-specs and /free blocks; each program uses keyed record-level I/O against the DDS files.

F.1 Programs (10 RPG + 1 COBOL + 4 CL)

CVREFLD (RPGLE) — reference-data seeder
Writes the 2 associations, 6 owners, 9 units, 3 assessment schedules, 7 unit accounts and 2 reserve funds, then DSPLYs CVREFLD ASSOC=2 UNIT=9 OWNER=6 ASMT=3 ACCT=7.
CVCHRUN (RPGLE) — monthly assessment charge run
Walks CVASMT; subroutine ASM1 expands one schedule (*ALL via CVUNTLF, else one unit), POST1 posts a CVLEDG open-item + CVHIST row and raises CVACCT.ABAL. Re-CHAINs the schedule row by its own AKEY before advancing ASMTPOST for a special (the unit walk moved the shared record buffer). DSPLYs CVCHRUN CHARGED=n SKIP=m.
CVCASHAP (RPGLE) — daily cash application
Walks CVRCPT; subroutine CSH1 takes min(RCAMT, CHGOPEN) against the nominated charge (CKEY), reduces the open item, lowers ABAL, writes a negative-amount 'P' history row and stamps the receipt A/P. DSPLYs CVCASHAP APPLIED=n SKIP=m.
CVDELQ (RPGLE) — period aging + late fee + lien
Pass 1 stamps CHGAGE from a 30/360 day-serial; pass 2 (LF1) finds each account's worst open bucket, sets LIENSTAT, and assesses a 10%-of-open late fee (one per run date). DSPLYs CVDELQ B0=.. B1=.. B2=.. B3=.. FEES=n.
CVVFINE (RPGLE) — period violation fines
Walks CVVIOL; subroutine VF1 fines an open violation whose cure period has elapsed (30/360 day-serial), posts an 'F' ledger + history row, raises ABAL, and re-CHAINs the violation to mark it 'F'. DSPLYs CVVFINE FINED=n SKIP=m.
CVRESVTR (RPGLE) — period reserve transfer
Walks CVRESV; subroutine RSV1 sums the association's 'P' cash history, transfers RPCT%, writes a CVRESVH + 'V' history row and raises RBAL. DSPLYs CVRESVTR XFER=n SKIP=m.
CVGLPST (SQLRPGLE) — period GL post
Sums CVHIST by type, computes gross less the already-posted DR floor (SELECT SUM(AMT) ... WHERE ACCT='1400-OAR' AND DRCR='D'), and inserts balanced DR/CR rows into CVGLDIST via glrow. DSPLYs CVGLPST BATCH=202609 ROWS=n.
CVUNTIQ / CVLEDIQ / CVMENU (RPGLE) — inquiries + menu
Read-only 5250 drivers over CVUNTD (plain unit/owner), CVLEDD (ledger subfile with SFLCLR/reload discipline) and CVMENUD (routes to the two inquiries).
CVARRPT (CBLLE) — AR control report
ILE COBOL sequential read of CVLEDG, totalling RAISED, OPEN, ITEMS and OVERDUE; DISPLAYs four CVARRPT ... lines.
CVSETUP / CVDAILY / CVMONTH / CVPERIOD (CLP)
Setup (DLTF/CRTPF/CRTLF/CRTDSPF/CRTPRTF/RUNSQLSTM/CRTBNDRPG/CRTBNDCBL) and the three parameterless job-cycle wrappers, each with its completion SNDPGMMSG banner.

F.2 Key derivation & idempotency

The idempotency mechanism is a stable derived history key, one disjoint numeric range per program, so a re-run regenerates the same CVHIST.HSEQ and the CHAIN(EN) guard refuses the duplicate. No control row, no run-flag — the derived key is the guard.

ProgramHTYPEHSEQ derivation
CVCHRUNA / S10000000 + (account-digits × 100) + ASMTID
CVCASHAPP20000000 + receipt-digits
CVDELQL30000000 + account-digits
CVVFINEF40000000 + violation number
CVRESVTRV50000000 + association-digits

"account-digits" is %dec(%subst(ACCTNO:2:9):9:0) (the numeric tail of ASSOCID||UNITNO); "receipt-digits" is the numeric tail of RCPTNO; "association-digits" the numeric tail of ASSOCID. The ranges are 10M apart so no two programs collide.

F.3 The AR balance invariant

The core correctness property the cycle test asserts to the cent: CVACCT.ABAL moves only by (up) the charge run, (down) cash application, and (up) fee/fine posting. Concretely, for the seeded book after the full cycle:

Each RPG program re-CHAINs the account (and the schedule/violation) after any intervening file walk, because the walk moved the shared record buffer; the CHAIN reloads the whole record from disk before the in-memory field is updated. This is the discipline that keeps ABAL exact under record-level I/O.

F.4 RPG / embedded-SQL patterns

F.5 Status-code table (field values that gate behaviour)

CIVICA/i has no SQLSTATE application-error surface (it is not SQL-PL). Behaviour is gated by field status codes:

FieldValuesEffect
CVASMT.ASMTSTATAOnly active schedules are charged; others SKIPped.
CVUNIT.USTATO/R/V*ALL expansion skips vacant (V) units.
CVRCPT.RCSTATU/A/POnly U (unapplied) receipts are applied; result A (full) or P (part).
CVLEDG.CHGSTATO/PA fully-applied charge flips O→P (open reduced to 0).
CVVIOL.VSTATO/F/COnly O past cure is fined → F; C is skipped; still-in-cure stays O.
CVACCT.LIENSTAT' '/D/N/LSet from worst open bucket: 1→D, 2→N, 3→L, none→blank.
CVLEDG.CHGAGE0/1/2/330/360 aging bucket: current / 1-30 / 31-60 / 61+.
CVGLDIST.DRCRD/CDebit / credit; total D must equal total C.

G. Glossary ↑ top

Assessment
A charge levied on an owner. Regular (ASMTTYPE R) = recurring monthly dues to every occupied unit; special (S) = a one-off or fixed-instalment levy (e.g. a roof fund) on a unit.
Owner ledger / open item (CVLEDG)
The receivables sub-ledger: one row per charge (assessment, late fee, fine), reduced as cash is applied (CHGOPEN). The unit's charges sit together under its account key.
Unit account (CVACCT) / ABAL
The running owner-ledger balance per unit, plus lien status. ABAL is the AR invariant: it moves only by charge (up), cash (down) and fee/fine (up).
Aging bucket
How overdue an open charge is, on a 30/360 day convention: 0 current, 1 = 1–30 days, 2 = 31–60, 3 = 61+. Stamped by CVDELQ into CHGAGE.
Late fee
A flat 10% of an account's total open balance, assessed once per aging run on any delinquent account.
Lien ladder (LIENSTAT)
Escalating collection status from the worst open bucket: D delinquent, N notice sent, L lien filed; blank when current.
Cure period
The days (VDAYS from the violation date) an owner has to fix a violation before a fine is assessed.
Reserve fund (CVRESV)
An association savings balance funded by a percentage (RPCT) of each period's collected cash, moved by CVRESVTR.
Derived key / idempotency
Each posting's CVHIST key is computed from a stable business key in a disjoint numeric range, so a re-run regenerates the same key and the CHAIN(EN) guard refuses the duplicate — the app's re-run safety (see F.2).
GL distribution (CVGLDIST)
The balanced double-entry feed: DR owner receivable = CR assessment + late-fee + fine revenue. Posted incrementally so a re-run never double-posts.
Subfile
A 5250 display construct listing many rows on one screen (DDS SFL/SFLCTL). CVLEDIQ's charge-history list is a subfile, cleared and reloaded on every enquiry.
SBMJOB
Submit Job — the IBM i command that queues a program to run as a batch job (e.g. SBMJOB CMD(CALL PGM(CIVICA/CVPERIOD))).
Logical file (LF) / alternate access path
A DDS keyed view over a PF giving a different record ordering: CVUNTLF (units by association), CVLEDLF (ledger by due date).