feat: add public h5 dashboard and publish traceability
This commit is contained in:
@@ -2,9 +2,13 @@
|
||||
|
||||
## Web Access Boundary
|
||||
|
||||
1. An anonymous browser requesting `/` or `/h5` is redirected to `/login` with an allowlisted return target; anonymous API/download requests receive JSON `401 AUTH_REQUIRED`.
|
||||
1. An anonymous browser requesting `/` is redirected to `/login` with an allowlisted return target. `/h5` and its H5
|
||||
assets are public; anonymous access is limited to `/api/public/h5/months`, `/api/public/h5/analytics` and the
|
||||
no-detail `/healthz` signal. Other anonymous API/download requests receive JSON `401 AUTH_REQUIRED`.
|
||||
2. `POST /api/login` accepts strict same-origin JSON, verifies runtime-owned credentials under a bounded per-client attempt ledger and issues a random server-side session plus CSRF token in an `HttpOnly`, `SameSite=Strict` cookie.
|
||||
3. Every portal page, detailed health response, read API, upload/mutation, task trace and artifact download validates the authenticated session. Mutations additionally validate the session CSRF token.
|
||||
3. Every desktop portal page, detailed health response, generic read API, upload/mutation, task trace and artifact
|
||||
download validates the authenticated session. Public H5 endpoints return only sanitized aggregate dashboard data;
|
||||
mutations additionally validate the session CSRF token.
|
||||
4. `POST /api/logout` validates CSRF, revokes the server-side session and expires the cookie. `/healthz` remains a no-detail anonymous readiness signal for container orchestration.
|
||||
5. `GET /api/history-months` is an authenticated read-only discovery path. It combines daily processing/monthly publication counts from PostgreSQL with durable company-job counts; each desktop history then reads its selected month through the existing paged list endpoint.
|
||||
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
| `arr_storage/aliyun_oss_v2.py` | Encrypted/unversioned OSS adapter | Writes all objects private |
|
||||
| `arr_web/downloads.py` | OSS daily + controlled local report download routing | Rechecks metadata, size and SHA-256 |
|
||||
| `arr_web/job_trace.py` | Programmatic persisted-fact trace | No external trace store |
|
||||
| `arr_web/app.py`, `arr_web/repository.py`, `arr_web/company_jobs.py` | Authenticated portal routes, paged history reads and read-only history-month discovery | Default-deny login gate protects pages/APIs/downloads; daily/monthly counts and rows share a repeatable-read snapshot; `/api/history-months` merges daily/monthly database counts with company job-state counts; company totals/slices share one lock |
|
||||
| `arr_web/app.py`, `arr_web/repository.py`, `arr_web/company_jobs.py` | Authenticated portal routes plus public H5 aggregate routes, paged history reads and read-only history-month discovery | Default-deny login gate protects the desktop/API/download surface; purpose-built `/api/public/h5/*` exposes only sanitized aggregate metrics; daily/monthly counts and rows share a repeatable-read snapshot; `/api/history-months` merges daily/monthly database counts with company job-state counts; company totals/slices share one lock |
|
||||
| `arr_web/server.py` | Standard-library HTTP transport | Dispatches GET/POST/PATCH/DELETE with one bounded body reader; real socket tests cover review update/delete and missing/oversized lengths |
|
||||
| `arr_web/static/login.html`, `login.css`, `login.js` | Responsive ARR login gateway | Labeled form, password visibility, generic inline failures, safe desktop/H5 return target and reduced-motion support |
|
||||
| `arr_web/static/app.js`, `arr_web/static/h5.js` | Authenticated client state, rendering and polling | Desktop daily/monthly/company histories own independent viewing-month state and default to the latest non-empty month; company generation month remains separate. Desktop also includes 50-row Booking draft review/edit, the draft's validated uploaded filename below the review title, individual/all-visible selection, count-aware in-page delete confirmation and activation; company generation keeps the fixed five-company context beside the page title, a four-card upload/period setup row, cumulative CO display labels, short centered period actions and an in-page generation confirmation dialog; session-expiry redirect and CSRF logout remain shared; monthly versions auto-refresh the selected viewing month every four seconds |
|
||||
| `arr_web/static/app.js`, `arr_web/static/h5.js` | Authenticated desktop and anonymous-capable H5 client state, rendering and polling | Desktop daily/monthly/company histories own independent viewing-month state and default to the latest non-empty month; company generation month remains separate. H5 reads only public aggregate endpoints and may retain optional logout for an authenticated session. Desktop also includes 50-row Booking draft review/edit, the draft's validated uploaded filename below the review title, individual/all-visible selection, count-aware in-page delete confirmation and activation; company generation keeps the fixed five-company context beside the page title, a four-card upload/period setup row, cumulative CO display labels, short centered period actions and an in-page generation confirmation dialog; session-expiry redirect and CSRF logout remain shared; monthly versions auto-refresh the selected viewing month every four seconds |
|
||||
| `monthly_reports/worker.py` | Dedicated outbox consumer | Lease/reclaim, retry/dead-letter, success acknowledgement after activation |
|
||||
| `monthly_reports/repository.py` | Monthly snapshot and publication repository | Derives scope from `ARRIVAL`; persists metadata/lineage/artifact identities |
|
||||
| `monthly_reports/xlsx/build_workbook.mjs` | Monthly XLSX builder and reopen validator | Exact row-relative `TOTAL PRICE` formulas only in column S |
|
||||
@@ -26,7 +26,7 @@
|
||||
| `database/012_monthly_report_publication.sql` | Additive metadata-only publication schema | Applied after immutable 008–011 baseline |
|
||||
| `database/014_booking_current_source_batch.sql` | Booking full-workbook current-source pointer and view scoping | Formally applied on 2026-07-31; batch 1 remains selected |
|
||||
| `database/015_booking_excel_review_drafts.sql` | Item-level Booking extraction draft state | Formally applied and empty; basic latest-state review only, with no actor/reason/revision history and no DB-enforced zero-pending activation |
|
||||
| `compose.yaml`, `deploy/` | Web-login + Caddy-HTTPS template and worker deployment boundary | Requires Web credentials; only `/healthz` is anonymously probed; no MCP port/domain/service |
|
||||
| `compose.yaml`, `deploy/` | Web-login + Caddy-HTTPS template and worker deployment boundary | Requires Web credentials for the desktop/operational surface; public H5 aggregate routes and `/healthz` remain anonymously reachable; no MCP port/domain/service |
|
||||
| `tests/test_arr_programmatic.py` | Real success/failure vertical slices | Primary ARR2.0 acceptance proof |
|
||||
|
||||
Historical ARR1 compatibility modules and migrations remain for audit/tests but are not imported, installed or deployed
|
||||
|
||||
@@ -31,7 +31,9 @@ from committed `ARRIVAL` facts, publishes a validated workbook, and records meta
|
||||
## Important Boundaries
|
||||
|
||||
- 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.
|
||||
- Login documents/assets, the H5 read-only page/assets, purpose-built public H5 aggregate endpoints, `POST /api/login`
|
||||
and minimal `/healthz` readiness are anonymous Web routes. The desktop portal redirects to login; generic 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.
|
||||
|
||||
Reference in New Issue
Block a user