Write requirements about outcomes and observable behavior. Keep explicit user choices; do not replace their product with a preferred solution.
Work
- Extract the user goal, initiating event, allowed actor, inputs, result, and failure behavior from the brief or running product.
- Give requirements stable IDs only when traceability helps. Prefer “An editor can rename a project; a viewer cannot” to legalistic filler.
- For each write, identify server authorization, validation, persistence, duplicate submission behavior, and what happens if the result is unknown after a timeout.
- Specify applicable quality constraints with conditions: target devices, input methods, content size, latency measurement, supported languages, privacy, and availability. Mark proposed targets as proposals.
- Name dependencies, unresolved contract questions, and excluded scope. Do not invent APIs or imply they exist.
- When revisiting implementation, report which requirements are met, changed, missing, or unverified, with evidence.
Deliver
Use requirement → acceptance example → dependency/unknown. Add only enough examples to distinguish correct behavior from a plausible implementation.
Write each requirement as:
FR-01: [actor + behavior]. Accept: [observable example]. Depends/unknown: [...] NFR-01: [constraint + condition]. Verify: [scoped check] Close with out-of-scope, assumptions, open questions, and next step.
Include a failure or boundary case for consequential behavior. “Accessible,” “fast,” and “secure” need scoped verification criteria. Use $flow when branch order is the open question; $component when a reusable interaction needs a contract.
Worked example
FR-01: An editor can rename a project; a viewer cannot. Accept: a viewer's direct rename request is rejected by the server and the stored name is unchanged. Depends: role data per organization.
FR-02: A rename that times out does not apply twice. Accept: resubmitting after a timeout leaves one stored name and one audit entry. Unknown: whether the API supports idempotency keys.
FR-03: The project list keeps its status filter in the URL. Accept: a copied link opens the same filtered list. Depends: none.
NFR-01: Renaming works with a keyboard alone. Verify: complete a rename without a pointer; focus returns to the project name.
NFR-02 (proposed, not agreed): The project list shows usable content within 2 s on the client's field phones over a throttled mobile profile. Verify: measure on that device profile once the client confirms the target.
Out of scope: bulk rename, rename history view.
Assumptions: project names are unique per organization.
Open questions: what a viewer sees when an editor renames a project they have open.
Next: $flow for the rename path, including two editors renaming at once.
Gotchas
- A permission check that only says the button is hidden passes a build that lets anyone call the API; include a direct-request case.
- Writes fail a third way: the request times out after the server saved, so consequential writes need a retry requirement.
- A requirement that names a component ("add a dropdown") locks in a solution before anyone designed it.
- "Fast", "secure", and "accessible" cannot fail a test until they have a condition and a check.
- Endpoint names written into requirements get treated as existing contracts; list undocumented APIs as unknowns.
Boundaries
- Do not use when the idea is still vague (who it is for, what outcome it serves); use
$intentinstead. - Do not use when the open question is navigation or which pages exist; use
$sitemapinstead. - Do not use to map the step-by-step path of a task; use
$flowinstead.