Skip to content

This is an internal working record, not an everyday instruction. It was written while the system was being rebuilt, for whoever maintains it. If you are here to do today's work, use the everyday documents instead: Procedures · Processes · Runbooks · The working day, step by step

CTC Billing, QBO, Files And Email Parity And Cutover Matrix

  • Status: CURRENT P6/P12 MIGRATION INPUT
  • Operating profile: ctc-execution
  • Source reconciliation: CTC_BILLING_QBO_FILES_EMAIL_RECONCILIATION.md
  • Policy decisions: CTC_BILLING_QBO_FILES_EMAIL_POLICY_DECISION_MATRIX.md
  • Rebuild packet: CTC_BILLING_QBO_FILES_EMAIL_CAPABILITY_REBUILD_PACKET.md
  • Target stack: React + Next.js + framework-independent TypeScript + MySQL repositories + durable Node worker; PostgreSQL later.
  • Does not activate: any migration wave, dual writer, DB schema, provider effect, deployment or Production change.

1. Migration Principle

Migration follows business capability and checkpoint authority, not current page or file layout.

current source characterization
-> target read model
-> read-shadow parity
-> one bounded write command
-> one authoritative writer
-> exact readback and effect reconciliation
-> rollback rehearsal
-> target-role stabilization
-> caller-zero
-> legacy retirement

The following cannot be cut over as one unit:

generic transaction
AR local confirm
QBO provider delivery
file object/link
BOL email
Packing List target-part email
daily composite reconciliation

They share an operational close but own independent state and recovery.


2. Global Gates

Every write/effect wave requires all applicable gates.

Gate Required evidence
G-010 Source baseline Exact current source revision, schema identity, deployment identity and active caller inventory.
G-020 Process contract Accepted business outcome, completion, non-implication, normal/negative/recovery behavior.
G-030 Role/capability Target tenant × role × page/API/record/action allow/deny matrix.
G-040 Data contract Authoritative identity, state, fields, units, relationships, audit/correction and retention.
G-050 Interface contract Semantic command/query DTO, stable errors, exact readback and idempotency.
G-060 Effect contract Intent, attempt, provider/object result, unknown state, retry/reconcile/manual recovery.
G-070 One writer One explicit selector/cohort chooses one writer; no PHP/TypeScript dual mutation.
G-080 Rollback Tested selector reversal from current MySQL state without replaying committed business/provider effects.
G-090 Parity Stable scenario IDs pass for old/new reads or accepted intentional difference.
G-100 Observation Request/process/effect IDs, logs/metrics, support runbook and bounded observation period.
G-110 Knowledge Process, Runbook, Wiki stable topics and current/future route links synchronized.
G-120 Caller-zero Static and runtime callers classified; unknown caller count is zero before deletion.

A UI that looks correct is not sufficient for a write/effect wave.


3. Wave Overview

Wave Capability Initial target Writer/effect owner after cutover Main rollback
BILL-W0 Shared context and observability TypeScript tenant/actor/error/request/effect IDs No business writer change Remove target read path
BILL-W1 Billing composite and workbench reads React + Next.js read-only projections from MySQL Current PHP writers remain Route users to current pages
BILL-W2 Generic transaction semantic reads TypeScript repositories/queries Current PHP writers remain Disable target queries
BILL-W3 Generic transaction create/edit/close/correct TypeScript application commands, MySQL Selected capability writer only Disable target commands; resume PHP from current rows
BILL-W4 AR candidate/preview/confirm React review + TypeScript confirm, MySQL TypeScript AR confirm writer Resume PHP confirm only after exact state reconciliation
BILL-W5 QBO intent and read model Durable intent/attempt/reconciliation + worker shadow PHP direct send remains until W6 Disable shadow worker/read model
BILL-W6 QBO delivery Node worker + TypeScript reconciliation Worker is only provider-send owner Stop new attempts; reconcile in-flight; restore PHP send only for unresolved intents after decision
BILL-W7 File object/link reads and upload Typed object/link repository with current storage One object/upload/link owner per command Restore current upload/link UI; keep objects/links
BILL-W8 File unlink/cleanup Reference-aware unlink + deferred cleanup worker TypeScript/File worker Stop cleanup; retain objects; restore current unlink only after reference check
BILL-W9 BOL email intent/send Durable email intent + worker Worker only Stop new attempts; current send restored only after in-flight reconciliation
BILL-W10 Packing List target-part send Durable batch/target/part intents + worker Worker per target-part Stop unresolved attempts; preserve successes; restore current endpoint only for new batch versions
BILL-W11 Daily close reconciliation React derived worklist/disposition Composite remains non-mutating Return to manual current cross-page review
BILL-W12 PHP/legacy retirement Caller-zero and route removal Target platform Re-enable compatibility routes only while data/contract remains supported
BILL-W13 PostgreSQL later Repository/data cutover TypeScript application unchanged DB failback per P11; never combined with first business/effect cutover

4. Wave BILL-W0 — Shared Context And Observability

Scope

  • strict tenant and effective actor/subject context;
  • semantic request ID and process/effect correlation;
  • stable public error envelope;
  • source revision/schema/config/deployment identity in support evidence;
  • no business write or provider effect.

Required parity

Concern Current Target parity
Tenant Legacy context/session with compatibility fallback Same selected tenant, explicit target context; no caller-supplied authority.
Actor Session user and current role/menu Same effective actor plus impersonation subject when applicable.
Timezone Current configured/runtime behavior Same business-date interpretation, explicitly sourced.
Error Current envelopes vary Stable semantic code while preserving safe user meaning.
Request trace Current request/debug/log IDs One request ID propagated to application and effect intent.

Exit

Target queries can execute read-only against the same MySQL data with traceable tenant/actor/request identity.


5. Wave BILL-W1 — Read-Only Composite And Workbench

Target views

  • Billing daily checkpoint worklist;
  • generic transaction list/detail;
  • AR candidate/workbench/detail;
  • QBO local/provider reconciliation projection;
  • transaction file list/readability projection;
  • BOL/Packing email readiness/result projection where current evidence exists.

Parity dimensions

ID Old source New projection Required comparison
BILL-PAR-010 Generic transaction list/detail GetTransactions, GetTransactionDetail IDs/UUIDs, source/account/company, amounts, status, close fields, lines.
BILL-PAR-020 AR Billing workbench GetArBillingWorkbench Candidate count, booking/container, customer, warnings, totals, invoice/QBO state.
BILL-PAR-030 AR preview PreviewContainerInvoice read-only Charge source/type/qty/rate/amount/description and total.
BILL-PAR-040 Current QBO columns GetQboReconciliation transaction group, local state/ID/doc/error, provider evidence when available.
BILL-PAR-050 Current file list/download GetTransactionFiles file identity, type/name/order, target relation, URL/readability.
BILL-PAR-060 Current BOL readiness GetBolEmailReadiness source/reference/recipient/scale/files/blocked reason.
BILL-PAR-070 Current Packing model/readiness GetPackingEmailReadiness booking/equipment/options/targets/recipient/part plan.
BILL-PAR-080 Manual daily cross-page review GetBillingCloseWorklist applicable checkpoints and current unresolved owner, no invented completion.

Rollback

Remove/rewrite target navigation and use existing pages. No data/effect rollback.


6. Wave BILL-W2 — Generic Transaction Semantic Reads

Purpose

Establish a typed repository/query boundary before changing current writes.

Required contracts

GetTransactionSources
GetTransactions
GetTransactionDetail
GetTransactionCloseEligibility
GetTransactionCorrectionHistory

Required current-source reconciliation

  • source type and relation identity;
  • UUID coverage versus numeric-only compatibility;
  • active line calculation;
  • status/close field meanings;
  • billing company/account derivation;
  • provider/file relations;
  • current delete/soft-delete semantics.

Exit

All later commands can reread exact authoritative state without importing current giant helpers or generic table mutation.


7. Wave BILL-W3 — Generic Transaction Writes

Candidate command order

CreateSourceTransactions
EditDraftTransaction
CloseTransactions
CorrectLocalTransaction
DeleteOrVoidDraftTransaction

Do not start with delete/correction if policy remains open.

One-writer selector

Recommended selection key:

capability/source type + tenant/cohort

Example:

TRUCKING AR create/close for one approved tenant

The same source/account capability cannot write through both PHP and TypeScript.

State parity

Command Old behavior to characterize Target required behavior
Create Source-specific helper may detect existing related IDs Explicit idempotency and per-source result.
Edit Generic schema-shaped mutation Allowlisted semantic fields and state predicate.
Close Bulk common update Compatible rows, conditional state/version, per-row readback.
Correct Existing edit/manual path Explicit reason/actor/version and provider guard.
Delete/Void Source-specific delete or generic delete Separate draft delete, business void and provider correction.

Rollback

  • disable target command routes/actions;
  • restore PHP writer selector;
  • retain all committed MySQL rows/audit;
  • do not replay create/close/correction;
  • reconcile any request with unknown response by exact IDs/UUIDs.

Caller-zero before PHP removal

  • transaction list/form JavaScript;
  • all source create/delete buttons;
  • close modal/actions;
  • direct API callers;
  • shared helper calls;
  • scripts/tests/imports;
  • report/file/provider consumers.

8. Wave BILL-W4 — AR Billing Confirm

Read-first prerequisites

  • accepted BILL-POL-060 preview consistency;
  • active invoice uniqueness/version policy;
  • correction policy;
  • exact source/rate/preset/transaction-type field contract;
  • target-role/API matrix.

Target transaction

For one confirm request, preserve the accepted all-items local atomicity unless policy intentionally changes it.

BEGIN
-> validate every candidate and source fingerprint
-> resolve customer/preset/rates/types
-> enforce active invoice uniqueness
-> insert or approved-version-rewrite each header/lines
-> record correction/version relation where applicable
-> optionally create QBO intent record without provider call
-> exact reread
COMMIT

Parity scenarios

  • one candidate success;
  • multiple candidate all-or-nothing success;
  • one invalid candidate rolls back request;
  • existing source AR conflict;
  • existing unsynced container AR correction;
  • existing synced row blocked;
  • concurrent same booking/container confirm;
  • response loss followed by exact reread.

Rollback

Resume PHP confirm only when:

  • target writer is disabled;
  • no target request is in-flight;
  • current active invoice/version is known;
  • QBO intent state is known;
  • operator uses current rows, not a replayed preview.

9. Waves BILL-W5 And BILL-W6 — QBO

W5 shadow/intents

Introduce target concepts without sending provider effects:

QboInvoiceIntent
QboInvoiceAttempt
QboInvoiceReconciliation

Shadow mode may:

  • build target payload;
  • compute immutable group identity and payload hash;
  • compare current PHP group/payload/result;
  • search/read provider only if separately authorized and supported;
  • never create an invoice.

W6 provider cutover

One effect intent chooses exactly one send owner.

sequenceDiagram
    participant App as TypeScript Application
    database DB
    participant Worker
    participant QBO

    App->>DB: Commit local invoice + effect intent
    Worker->>DB: Claim one intent/attempt
    Worker->>QBO: Search/reconcile or create using intent identity
    QBO-->>Worker: Provider result/unknown
    Worker->>DB: Persist attempt and reconciliation
    App->>DB: Project invoice delivery state

Required effect states

PENDING
CLAIMED
PROVIDER_ACCEPTED
SYNCED
FAILED_RETRYABLE
FAILED_FINAL
UNKNOWN_PROVIDER_RESULT
MANUAL_REVIEW
CANCELLED_BEFORE_ATTEMPT

Cutover rule

  • current PHP /qbo-sync send disabled for target cohort;
  • worker is only provider-create owner;
  • current UI may call a compatibility target command but does not call QBO directly;
  • SYNCING compatibility projection derives from active target attempt, not a second independent claim.

Rollback

  1. Stop worker from claiming new intents.
  2. Let or manually reconcile claimed/in-flight attempts.
  3. Do not route unresolved intents to PHP until provider absence/known state is established.
  4. For new requests only, restore PHP sender if explicitly approved.
  5. Preserve target intent/attempt records for audit.

Caller-zero

  • PHP QBO helper/client creation path;
  • browser automatic qbo-sync call;
  • manual qbo-sync calls;
  • token refresh inside business route;
  • direct QBO status writes;
  • scripts/support procedures relying on raw QBO_ERROR claim token.

10. Waves BILL-W7 And BILL-W8 — Files

Target contracts:

UploadFileObject
LinkFileToTransaction
GetTransactionFiles
GetFileReadability

Initial storage remains current EFS/S3.

Identity/parity

Concept Current mapping Target identity
Object path/URL/storage/UUID in upload metadata and T_FILE rows file-object UUID + storage provider/key + content hash
Link T_FILE.TABLE_NAME/TABLE_ID/TYPE independent link UUID + target entity UUID + object UUID + link type
Readability generated download URL/object access read/check result with timestamp/error classification
Sequence current max/order presentation ordering, not identity

W8 unlink/cleanup

Commands:

UnlinkFileFromTransaction
EvaluateFileObjectCleanup
DeleteUnreferencedFileObject
ReconcileOrphanFileObject

Cleanup worker must never delete while:

  • active links exist;
  • legal/retention hold exists;
  • link/reference inventory is unknown;
  • storage result is unknown.

Rollback

  • stop cleanup worker immediately;
  • preserve objects and active links;
  • restore current upload/link UI for new work;
  • never reconstruct missing objects by copying a stale URL;
  • reconcile any object/link unknown result before retry.

Caller-zero

  • media upload consumers;
  • generic /files callers;
  • transaction document registration;
  • delete/type-update actions;
  • direct path/URL consumers;
  • BOL/Packing attachment readers;
  • Wiki/file special consumers kept under their own capability.

11. Wave BILL-W9 — BOL Email

Target intent identity

intent UUID
+ tenant
+ transload UUID
+ recipient-set hash
+ subject/content version
+ attachment object UUID/hash set

Required sequence

operator reviews readiness
-> command commits EmailIntent and target/attachments
-> worker claims attempt
-> search/reconcile if prior unknown
-> send Gmail
-> persist message/thread ID
-> operator sees exact result

Parity

  • same normal recipient semantics after removal of username override;
  • same subject/reference;
  • same optional scale PDF and active source files;
  • same no-business-state rollback on mail failure;
  • improved durable intent/result and unknown recovery.

Rollback

  • stop new worker claims;
  • reconcile claimed/in-flight sends;
  • restore current endpoint only for newly created intent versions after explicit choice;
  • do not replay an unresolved intent through PHP.

12. Wave BILL-W10 — Packing List Target-Part Email

Target hierarchy

PackingEmailBatch
-> EmailTarget CUSTOMER/INSPECTOR
-> EmailPart 1..N
-> EmailAttempt(s)
-> Provider reconciliation

Required parity

  • booking/equipment source model;
  • selected weight/reference options;
  • selected targets;
  • recipient resolution;
  • generated body and attachment partition content;
  • subject and part numbering;
  • preserve successful target-parts after later failure.

Intent versioning

If source content, options, recipients or partitioning changes:

new batch version

Do not mix a regenerated part set with prior successful parts under the same immutable batch version.

Rollback

  • stop new attempts;
  • preserve all sent message IDs;
  • current endpoint may send only a new intentionally versioned batch after unresolved old parts are reviewed;
  • never replay full target automatically.

Caller-zero

  • current booking email route;
  • browser action;
  • GmailSender direct call;
  • attachment split/temp cleanup path;
  • current response-only Results assumptions;
  • admin override.

13. Wave BILL-W11 — Daily Composite Reconciliation

Target result

A React worklist shows each applicable child checkpoint without creating a universal business state.

Local transaction
Local container AR
QBO
File
BOL email
Packing target/parts

Possible human disposition:

VERIFIED
CARRIED
NOT_APPLICABLE
BLOCKED
UNKNOWN

If persisted, the disposition references exact child IDs/evidence/owner and remains non-authoritative over child state.

Parity

  • every current applicable child remains visible;
  • no provider/file/email completion inferred from local close;
  • unresolved items show next owner and safe action;
  • no action replay from the composite page without invoking the child command.

Rollback

Return to current manual cross-page review. Child data/effects remain unchanged.


14. Wave BILL-W12 — Legacy Retirement

Required caller inventory status

ACTIVE
COMPATIBILITY
TEST_ONLY
HISTORICAL
UNKNOWN
REMOVED_AND_VERIFIED

UNKNOWN blocks deletion.

Retirement families

  • generic BMS transaction routes/helpers and table-mutation form;
  • AR Billing PHP routes/helper/JS;
  • direct QuickBooks client and request-path token refresh;
  • shared file routes only where fully replaced and not consumed by other domains;
  • BOL/Packing direct Gmail routes;
  • old PHP pages and shared JS;
  • configuration keys only after new owner and migration;
  • documentation and Wiki application links.

Runtime evidence

  • static search;
  • route/caller telemetry;
  • server access logs;
  • provider/effect logs;
  • scheduled jobs/scripts;
  • bookmarks/Wiki links;
  • target-role browser traffic;
  • controlled compatibility-disable observation.

15. Wave BILL-W13 — PostgreSQL Later

P11 preserves the accepted TypeScript/MySQL contract.

Required parity:

  • transaction/invoice UUID and active uniqueness;
  • decimal precision/currency/rounding;
  • soft-delete and invoice-version relation;
  • conditional transitions and concurrency;
  • QBO/file/email effect identities and attempts;
  • JSON/preset mapping;
  • file object/link reference integrity;
  • target-part identity;
  • indexes/query plans;
  • active in-flight intent migration;
  • failback representation.

Do not move provider sends during the DB cutover.


16. Stable Migration Scenario Catalog

Read parity

ID Scenario Required evidence
BILL-MIG-SCN-010 Generic transaction old/new list/detail parity Same selected rows, lines, totals, statuses and identities.
BILL-MIG-SCN-020 AR workbench parity Candidate, warnings, totals, existing state.
BILL-MIG-SCN-030 AR preview parity Line source/qty/rate/amount/total.
BILL-MIG-SCN-040 File list/readability parity Object/link/read state.
BILL-MIG-SCN-050 Billing close worklist Correct applicable checkpoints and unresolved owner.

Local writes

ID Scenario Required evidence
BILL-MIG-SCN-110 One source transaction create One semantic result and no duplicate.
BILL-MIG-SCN-120 Compatible multi-row close Per-row conditional write/readback.
BILL-MIG-SCN-130 Mixed-company close rejected No row mutation.
BILL-MIG-SCN-140 Close response loss Exact reread; no blind reapply.
BILL-MIG-SCN-150 AR confirm one/many Accepted atomicity and active uniqueness.
BILL-MIG-SCN-160 Concurrent AR confirm One accepted active invoice/version outcome.
BILL-MIG-SCN-170 Synced correction blocked No raw local mutation.

Effects

ID Scenario Required evidence
BILL-MIG-SCN-210 QBO normal delivery Intent/attempt/provider/local reconciliation.
BILL-MIG-SCN-220 QBO provider success/local response loss Search/reconcile; no duplicate create.
BILL-MIG-SCN-230 QBO stale claimed attempt Safe disposition, no time-only resend.
BILL-MIG-SCN-240 File object success/link failure Targeted link recovery; no duplicate object.
BILL-MIG-SCN-250 Shared object unlink Object retained while another link exists.
BILL-MIG-SCN-260 BOL unknown result Sent/provider reconciliation before resend.
BILL-MIG-SCN-270 Packing later part failure Prior parts preserved; only unresolved part eligible.
BILL-MIG-SCN-280 Gmail send response loss Provider message reconciliation.

Cutover/rollback

ID Scenario Required evidence
BILL-MIG-SCN-310 One-writer selector One command/effect owner per cohort.
BILL-MIG-SCN-320 Rollback after committed local write PHP resumes from current state; no replay.
BILL-MIG-SCN-330 Rollback with provider attempt in-flight Attempts reconciled before alternate sender.
BILL-MIG-SCN-340 Compatibility disable observation No unknown caller; support path remains.
BILL-MIG-SCN-350 Caller-zero All callers classified; unknown zero.

17. Wave Status Ledger

Wave Status Activation decision Starting revision Writer/effect selector Evidence Rollback result Caller-zero
BILL-W0 NOT_STARTED
BILL-W1 NOT_STARTED
BILL-W2 NOT_STARTED
BILL-W3 NOT_STARTED
BILL-W4 NOT_STARTED
BILL-W5 NOT_STARTED
BILL-W6 NOT_STARTED
BILL-W7 NOT_STARTED
BILL-W8 NOT_STARTED
BILL-W9 NOT_STARTED
BILL-W10 NOT_STARTED
BILL-W11 NOT_STARTED
BILL-W12 NOT_STARTED
BILL-W13 NOT_STARTED

Documentation completion does not advance a wave status.

---

Source: docs/processes/CTC_BILLING_QBO_FILES_EMAIL_PARITY_AND_CUTOVER_MATRIX.md — ctc repository · This page is an English translation of the source document. Identifiers, file paths and code symbols are unchanged.