> ## Documentation Index
> Fetch the complete documentation index at: https://synthetiq.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# PRD structure

> Sections, entry types, and how feature, API access, and calculation entries differ

The PRD lives in `prd.json` at the app root, alongside the test files that back it:

```
prd.json            — the requirements document (sections, entries, access matrix)
prd/tests/          — Playwright specs for feature entries (one per entry, recorded)
prd/api/            — API access specs (headless, no browser)
prd/unit/           — calculation specs (real implementation, exact values)
prd/fixtures/       — shared seed fixtures and service stub responses
prd/recordings/     — generated videos and run manifests
```

Every entry is bound 1:1 to a test: the entry names the test file, and the test's title must equal the entry id. The build fails on an entry with no test, so there is no way to add an unverified claim.

## Features vs. API access

The PRD view presents the app through two top-level sections:

* **Features** — what the app *does*: user-visible flows, business behaviors, side-effects, cross-service merges. Verified end-to-end in a browser and recorded.
* **API Access & Rules** — the rules the backend *enforces*: who can call each endpoint, how each endpoint's rows are scoped to the caller, and the invariants the boundary rejects on. Verified headlessly with real requests, in both directions: the permitted call succeeds and really changes the data, and the denied call is rejected.

The dividing line: **is the requirement a rule the boundary enforces, or something the app does?** Rules that deny an anonymous caller, filter another user's rows, or reject a fourth task when three are active belong to API access. Behaviors that send the Slack message, compute the score, or render the dashboard are features, even when conditioned on ownership or permissions.

A rule can appear in both, because the two sections verify different things: the API row proves the boundary can't be bypassed; the feature recording shows what the user experiences. "Users only see their own tasks" is an API row (the query denies) and also a feature assertion (the screen omits).

## Anatomy of a feature entry

Each feature belongs to a section and gets exactly **one hero test**: the canonical end-to-end flow a reviewer watches. Visible details of that flow ("the completed task shows a strikethrough") are assertions inside the hero, not separate entries. Splitting them out would produce many near-identical videos.

A feature may nest **one level** of children for what the hero flow doesn't show:

* **A visual child** — a distinct state or screen the hero never passes through: the empty state, the error state, the at-limit view. Each gets its own small recording.
* **A calculation child** — the internal logic powering the feature (a score formula, tax math, a validation rule), where the input space is combinatorial and there is nothing distinct to watch. Verified as a table of checked values; see [Verifying calculations](/docs/platform-docs/app-framework/prd/verifying-calculations).

A hero test verifies logic too: it asserts what's on screen and what the flow left in the data, so "the deleted task is gone" is checked in both places. The split decides where the *extra* cases go. A case with something distinct to watch is a visual child; a case that's one of many input combinations, where the runs would look identical and only the numbers differ, is a calculation child.

A failing child fails its feature, even when the hero flow passed. Nesting stops at one level; a child that would need children of its own is a separate feature, and the build rejects a grandchild.

## Anatomy of an access entry

The access side of `prd.json` carries one entry per backend procedure. Each entry declares a structured **access contract**: whether the caller must be signed in, which scopes are required, and how rows are scoped to the caller (own rows only, rows reachable through a relationship such as a reporting chain, rows in the caller's org, and so on).

The contract is a machine-checked decision table, not prose. The build derives from it the exact set of scenarios the entry's test must cover (anonymous denied, wrong scope denied, the owner's call works, another user's doesn't, each business rule rejects) and fails until every one exists. The plain-language "who can do this" text in the PRD view is generated from the contract, never hand-written. See [Access verification](/docs/platform-docs/app-framework/prd/access-verification).

## Choosing where something goes

| The thing to verify                                           | Where it goes                                |
| ------------------------------------------------------------- | -------------------------------------------- |
| A flow a user would name ("add a task", "generate a summary") | A feature with a hero test                   |
| A visible detail of that flow                                 | An assertion inside the hero                 |
| A distinct screen or state the hero doesn't reach             | A visual child                               |
| A formula or rule with many input cases                       | A calculation child                          |
| Who can call an endpoint, and whose rows it returns           | An access entry                              |
| An input or state the backend must reject                     | A business-rule scenario on the access entry |
| A separate journey ("a manager reviews their team")           | Its own feature                              |
