Batch 8 replaces the Batch-7 browser-local-only access model with a real FastAPI backend at docs/runtime/document-access-service/. The backend issues opaque session tokens (UUID v4), reads users from a file-backed JSON store, and resolves per-document visibility against the Batch-7 visibility matrix. The Universal Document Shell now attempts backend resolution first and falls back to the browser-local model when offline.
Batch 8 เปลี่ยนจาก access model ที่อยู่แค่ browser ใน Batch 7 เป็น backend FastAPI จริงที่ docs/runtime/document-access-service/ · ออก token UUID v4 · อ่าน user จากไฟล์ · ตัดสิน visibility ต่อเอกสารตาม matrix จาก Batch 7 · shell ลอง backend ก่อน · ถ้า offline จะ fallback ใช้ local
Real backend path with honest "local/dev auth" labeling · graceful offline fallback · share/export policy bound to access state · 5 shelled pages enforce · other pages still legacy.
Backend จริงพร้อมป้าย honest · fallback เมื่อ offline · share/export ผูกกับสิทธิ์ · 5 หน้าบังคับใช้ · หน้าอื่นยัง legacy
The backend exposes 7 endpoints: health · login · logout · me · resolve · groups · documents. Login accepts any email present in the file-backed roster (user_store_examples.json) and issues a cookie + token. Resolve returns visibility state, allow_read/share/export flags, and bilingual banners. The shell tries backend first; on success updates the current user and applies per-page decisions (banner + share/export button enable/disable + content blur when read is denied). Offline reverts to Batch-7 behavior with an explicit "OFFLINE · LOCAL FALLBACK" badge.
Backend เปิด 7 endpoints · login ใช้อีเมลจากคลังไฟล์ · ออก cookie + token · resolve คืนค่า state + flag อนุญาต · shell ลอง backend ก่อน สำเร็จใช้ผลตัดสินจาก server · ล้มเหลวกลับไปใช้ local พร้อมป้าย OFFLINE ที่ honest
Browser (shelled page) │ ├── document-shell.js │ └── initBackend() → GET /api/access/me │ GET /api/access/resolve?doc_id=… │ ↓ │ applyBackendDecision() │ ├─ visibility banner │ ├─ share/copy/print enable/disable │ └─ content mask (blur) when !allow_read │ ↓ fetch (credentials:include) │ Document Access Service · http://127.0.0.1:8090 (local/dev) ├── FastAPI (app.py) │ ├── GET /api/access/health │ ├── POST /api/access/login → issue UUID token + cookie │ ├── POST /api/access/logout → drop token │ ├── GET /api/access/me → profile OR anonymous │ ├── GET /api/access/resolve → state + policy per doc │ ├── GET /api/access/groups → per-user group map │ └── GET /api/access/documents → filtered list (hidden omitted) │ ├── user_store_examples.json (file-backed user roster) └── document_visibility_matrix.json (group→doc map · consumed read-only)
| Method | Path | Purpose | Auth |
|---|---|---|---|
| GET | /api/access/health | Liveness · user-store stats | none |
| POST | /api/access/login | email → token + cookie | body{email} |
| POST | /api/access/logout | Invalidate token | cookie |
| GET | /api/access/me | Current profile (anonymous fallback) | cookie/query/bearer |
| GET | /api/access/resolve | Per-doc visibility + policy | cookie/query/bearer |
| GET | /api/access/groups | Per-user group visibility | cookie/query/bearer |
| GET | /api/access/documents | Filtered doc list (hidden omitted) | cookie/query/bearer |
| GET | /api/access/debug/user-store | DEV dump | none · dev only |
Full contract: session_contract.json · access_contract.json
group_id from doc_id via document_visibility_matrix.json.group_id in profile.hidden_groups → hidden-group.group_id not in profile.visible_groups → hidden-group.doc_id in profile.hidden_documents → not-granted.profile.visible_documents is non-null and doc_id not in it → hidden-doc.doc_id in profile.restricted_documents → restricted.Precedence · ลำดับ: hidden_groups > hidden_documents > restricted_documents > visible_documents > visible_groups.
| State | allow_read | allow_share | allow_export | UI behaviour · พฤติกรรม UI |
|---|---|---|---|---|
| visible | ✓ | ✓ | ✓ | No restriction · ไม่มีข้อจำกัด |
| restricted | ✓ (metadata) | ✗ | ✗ | Banner + share/copy/print disabled · เนื้อหาบังบาง · ปุ่มแชร์/คัดลอก/พิมพ์ถูก disable |
| hidden-doc | ✗ | ✗ | ✗ | Content blurred · banner · ทุกปุ่ม disable |
| hidden-group | ✗ | ✗ | ✗ | Content blurred · banner · ทุกปุ่ม disable |
| not-granted | ✗ | ✗ | ✗ | Content blurred · banner · ทุกปุ่ม disable |
Honest: the shell disables UI surfaces only. Once a URL is known it can be shared externally. Future step: server-side content gating. · ระดับ UI เท่านั้น · ภายนอก share URL ได้เอง · backend gating ยังไม่มี
Not retrofitted (still legacy presentation): all other planning/runtime/KB/demo pages. They receive no access enforcement · ยังไม่ถูก retrofit · ไม่มีการ enforce สิทธิ์
If the shell cannot reach the backend (server not running · network error · wrong base URL), the mode badge flips to OFFLINE · LOCAL FALLBACK and all Batch-7 browser-local behavior continues. The user panel keeps creating/switching browser-local profiles. Visibility is advisory (not enforced).
ถ้า shell ติดต่อ backend ไม่ได้ · ป้ายเปลี่ยนเป็น OFFLINE · LOCAL FALLBACK และใช้ behavior แบบ Batch 7 · user panel ยังสร้าง/เปลี่ยน profile ได้ · แต่ไม่มีการ enforce จริง
Base URL resolution: <html data-ds-auth-base="…"> → window.DS_AUTH_BASE → default http://127.0.0.1:8090. Set to none to disable backend attempts entirely.
| Date | Change · รายการ |
|---|---|
| 2026-04-20 | v1.0 · initial backend + shell integration · Batch 8 |