Hermes 284313f908
Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

5.0 KiB

Recurring Invoicing Hard Cutover Runbook

Purpose

Use this runbook after the hard cutover when recurring invoicing is service-period driven only.

It is the operator and developer reference for:

  • understanding the final recurring mental model
  • diagnosing missing due recurring work without falling back to billing-cycle compatibility rows
  • repairing materialization or linkage gaps through canonical recurring service-period data
  • validating that history and reversal still line up with canonical recurring linkage

Final Recurring Mental Model

Recurring invoicing now has one operational model:

  1. cadence ownership and source rules generate persisted recurring_service_periods
  2. due recurring work is the set of due recurring_service_periods
  3. preview, generate, retry, history, reverse, and delete actions all act on canonical execution-window or service-period identity
  4. client_billing_cycles remain cadence infrastructure, not recurring due-work rows

Compatibility due-work rows are removed from steady-state recurring execution. If a recurring obligation should be invoiceable and no canonical service-period row exists, treat that as a repairable materialization failure.

Hard-Cutover Operator Sequence

  1. Confirm the affected obligation has persisted recurring_service_periods for the expected invoice window.
  2. If the row is missing, treat that as materialization repair work instead of looking for a compatibility client_billing_cycles row.
  3. Validate the due row identity from canonical fields such as record_id, schedule_key, period_key, invoice_window_start, and invoice_window_end.
  4. Run preview or generate flows only from canonical selector input.
  5. When reversing or deleting a billed recurring invoice, validate the linked recurring service-period rows reopen or remain correctly linked through canonical invoice linkage.

Missing Due-Work Diagnosis

1. Inspect persisted recurring service periods

select
  record_id,
  schedule_key,
  period_key,
  cadence_owner,
  lifecycle_state,
  service_period_start,
  service_period_end,
  invoice_window_start,
  invoice_window_end,
  invoice_id,
  invoice_charge_id,
  invoice_charge_detail_id
from recurring_service_periods
where tenant = :tenant
  and client_id = :client_id
order by invoice_window_end desc, service_period_start desc;

2. Interpret the result

  • matching canonical row exists and is due: recurring UI and API should use that row directly
  • matching canonical row exists but is billed or locked: validate whether the invoice history or reversal state already explains the absence from due work
  • matching canonical row does not exist: missing recurring service-period materialization is a repair state, not a fallback-ready invoice row

3. Check source-rule inputs

If the row is missing, confirm:

  • cadence owner is correct for the obligation
  • client cadence rules still exist when cadence_owner = client
  • future recurring service periods were regenerated after source-rule changes

Reverse/Delete Repair Notes

Use canonical recurring linkage when repairing recurring invoice state:

  1. capture record_id, schedule_key, period_key, invoice_id, and the canonical execution-window identity
  2. perform the reverse or delete action
  3. confirm recurring_service_periods.invoice_id, invoice_charge_id, and invoice_charge_detail_id reflect the repaired state
  4. confirm lifecycle state is reopened or preserved according to the canonical linkage repair flow
  5. rerun due-work validation to confirm the same execution window reappears only when it should be invoiceable

Do not treat a billing_cycle_id value as the primary repair handle for recurring invoices.

Historical Incomplete Linkage

Some historical invoices may remain readable without complete canonical recurring linkage.

Use this posture:

  1. if canonical recurring detail rows exist, read and explain the invoice from those canonical periods
  2. if canonical detail rows are absent, keep the invoice readable as a historical financial document instead of inventing synthetic recurring periods
  3. if related source invoice lineage cannot be resolved, surface that as missing source context and keep the invoice readable with null recurring period metadata

What not to do:

  • do not recreate live recurring due rows from client_billing_cycles
  • do not treat billing_cycle_id as a replacement execution key
  • do not backfill synthetic recurring service periods onto historical invoices purely for display

Fallback read states such as financial_document_fallback and missing_source_context are acceptable only to preserve historical readability while cleanup or backfill work is handled explicitly.

Validation Checklist

  • recurring due-work investigation starts from recurring_service_periods
  • no operator step expects a compatibility due-work row from client_billing_cycles
  • client cadence is explained as source-rule infrastructure only
  • history and reversal checks are driven by canonical recurring linkage
  • billing_cycle_id is treated as optional historical context only