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": "hr-approve-applicant-documents",
  "title": "Review & approve an applicant's documents",
  "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). Honest scope: with the default config, draft guides are served to everyone right next to published ones. Production hosts should set config('splain.playback.serve_drafts') to false. There is also a stored phi_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": "SubmissionResource (Document Submissions review queue)",
  "role_in_workflow": "The review queue table ...",
  "route": "/hr/submissions" }

Steps

Marked required below is what splain:check enforces; in practice every step also wants 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" }
]

phi_risk: flagging sensitive data

"phi_risk": {
  "renders_phi": 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@b6ea439. The documentation is rendered from the package repository — the same files that ship with Splain — so the site can't drift from the code.