5 Authoring in Quarto
5.1 .need blocks
The authoring surface remains simple: objects are declared as Pandoc Div blocks with the .need class.
::: {.need #NFR-001 type="non-functional-requirement" status="approved" priority="high" tags="performance"}
verified-by: TC-006
implemented-by: COMP-002
## Respond to authorization within the latency objective
The authorization decision shall remain within the defined SLO under nominal load.
### Rationale
Centralized policy is acceptable only if it does not materially degrade the experience.
:::Machine-queryable metadata stays in the block preamble; human explanations remain in Markdown. This distinction prevents documentation from becoming an excessively structured form.
A ### Rationale section inside the block is indexed into the object’s machine-readable rationale field — so per-field diffs, baselines, and exports see it — while the body itself is preserved verbatim. A rationale: preamble key, when present, takes precedence.
5.1.1 Anatomy of a block
A .need block has three parts, in this order:
-
The opening fence, which carries the required
#IDand optional inline attributes. -
The preamble, a YAML-like
key: valueregion. It ends at the first heading, or at the first line that is neitherkey: valuenor a-list item. Blank lines inside it are ignored, not terminators. - The body, ordinary Markdown. Its first heading becomes the object title; without a heading, the title falls back to the ID.
Because a prose line closes the preamble, keep every key: value line above the body. A metadata line written after a sentence is read as body text: it is not an attribute, not a relation, and produces no diagnostic.
Both the fence attributes and the preamble write to the same set of keys, so status can be declared in either place. When the same key appears in both, the preamble wins. Use the fence for short scalars and the preamble for anything that benefits from being on its own line.
5.1.2 Reserved keys
These keys have defined meaning; everything else becomes a queryable attribute.
| Key | Default | Meaning |
|---|---|---|
#ID |
— | Required. The object’s identity, given on the fence as a Pandoc identifier. |
type |
need |
Engineering type. Drives roles, required attributes, prefixes, and badge color. |
status |
draft |
Lifecycle status. Validated against allowed-statuses when configured. |
title |
first body heading | Object title. Falls back to the ID when neither is present. |
rationale |
### Rationale section |
Machine-readable rationale. The key takes precedence over the section. |
priority, tags, and date are ordinary attributes rather than reserved keys, but they receive dedicated presentation: priority gets a badge and rank-aware sorting, tags renders as tag chips and feeds the tag catalog, and date appears on architecture-decision cards.
5.1.3 Relations and attributes
Any preamble key that names a relation in the catalog declares relations; every other key becomes an attribute readable as attributes.<name> in named queries.
::: {.need #FUN-014 type="functional-requirement" status="approved" priority="high"}
derives-from: SYS-003
verified-by: TC-020, TC-021
implemented-by:
- COMP-PARSER
- COMP-ANALYSIS
owner: Platform team
expires: 2027-01-31
## Reject malformed declarations
:::Multiple targets are written either as one value separated by commas or semicolons, or as a - list on the following lines. The two forms are equivalent.
Declare each key once per block. The preamble is a mapping, so repeating a key keeps only its last occurrence; write verified-by: TC-020, TC-021 or the list form instead of two verified-by: lines. A repeated key is reported as QND003 so the discarded value cannot pass unnoticed.
Relation targets are not resolved while parsing. A target that names no declared object is reported as REQ005 during validation, which is how typos surface instead of becoming silent dead ends.
5.2 References and views
The book can project the graph with shortcodes such as:
{{< need NFR-001 title=true >}}
{{< need-table types="architecture-decision" columns="id;title;status" >}}
{{< need-matrix rows="functional-requirement" columns="test-case" relation="verified-by" >}}
{{< need-flow root="NFR-001" depth="4" direction="LR" >}}
{{< need-inspector ADR-002 >}}
{{< need-graph view="graph-exploration" >}}
{{< need-c4 root="SYS-001" level="context" >}}
{{< adr-table status="accepted" >}}
{{< adr-count status="accepted" >}}Views read the canonical artifact; they do not reimplement semantic rules in the renderer.
The views reference documents every registered shortcode, its selectors and options, interactive controls, and page-sidebar configuration.
5.3 Tag index and deep linking
For a clickable tag catalog, create a chapter (e.g. tags.qmd) containing:
{{< need-tags >}}This shortcode renders interactive tag chips and a consolidated table of all tagged objects. To link every tag badge across the site into this page, configure _quarto.yml:
quarto-needs:
tags-page: tagsWhen configured, clicking any tag badge anywhere in the project navigates to tags.html?tag=<slug> with that tag pre-filtered.
5.4 Localized titles
Object titles can be localized without duplicating the engineering model. Place a translated sibling next to its canonical source file, adding the locale to the stem — for example, declare objects in requirements.qmd and provide requirements.pt-BR.qmd:
- Both files must declare the same object IDs with the same types, statuses, attributes, and relations. Only the title, body, and rationale may differ; a sibling that changes engineering metadata fails the render with an error.
- Localized siblings are presentation sources. The canonical graph is built from the unsuffixed files; localized files never add, remove, or hide objects.
-
quarto-needs scanvalidates every localized sibling and writes the approved titles to.quarto-needs/i18n/<locale>.json. - The page filename suffix selects the locale (for example,
chapter.pt-BR.qmdrenders as pt-BR). Views, tables, dashboards, and theneed-graphcanvas render the localized titles for that locale, falling back to the canonical title when a locale has no entry for an object. Spell the locale identically in sibling filenames and page filenames — the mapping is exact, not case-normalized.
English pages keep the canonical titles; no default title map is required. The language server keeps localized siblings consistent across ID renames.
5.5 Prefix configuration
Prefixes are declared per type:
[types.system-requirement]
id-prefix = "SYS-"
[types.architecture-decision]
id-prefix = "ADR-"When configured, an incompatible ID produces ID001. For a project that needs a compound namespace:
[types.architecture-decision]
id-prefix = "PAY-ADR-"When the project context already defines the domain, use shorter prefixes. The goal is readable identity, not ritual namespace repetition.