Last reviewed: 2026-08-13
Accepted decision:
- ../../decisions/accepted/0031-company-scoped-postgresql-backup-and-atomic-restore.md
Contract: Company backup snapshot
Purpose
This contract defines the versioned ownership catalog and restore behavior for one BooksPlus company stored in a shared PostgreSQL schema.
Snapshot identity
The current catalog version is company-snapshot-v23.
The current application-schema version is bp3-schema-202608130002.
A snapshot carries:
- backup, company, format, application-schema, and catalog versions;
- the exact company-owned relational projection;
- the exact managed-evidence component;
- the exact company key-envelope component;
- referenced immutable shared definitions; and
- a manifest of every component identity, length, and cryptographic digest.
An implementation must compare the live schema with this catalog. An uncataloged persisted relation or an unexpected ownership path blocks backup creation and restore.
Current relation catalog
Direct company-owned state
Rows are selected by their company_id, except company, which is selected by
its stable id. security_audit_event includes only rows whose company_id
equals the backup company.
companyaccountaccount_historyaccount_role_assignmentaccounting_correctionaccounting_event_relationshipaccounting_import_accepted_candidateaccounting_import_runbanking_and_finance_factchart_import_batchclose_approvalclose_check_snapshotclose_report_packclose_reopenclose_runclose_run_number_sequenceclose_waivercompany_conversion_runcompany_conversion_control_resultcompany_conversion_approvalcompany_conversion_applicationcompany_protection_key_envelopedolibarr_account_crosswalk_mappingdolibarr_mapping_set_selectiondolibarr_role_projectionfinancial_periodfinance_account_reconciliation_resultfinance_statement_match_resultfinance_sales_tax_remittance_matchfinance_settlement_allocationfiscal_calendar_profilejournal_entryjournal_entry_number_sequenceinformation_return_payer_profileinformation_return_payer_profile_protected_tininformation_return_support_runinventory_accounting_factinventory_ppv_allocationinventory_ppv_reconciliation_resultinventory_valuation_snapshotinformation_return_draftinformation_return_filing_submissioninformation_return_recipient_statementpayee_profile_protected_tinpayee_tax_profileprotected_payload_envelopeqbo_connectionqbo_conversion_extractionpurchasing_and_payables_factpurchasing_grni_settlement_allocationpurchasing_prepayment_recognition_allocationreport_runreport_run_number_sequencesecurity_audit_eventsales_tax_capability_profilesales_tax_resultsales_tax_return_controlsales_tax_return_control_number_sequencesales_tax_remittancesales_tax_remittance_number_sequencesensitive_source_document_artifactsetup_acknowledgementstarter_chart_installation_reviewsource_documentsummary_accounting_batchsummary_accounting_batch_number_sequenceworker_classification_record
Company-owned child state
Rows are selected only through the declared parent path:
| Relation | Company-owning parent path |
|---|---|
accounting_import_payload |
accounting_import_run |
chart_import_row |
chart_import_batch |
chart_import_issue |
chart_import_batch |
company_conversion_import_link |
company_conversion_run |
company_conversion_mapping_decision |
company_conversion_run |
company_conversion_status_change |
company_conversion_run |
company_conversion_control_check |
company_conversion_control_result |
company_conversion_application_step |
company_conversion_application |
company_conversion_application_account |
company_conversion_application |
qbo_conversion_extraction_checkpoint |
qbo_conversion_extraction |
close_check_source_reference |
close_check_snapshot |
close_report_pack_evidence |
close_report_pack |
close_report_pack_report_run |
close_report_pack |
close_reopen_evidence |
close_reopen |
financial_period_state_change |
financial_period |
finance_account_reconciliation_line |
finance_account_reconciliation_result |
journal_entry_line |
journal_entry |
report_snapshot |
report_run |
report_snapshot_line |
report_snapshot through report_run |
report_snapshot_source_contribution |
report_snapshot through report_run |
sales_tax_profile_evidence |
sales_tax_capability_profile |
sales_tax_jurisdiction_summary |
sales_tax_result |
sales_tax_return_inclusion |
sales_tax_return_control |
sales_tax_reconciliation_snapshot |
sales_tax_return_control |
sales_tax_external_filing_evidence |
sales_tax_return_control |
sales_tax_return_status_history |
sales_tax_return_control |
sales_tax_external_payment_evidence |
sales_tax_remittance |
sales_tax_remittance_status_history |
sales_tax_remittance |
information_return_support_line |
information_return_support_run |
summary_accounting_validation_issue |
summary_accounting_batch |
summary_accounting_evidence_link |
summary_accounting_batch |
summary_accounting_prepared_entry_preview |
summary_accounting_batch |
summary_accounting_prepared_entry_preview_line |
summary_accounting_prepared_entry_preview through summary_accounting_batch |
summary_accounting_posting_result_link |
summary_accounting_batch |
Company security configuration requiring review
security_actor_role_assignment
Captured assignments are not automatically activated. Before replacement, the
restore workflow presents current and captured assignments for an explicit
protected role_permission.change review. Only approved assignments are
applied in the replacement transaction. Existing assignments remain current
unless the review explicitly changes them; recovery into an absent company
activates none by default.
Embedded immutable shared definitions
These relations are not replaced wholesale. Only definitions referenced by the company snapshot are embedded and reconciled under ADR 0031:
information_return_rule_setsecurity_actorsecurity_rolesecurity_permissionsecurity_role_permission
Actor references include actors named by company records and company-scoped audit events, not only actors with a current role assignment.
Installation state excluded from company backup
booksplus_schema_migration- company-null rows of
security_audit_event
The migration ledger is used to establish the application-schema version but is never restored from a company backup.
Logical component projections
Physical co-location does not collapse required backup components:
company_protection_key_envelopeis projected into the company-key-envelope component and omitted from the ordinary relational component;- for
protected_payload_enveloperows owned by a sensitive W-9 artifact, the encrypted artifact bytes and their encryption/integrity material are projected into the managed-evidence component while the owning relational identities remain in the relational projection; - other protected payloads, including protected taxpayer identifiers, QBO token bundles, and exact QBO response checkpoints, remain in the company relational projection; and
sensitive_source_document_artifactmetadata binds the managed-evidence component back to its Source Document and protected-payload identity.
The capture and restore implementation must prove that every logical row and artifact is represented exactly once and that the components reconstruct all required database constraints.
Shared-definition reconciliation
- Existing shared definitions are never overwritten.
- Existing information-return rule versions require exact content equality.
- Existing role identities require compatible role name and exact permission membership.
- Existing protected-action permission names must match the embedded identity.
- Existing actor identities require compatible stable actor id, actor type, and mapped external identity when present. Existing status and login mapping remain current.
- Missing shared roles, permissions, and role-permission memberships may be inserted exactly.
- Missing actors are inserted disabled and without a login or operating-system mapping. Their historical display name and actor type are retained.
- Captured actor-role assignments remain inactive unless explicitly approved through protected role-permission review.
- Any incompatible shared identity blocks restore before mutation.
Restore rules
- The target company UUID must equal the backup company UUID or be absent.
- An absent company is created with the captured UUID; identity is never remapped.
- Replacement runs only in exclusive BooksPlus maintenance mode under the company-scoped restore lock.
- All validation completes in staging before the replacement transaction.
- The recovery secret must authenticate both the container and company key envelope.
- Company-owned state is replaced atomically.
- Company audit events are merged append-only by immutable event id.
- Other-company and installation state is unchanged.
- Failure leaves pre-restore company state unchanged and emits value-free protected-action audit evidence where the current audit store is available.
Schema evolution
Every persistence migration must:
- update this catalog for every relation or ownership-path change;
- increment the catalog version when snapshot representation or restore behavior changes;
- add schema-to-catalog conformance tests; and
- add capture and restore tests for the changed state.
The initial implementation supports only exact schema and catalog versions.
Reporting owns report_run and its number sequence directly by company.
Immutable report snapshots, normalized lines, and source contributions are
company-owned children reached through their ReportRun. Restore replaces this
aggregate in dependency order and preserves the run-to-succeeded-audit link.
The Sales Tax Accounting and Remittance Contract makes capability profiles,
tax results, jurisdiction summaries, return controls and inclusions,
reconciliation snapshots, filing and payment evidence links, remittances,
Finance remittance matches, number sequences, histories, and audit links
company-owned backup state. Catalog version company-snapshot-v23 includes
the capability-profile, Sales-result, return-control, reconciliation, filing-
evidence, remittance, external-payment-evidence, Finance-match, numbering, and
history relations introduced through Slices 15B0T3 and 15B0T4.
Acceptance criteria
- Every current persisted relation is classified.
- Backup creation fails when the live schema contains an uncataloged relation.
- Capture observes one repeatable-read company snapshot.
- Other-company rows and company-null audit events are absent.
- Referenced shared definitions are complete and conflicts block restore.
- Missing actors cannot receive access merely because a backup was restored.
- No captured actor-role assignment becomes active without explicit protected review.
- Managed evidence and the company key envelope are present exactly once.
- Container and company-key recovery validation completes before mutation.
- Failed restore leaves replaceable company state unchanged; only the permitted append-only failed-restore audit evidence may be added.
- Successful restore changes only the target company and merges audit evidence append-only.