Ecommerce operations and acceptance¶
This page defines service behavior and go-live gates. Incident actions and exit criteria are normative in Operational runbooks; classification, retention, exports, and offboarding are normative in Data governance.
Job catalog¶
| Job | Lease key | Retry policy | Terminal evidence |
|---|---|---|---|
source_webhook_process |
provider delivery ID | Exponential, max 10; no Odoo side effect | Canonical events committed |
airbyte_run_monitor |
Airbyte connection + job ID | Poll with bounded deadline | Run counts/checkpoint recorded |
canonicalize_record |
inbox record + adapter version | Exponential, max 8 | Lineage and projection committed |
source_completeness_check |
connection + stream + period | Daily retry for 24 hours | Control totals and missing IDs recorded |
posting_intent_build |
canonical aggregate + policy version | Retry only transient reads | Immutable valid/blocked intent |
odoo_command_execute |
operation business key | Profile-specific; never blind retry after ambiguity | Odoo readback confirms or classifies |
odoo_verify_unknown |
operation ID | Increasing intervals, bounded 24 hours | Confirmed, safe-to-retry, or repair-required |
settlement_allocate |
settlement ID | Deterministic replay | All lines allocated or exception |
payout_match |
payout ID | Retry while bank window open | Approved match or exception |
mart_refresh |
mart + partition | Safe replay | Watermark and row-count checks |
Workers claim jobs using fenced leases and compare the fence token before committing results. A worker processes one tenant context per transaction and clears it before accepting another job.
Retry classification¶
| Class | Examples | Behavior |
|---|---|---|
| Safe transient | 429, pre-mutation 502/503, queue outage |
Exponential backoff with jitter and provider limit |
| Business block | missing mapping, closed period, invalid state, total mismatch | No automatic retry until dependency version changes |
| Authentication/config | expired secret, disabled connection, permission loss, drift | Disable affected capability and alert operations |
| Ambiguous mutation | timeout, connection loss after request delivery | verification_required; read before any retry |
| Permanent contract | unsupported enum/schema, invariant failure | Quarantine and require code/policy change |
Retries preserve operation_id and request hash and create a new attempt_id and delivery ID. Operators cannot force a mutation retry while verification is incomplete.
Service objectives¶
| Objective | Pilot target |
|---|---|
| Webhook durable receipt availability | 99.9% monthly |
| Valid webhook to canonical projection | p95 under 5 minutes |
| Hourly Airbyte run completion | 95% within 90 minutes; 99% within 4 hours |
| Valid approved order to draft Odoo sale order | p95 under 15 minutes |
| Odoo readback after mutation | p95 under 2 minutes; p99 under 15 minutes |
| Settlement availability after source publication | p95 under 4 hours |
| Approved payout to bank reconciliation | p95 under one business day after bank evidence exists |
| Unknown mutation classification | 99% within 30 minutes; 100% within 24 hours or incident |
| Cross-tenant leakage | Zero |
| Unexplained automatic write-off | Zero |
SLOs are measured per tenant and source connection as well as globally. Planned provider outages are reported but not removed from data-correctness measures.
Observability¶
Every log, metric, trace, and audit event carries safe forms of:
tenant_id
source_connection_id
odoo_connection_id
ingestion_run_id
canonical aggregate ID
operation_id and attempt_id
correlation_id
contract/adapter/policy/mapping version
status and stable error code
Required dashboards:
- source freshness, run success, cursor age, and rejected/quarantined records;
- canonical control-total failures and adapter schema drift;
- mapping backlog and aging;
- operation queue depth, attempts, unknown outcomes, and repair tasks;
- settlement allocation, payout matching, bank matching, and clearing-account differences;
- Odoo latency, throttling, authentication failure, capability expiry, and drift;
- per-tenant posting volume, failure rate, SLO burn, and last confirmed readback.
Alerts page on cross-tenant/security indicators, sustained ingestion loss, unknown Odoo mutation age, settlement imbalance near close, and clearing-account mismatch. Ordinary mapping exceptions enter a work queue rather than paging.
Security and privacy¶
- Source, Airbyte, webhook, Odoo, database, and object-store secrets live in the secrets manager and rotate independently.
- Webhook signatures are verified against the raw request body. Odoo Studio bearer webhook secrets are not described as signatures.
- Egress allowlists and SSRF protections restrict source and Odoo destinations to provisioned connections.
- PostgreSQL uses forced RLS, composite tenant foreign keys, non-owner runtime roles, and transaction-local tenant context.
- Queue payloads contain opaque IDs, not credentials or raw customer payloads.
- Raw payload access is role-restricted, time-bound, audited, and unavailable in standard support tools.
- Logs, traces, exports, error messages, and dead-letter records redact credentials and customer/payment data.
- Payment card data is never intentionally ingested. Connector catalogs and payload schemas are tested to prevent PAN/CVV storage.
- Data subject handling distinguishes erasable customer data from restricted statutory accounting evidence.
- Backups, restores, and disaster-recovery exercises prove tenant isolation and operation uniqueness.
Test layers¶
| Layer | Mandatory coverage |
|---|---|
| Unit | Decimal arithmetic, signs, tax/discount allocation, event IDs, state transitions, mapping selection |
| Adapter contract | Recorded source fixtures, schema drift, unknown enums, deletion, duplicate and out-of-order records |
| Database | Composite tenant FKs, forced RLS, uniqueness, immutability, leases, optimistic concurrency, outbox/inbox |
| API/event contract | OpenAPI/JSON Schema, unknown properties, versions, errors, idempotency, pagination |
| Airbyte integration | Catalog/version capture, incremental replay, lookback, failed run, bounded backfill, count/amount controls |
| Odoo clone | Access, company isolation, create/confirm/deliver/invoice/post/pay/refund/return/reconcile/readback |
| Failure injection | 429, secret expiry, schema drift, worker crash, duplicate delivery, timeout before/after mutation |
| Security | Cross-tenant API/SQL/queue/cache/object/log/export tests, webhook forgery/replay, SSRF, role escalation |
| Accounting | Golden orders, tax/rounding, partial fulfillment, refunds, fees, payouts, disputes, clearing reconciliation |
| Warehouse | Fact/mart grain, uniqueness, lineage, late corrections, metric fixtures, freshness, source-to-mart controls |
| Governance | Classification, prohibited-data detection, retention/hold, subject restriction, export, offboarding |
| Recovery | Restore database/object evidence, resume outbox/jobs, classify unknown operations without duplicates |
| Runbook | Tabletop and failure-injection exercises with evidence and exit-criteria verification |
Property tests assert that allocations balance, cumulative refunds/returns never exceed approved bounds, replay is idempotent, and no confirmed state exists without required evidence.
Pilot acceptance criteria¶
- One Shopify pilot tenant completes a historical backfill and seven consecutive days of hourly sync without unexplained missing source IDs or monetary control differences.
- Duplicate and out-of-order webhooks produce one canonical outcome and no duplicate Odoo operation.
- Every posted Odoo object is traceable to source payload hash, canonical event, policy/mapping version, operation, attempt, and readback.
- Order, fulfillment, invoice, payment, refund, return, settlement, payout, and bank states can progress independently.
- A timeout after each supported Odoo mutation is recovered by search/readback without a duplicate confirmed mutation in clone testing.
- Settlement lines balance to provider payout, payout matches the bank transaction, and Odoo clearing residual is zero or an approved explicit rounding amount.
- Negative tenant-isolation tests cannot retrieve another tenant's data through API, SQL, queue, object storage, cache, logs, search, or export.
- Unsupported tax, currency, gift-card, dispute, inventory, and accounting-period cases fail closed with stable codes.
- Restore testing meets the platform RPO/RTO and resumes ingestion and operation processing without violating uniqueness.
- Accounting, security, and operations owners sign the tenant policy, threat model, runbook, and go-live report.
- Every governed mart passes grain, uniqueness, lineage, freshness, and source-to-fact-to-mart control totals by tenant/date/currency.
- Classification, retention/hold, subject restriction, export expiry, and tenant-offboarding tests cover every storage and processor class.
- Ingestion lag, Odoo unknown outcome, settlement imbalance, credential rotation, schema drift, stale mart, cross-tenant exposure, and restore runbooks pass exercises.
Delivery milestones¶
Milestone E0: contract proof¶
- Approve the contract registry and commit OpenAPI, event schemas, canonical SQL migrations, mart models/tests, Shopify fixtures, accounting examples, governance metadata, and Odoo clone test plan.
- Verify connector catalog and Odoo capabilities using non-production credentials.
- Obtain accounting sign-off for
order_invoice_v1and the clearing-account design.
Milestone E1: ingestion and canonical shadow¶
- Implement source connections, capabilities, ingestion runs/inbox, webhook verification, Airbyte monitoring, raw evidence, canonical events, mappings, projections, warehouse facts/marts, and completeness/control checks.
- Run without Odoo mutation and compare source control totals for at least seven days.
Milestone E2: Odoo posting shadow¶
- Implement mappings, policies, posting intents, operations, Odoo adapters, evidence fields, capability scans, and readback.
- Execute only in a representative Odoo clone; reconcile all golden cases.
Milestone E3: controlled pilot¶
- Enable one tenant with manual approval for every mutation.
- Reconcile daily source, canonical, Odoo, settlement, payout, bank, and clearing totals.
- Require zero unresolved high-severity defects and no unknown mutation older than 24 hours.
Milestone E4: policy automation¶
- Auto-approve only proven ordinary cases under the same policy version.
- Keep refunds, returns, disputes, mapping changes, period overrides, and repair actions reviewed.
- Expand tenants only after per-tenant capability and policy sign-off.
Milestone E5: additional sources/profiles¶
- Add Amazon/eBay or summary posting through separate adapters, schemas, policies, fixtures, reconciliation rules, and architecture decisions.
- Scale infrastructure only when measured throughput, concurrency, retention, recovery, SLO, and cost thresholds require it.
Required implementation artifacts¶
The post-Odoo implementation artifact guide maps the executable readback-to-reporting slice and its deployment gates. The code repository must contain version-controlled sources for the complete pilot:
docs/assets/downloads/ecommerce/ecommerce-reporting-v1.openapi.yaml
docs/assets/downloads/ecommerce/*.schema.json
schemas/source/*.json # pending upstream source slice
db/migrations/*commerce*.sql
db/tests/*.sql
dbt/models/**/*.sql
dbt/models/**/schema.yml
fixtures/shopify/*.json # pending pilot evidence
fixtures/odoo/*.json # pending clone evidence
policies/order_invoice_v1.schema.json # pending accounting approval
monitoring/prometheus/*.rules.yml
scripts/check_ecommerce_artifacts.py
The required semantics and acceptance controls are defined by the contract registry. Generated documentation may render executable artifacts, but hand-written prose is not a substitute for machine-validated schemas, migrations, mart models, capability fixtures, and contract tests. Runbook automation may use separate files or be generated from Operational runbooks, but its steps and exit criteria may not be weakened.