letmesplain

The guide JSON, field by field

This is the reference for everything that can appear in a guide. For a gentle start, read authoring.md first; to test what you wrote, see checking.md.

Every field below is tagged one of two ways:

One safety promise up front: a malformed guide degrades to "this guide is absent" on the page, never to an error on your app.

The guide (top level)

{
  "slug": "approve-a-document",
  "title": "Review & approve a submitted document",
  "genre": "walkthrough",
  "spans": [ ... ],
  "steps": [ ... ]
}

Two more fields live on the database row (the splain_guides table), not in the JSON you write: status (draft or published, default draft) and version (an integer, default 1, part of the completion-tracking key). Draft guides are hidden from regular users by default (serve_drafts ships false); gate-passers preview them in place. There is also a stored pii_default flag on the row; nothing acts on it today.

Spans: the pages a guide covers

A span names one place the guide touches:

{ "resource": "DocumentResource (document review queue)",
  "role_in_workflow": "The review queue table ...",
  "route": "/admin/documents" }

Steps

splain:check only fails if key, span_ref, or anchor are missing; a useful step also needs order, title, and instruction (they default to blank, which plays but says nothing).

Anchors: pointing at the right thing

"anchor": {
  "selector": "[data-splain=\"start-review\"]",
  "component_name": "the Start Review button",
  "fallback_selectors": ["[data-splain=\"row-review\"]"],
  "needs_injected_attr": true,
  "recommended_attr": "->extraAttributes(['data-splain' => 'start-review']) on the start_approval header Action"
}

Naming data-splain markers: kebab-case, {thing} or {thing}-{role}start-review, doc-accept, branch-wallet-section. Name the thing the way a human would say it.

Decision options

A decision step lists the real buttons the user can choose between:

"options": [
  { "label": "Accept",
    "anchor": { "selector": "[data-splain=\"doc-accept\"]" },
    "status_effect": "IN_REVIEW -> ACCEPTED; reviewed_at=now; auto-advances",
    "next": "accept-all-gating" }
]

pii_risk: flagging sensitive data

"pii_risk": {
  "renders_pii": true,
  "types": ["name"],
  "mask_target": "The Submitted By and Reviewed By columns",
  "mask_selectors": [
    { "selector": ".fi-table-cell-submitter\\.name", "mode": "blur" }
  ]
}

Honest scope, verbatim in spirit from privacy-mode.md: Privacy Mode is a demo and screen-recording aid, not a security control. The data stays in the page; masking is purely visual.


Rendered from splain@a738cf8. The documentation is rendered from the package repository — the same files that ship with Splain — so the site can't drift from the code.