{
  "schema_version": "1.0",
  "baseline": "A-document-access-service-v3",
  "phase": "Batch 13 · team-usable",
  "updated_at": "2026-04-20",
  "owner": "session_a",
  "purpose_en": "Contract for /api/access/render — the Batch-13 server-delivered HTML render path. Server reads the target file from DOCS_ROOT, evaluates access state, and returns either the full body, a restricted variant, or a stub. A meaningful improvement over envelope-only gating.",
  "purpose_th": "สัญญา /api/access/render · Batch 13 · server อ่านไฟล์จาก DOCS_ROOT · ประเมินสิทธิ์ · ส่ง body ครบ · variant restricted · หรือ stub",
  "honest_note": "This provides SERVER-DELIVERED HTML for the target document. However the ORIGINAL static URL (e.g. /planning/document-access-model.html) remains served by whatever hosts the static site. For true HTTP-level route protection, a reverse-proxy rule is still required to route all traffic through /api/access/render. That's a deployment concern, not a service concern.",
  "endpoint": {
    "method": "GET",
    "path": "/api/access/render",
    "query": {
      "doc_id": "string (required) · path under DOCS_ROOT, must end with .html · validated against traversal",
      "token": "string (optional; rejected when DAS_REJECT_QUERY_TOKEN=true)"
    },
    "auth": "Cookie ds_session OR Authorization: Bearer (preferred) OR ?token= (unless rejected)",
    "returns": "text/html"
  },
  "state_to_response": {
    "visible":      { "body": "full file contents", "headers": { "X-DAS-Render-State": "visible",      "Cache-Control": "private, no-store" } },
    "restricted":   { "body": "file contents with sticky RESTRICTED banner injected after <body>", "headers": { "X-DAS-Render-State": "restricted",   "Cache-Control": "private, no-store" } },
    "hidden-doc":   { "body": "minimal inline-styled stub",   "headers": { "X-DAS-Render-State": "hidden-doc",   "Cache-Control": "private, no-store" } },
    "hidden-group": { "body": "minimal inline-styled stub",   "headers": { "X-DAS-Render-State": "hidden-group", "Cache-Control": "private, no-store" } },
    "not-granted":  { "body": "minimal inline-styled stub",   "headers": { "X-DAS-Render-State": "not-granted",  "Cache-Control": "private, no-store" } }
  },
  "security_checks": [
    "doc_id starts without leading slash, must end with .html",
    "doc_id cannot contain '..', ':' or backslash path segments",
    "resolved absolute path must start with DOCS_ROOT + sep (prevents traversal)",
    "file must exist and be a regular file",
    "response headers include X-DAS-Render-State + Cache-Control: private, no-store"
  ],
  "versus_gate_envelope": {
    "envelope_endpoint": "/api/access/gate",
    "envelope_returns":  "JSON with allow_render, render_mode, stub_html · client must cooperate",
    "render_endpoint":   "/api/access/render",
    "render_returns":    "actual HTML · client can display directly without further decisions",
    "use_case_for_envelope": "pages already loaded with shell JS that want to read access state + selectively mask",
    "use_case_for_render":   "proxying / fetch-and-display paths where the response IS the page"
  },
  "client_usage_pattern_reverse_proxy": "nginx / Cloudflare rules could rewrite all /planning/*.html → /api/access/render?doc_id=... · this achieves real HTTP-level gating. NOT implemented in this service (deployment concern).",
  "client_usage_pattern_client_fetch": "shell JS fetches /api/access/render and renders the response into an iframe or dom replacement · in-scope for Batch 13 as an option (current shell uses /api/access/gate + body-swap instead).",
  "non_goals_this_batch": [
    "Automatic rewriting of legacy static HTML URLs · reverse-proxy platform concern",
    "Streaming response",
    "Request body caching",
    "Per-role content variants within the same file (mask specific sections)"
  ],
  "cross_references": {
    "access_contract":  "docs/runtime/document-access-service/access_contract.json",
    "gating_contract":  "docs/runtime/document-access-service/gating_contract.json",
    "deployment":       "docs/runtime/document-access-service/deployment.md",
    "planning":         "docs/planning/document-http-gating.html"
  }
}
