feat: sync latest ARR implementation

This commit is contained in:
Wyndham ARR
2026-07-31 15:11:42 +08:00
parent d6f8a747fa
commit bf7939dd1a
185 changed files with 17527 additions and 2260 deletions

View File

@@ -2,32 +2,52 @@
## Current Architecture
The ARR system accepts an Opera XML upload, stores the private source artifact, invokes an Agent for deterministic processing, validates the returned structured result, and commits accepted Finance facts to PostgreSQL. Downstream analytics and report programs consume those committed facts. The accepted target flow automatically triggers monthly processing after the commit; the current manual monthly UI/API remains a known implementation gap.
ARR2.0 accepts Opera XML plus a separate Booking Tour Code/`โรงแรม` workbook and owns both deterministic processing
lifecycles. It writes immutable private
objects, runs the frozen processor locally, independently validates the complete artifacts, and atomically commits
accepted facts to PostgreSQL. Downstream analytics and report programs read committed facts.
Successful daily commits also create a durable outbox event. A separate worker derives the affected month and watermark
from committed `ARRIVAL` facts, publishes a validated workbook, and records metadata-only report state in PostgreSQL.
## Main Components
| Component | Responsibility | Notes |
|---|---|---|
| `arr_web` | XML upload, job status, controlled downloads and business APIs | The existing manual monthly-generation request is not the accepted primary flow. |
| SuperAgent + deterministic processing skill | Convert XML to the approved structured result | Must not decide user-facing report parameters. |
| `arr_mcp` / ingestion service | Independently validate/replay and atomically commit accepted structured results | Automatic downstream trigger begins only after commit success. |
| PostgreSQL Finance facts | Authoritative current and retained daily facts | Source of truth for downstream reports. |
| `monthly_reports` | Generate monthly XLSX from committed database facts | Internal month/cutoff inputs are allowed; `TOTAL PRICE` must be an XLSX formula. |
| `channel_analytics` / `company_reports` | Additional read/report consumers | Must not change the monthly-report trigger contract. |
| Caddy + Compose deployment boundary | Terminate HTTPS, authenticate Web users, keep Web/MCP ports internal and start the explicit processing profile | MCP still performs its own bearer check and DNS-rebinding Host validation. |
| Component | Responsibility |
|---|---|
| `arr_web.auth` / authenticated `SessionLedger` | Environment-owned operator credentials, bounded login attempts, random server-side sessions, CSRF and logout revocation |
| `arr_web.programmatic` | Terminal upload orchestration and safe public error mapping |
| `arr_processing.local` / `arr_processing.policy` | Isolated frozen processor execution and approved version/rule identity |
| `arr_storage` | Immutable staged/committed OSS workflow; all object ACLs private |
| `arr_ingestion.validation` | Strict delivery/result/structured validation plus independent daily validation |
| `arr_ingestion.postgres` | Job lifecycle, artifact registration, atomic Finance version commit and outbox |
| `booking_ingestion.excel` | Bounded Tour Code/`โรงแรม` extraction, latest-row/cancellation semantics and room-item normalization |
| `booking_ingestion.excel_review_postgres` | Durable editable draft state and zero-pending atomic current-source activation |
| `arr_web.booking_uploads` | Private Booking workbook upload, draft review orchestration and privacy-minimized source summaries |
| `arr_web.job_trace` | Read-only programmatic trace from persisted run/attempt/delivery/version/outbox facts |
| `monthly_reports.worker` | Dedicated leased outbox consumer with retry/dead-letter behavior |
| `monthly_reports.repository` / `reporting` schema | ARRIVAL-derived snapshots, report versions, lineage, manifests and artifact identities |
| `monthly_reports`, `channel_analytics`, `company_reports` | Deterministic downstream consumers of committed facts |
| Web + Caddy Compose | Web-owned login/session boundary behind Caddy HTTPS; no browser-native Basic Auth and no MCP service |
## Important Boundaries
- XML processing and Finance fact validation happen before the monthly-report trigger.
- The user-facing upload workflow does not collect monthly report year, month, or cutoff date.
- Monthly processing reads validated database facts rather than repeating Agent business logic.
- Database `total_price` may support validation, but the exported `TOTAL PRICE` cell must remain a formula.
- Container deployment enables XML processing through both the Dockerfile default Web CMD and the explicit Compose command, and still requires `processing_ready=true`; direct source CLI execution remains default-closed.
- The uploaded source is re-materialized from committed object storage before processing.
- Login documents/assets, `POST /api/login` and minimal `/healthz` readiness are the only anonymous Web routes. Portal documents redirect to login; business APIs, detailed health, uploads, traces and downloads return `401` without an authenticated server-side session.
- Operator credentials come only from runtime `ARR_WEB_USERNAME` / `ARR_WEB_PASSWORD`; the application fails closed when either is absent. Authenticated mutations also require the per-session CSRF token.
- Processor exit code and JSON status must agree; output paths are confined to an isolated temporary directory.
- Validation completes before the database transaction; any transaction failure leaves no partial active version.
- Booking uploads create review drafts first. Only an explicit activation with no retained pending items can atomically
create immutable Booking facts and switch `booking.current_source_batch`; an open draft blocks company-report creation.
- Only recognized transient PostgreSQL concurrency errors receive bounded transaction retries.
- PostgreSQL state, not HTTP/console output, is authoritative for success.
- Daily downloads are read from OSS and rechecked; monthly downloads resolve only registered active/superseded local artifacts and recheck path, size and SHA-256.
- Fresh uploads are new jobs/versions; exact delivery replay is idempotent.
- Monthly success is acknowledged only after both artifacts are registered and the publication is active; replay of the same snapshot returns the existing report.
## Related Decisions
- [ADR-004](../10-decisions/ADR-004-arr-owned-programmatic-processing.md)
- [ADR-001](../10-decisions/ADR-001-automatic-monthly-trigger-and-total-price-formula.md)
## Last Updated
2026-07-29
2026-07-31