{
  "schema_version": "1.0",
  "baseline": "A-document-note-system-v1",
  "updated_at": "2026-04-19",
  "owner": "session_a",
  "purpose_th": "Schema สำหรับระบบ Notes / Requirements ของเอกสารใน console · ทุกหน้าเอกสารที่ opt-in ใน document-shell.js จะใช้ schema นี้",
  "purpose_en": "Field specification for the Document Notes / Requirements / Improvement Requests system. Every document page that opts into document-shell.js adheres to this schema. Notes are currently browser-local (localStorage). Server-side persistence deferred.",
  "honest_note": "Backing: localStorage ONLY in this batch. No server round-trip. No cross-device sync. The schema is designed so that a future server backend can consume the same field shape without migration — any persistence upgrade must respect note_id stability.",
  "storage_key_pattern": "ds.notes:<doc_id>",
  "doc_id_resolution": "Read from <html data-ds-doc-id> attribute. Falls back to location.pathname if not set. SHOULD be stable across renames — if a page moves, the owning team supplies a redirect note linking old doc_id to new.",
  "fields": {
    "note_id": {
      "type": "string",
      "format": "note-<base36-timestamp>-<5char-random>",
      "required": true,
      "stability": "immutable",
      "description_en": "Unique identifier for a single note. Generated client-side. Stable across edits."
    },
    "doc_id": {
      "type": "string",
      "required": true,
      "description_en": "Page identifier from data-ds-doc-id. Used as the partitioning key for storage."
    },
    "section_ref": {
      "type": "string | null",
      "required": false,
      "description_en": "Optional anchor to the specific section the note refers to (e.g. 'checklist', 'glossary', 'references#ref-3'). Null if whole-document."
    },
    "created_at": {
      "type": "string",
      "format": "ISO-8601 UTC",
      "required": true,
      "description_en": "When the note was first created. Never overwritten."
    },
    "created_by_type": {
      "type": "enum",
      "values": ["human", "AI", "system", "imported"],
      "required": true,
      "default": "human",
      "description_en": "Source kind. 'AI' reserved for notes created by an automated sweep (see document_note_sweep_model.json). 'system' = infra-generated. 'imported' = migrated from another store."
    },
    "title": {
      "type": "string",
      "required": true,
      "max_length": 200,
      "description_en": "Human-readable summary of the note / requirement."
    },
    "body": {
      "type": "string",
      "required": false,
      "description_en": "Full text of the note. Newlines preserved."
    },
    "note_type": {
      "type": "enum",
      "values": [
        "bug",
        "content-gap",
        "structure",
        "linkage",
        "metadata",
        "glossary",
        "references",
        "export",
        "design",
        "runtime-mismatch",
        "enhancement",
        "requirement"
      ],
      "required": true,
      "default": "requirement",
      "description_en": "Category of the note — informs how an AI sweep triages it."
    },
    "priority": {
      "type": "enum",
      "values": ["P0", "P1", "P2", "P3"],
      "required": true,
      "default": "P2",
      "description_en": "P0 = blocker · P1 = critical · P2 = normal · P3 = nice-to-have. Used by periodic sweep to order backlog."
    },
    "status": {
      "type": "enum",
      "values": ["open", "triaged", "in_review", "planned", "in_progress", "done", "deferred", "rejected"],
      "required": true,
      "default": "open",
      "transitions": "See document_note_status_matrix.json",
      "description_en": "Current lifecycle state of the note."
    },
    "resolved_flag": {
      "type": "boolean",
      "required": true,
      "derived_from": "status",
      "rule": "true when status in ('done', 'rejected')",
      "description_en": "Convenience flag mirroring terminal states. UI uses this for struck-through rendering."
    },
    "linked_change_ref": {
      "type": "string | null",
      "required": false,
      "description_en": "Optional pointer to a commit hash, PR id, or change-log entry that resolved the note. Used by AI sweep for linked-change verification."
    },
    "resolved_at": {
      "type": "string | null",
      "format": "ISO-8601 UTC",
      "required": false,
      "description_en": "Timestamp when status first reached a terminal value. Null if never resolved."
    },
    "last_action_at": {
      "type": "string",
      "format": "ISO-8601 UTC",
      "required": true,
      "description_en": "Updated on every mutation. Used by UI to show 'latest activity' and by AI sweep to flag stale items."
    }
  },
  "cross_references": {
    "status_matrix": "docs/assets/notes/document_note_status_matrix.json",
    "sweep_model":   "docs/assets/notes/document_note_sweep_model.json",
    "examples":      "docs/assets/notes/document_note_examples.json"
  },
  "planned_upgrades": [
    "Server-side persistence · PostgreSQL table ds.document_note · schema parity with this file",
    "Per-note audit trail (history of transitions)",
    "Notification wiring when a note transitions (Slack / LINE / email · TBD)",
    "Cross-device sync once authenticated session layer exists",
    "Bulk export to JSON / CSV for backlog review"
  ]
}
