---
name: fp-prd-to-erd
description: Convert a PRD into an Engineering Requirements Document using this repo's architecture, decisions, and patterns as constraints. Produces interface contracts, data model diffs, module boundaries, security considerations, and acceptance criteria. Writes to fastpace/docs/erd/<slug>.md. Triggers on /fp-prd-to-erd <prd-slug>.
---

# fp-prd-to-erd

Translate a PRD into an ERD that's *grounded* — its design choices reflect the repo's real architecture, prior decisions, and codified patterns. A generic ERD is a failed ERD; cite the source for every non-obvious choice.

## Preflight

1. **PRD must exist.** Read `fastpace/docs/prd/<slug>.md`. If missing, tell the user to run `/fp-write-prd <slug>` first and stop.
2. **Context load (mandatory, in order):**
   - `fastpace/context/architecture.md` — module boundaries, entry points.
   - `fastpace/context/patterns.md` — idioms you should reuse.
   - `fastpace/context/decisions.md` + `fastpace/docs/adr/*.md` — constraints you can't quietly violate.
   - `fastpace/context/learnings.md` — pitfalls to route around.
   - `fastpace/context/glossary.md` — canonical vocabulary for the ERD.
3. **External doc bodies (optional).** If the PRD frontmatter has a `references:` block, run `fastpace refs resolve <slug>` once (silently — no user prompt; idempotent), then list `fastpace/.refs-bodies/<slug>/`. If files exist, read each one — they're cached plain-text dumps of Confluence pages / Google Docs that the PRD already links to. Architecture decisions in those docs are *binding* on this ERD. Skip silently if no refs or providers not configured.
4. **Check for conflicts.** If the PRD's goals would require contradicting a decision/ADR, **stop** and ask the user: "This PRD needs to contradict decision `<date>` / ADR NNNN. Want to write a new ADR to supersede, or rescope the PRD?" Do not write an ERD that silently violates a decision.

## Process

1. **Propose the design** to yourself first, privately. Don't ask the user to design — ask the user to approve.
2. **Write the ERD** to `fastpace/docs/erd/<slug>.md` using the format below.
3. **Every non-trivial choice carries a citation** (see citation rule).
4. **Surface risks and open questions** explicitly. An ERD with an empty "Risks" section is a lie.
5. **Threat model + compliance check** (after the ERD file is written). Run both — see "Threat model & compliance check" below. Fold the findings back into the ERD before showing the draft.
6. **Show the draft** to the user before the final save. Offer a "what would you push back on" prompt.
7. **Auto-discover external refs** (only if a provider has auto-discovery enabled — most repos won't). Run `fastpace refs suggest <slug>` against the freshly-written ERD body. Show top candidates as a numbered list and ask which to add. **Never add silently.** See "Auto-discovery" below.

## ERD format (exact)

```markdown
---
title: <feature name>
slug: <slug>
status: draft
prd: fastpace/docs/prd/<slug>.md
created: <YYYY-MM-DD>
author: <user>
---

# <feature name> — Engineering Requirements

## Overview

<2-3 sentences. Include a link to the PRD and the one-line summary of the PRD's goal.>

## Proposed design

<Narrative + ASCII or mermaid diagram if helpful. Keep it high-level here;
details go in later sections. Mention which modules are touched and which
entry points are added/changed.>

<Cite architecture.md for any boundary decision: "Per architecture.md,
`api/cart` owns checkout flow — this feature extends that module.">

## Interface contracts

<For every public function, endpoint, event, or message, list:
- signature with types
- success / error shapes
- backward-compat notes if the surface exists>

Example:

```
POST /api/cart/submit
  req:   { items: CartItem[], payment: { pan, exp_month, exp_year, cvc } }
  200:   { order_id: string }
  400:   { error: "invalid_card" | "declined" | ..., hint?: string }
  auth:  session cookie (existing)
```

## Data model changes

<Schema diffs. Mention migration strategy. Cite decisions.md for any
modeling choice that's been discussed before.>

- New table? Migration direction?
- New index? Why + measured query it supports.
- New column on existing table? Default value + backfill plan.
- No changes? Say so explicitly ("no schema change").

## Module boundaries

<What goes where. What must NOT change. If you're extending a module,
cite architecture.md's module list.>

## Security considerations

This section is **never empty.** If the feature genuinely has no security
surface, write: "Low — see below" and explain why (e.g. internal tooling,
no PII, no auth boundary crossed).

Cover at minimum:
- **authn / authz:** <new checks, scopes, role changes>
- **input validation:** <what's validated, where>
- **rate limiting:** <needed? existing middleware?>
- **PII / sensitive data:** <what's handled, redaction, logging rules — cite decisions.md if a redaction rule exists>
- **secrets handling:** <new secrets? how stored?>

## Observability

- **Logs added:** <structured keys, cardinality notes>
- **Metrics added:** <counter/histogram names + labels>
- **Traces added:** <span boundaries>
- **Alerts added:** <thresholds + escalation>

## Performance

- Expected load: <RPS / QPS / concurrent users>
- Constraints: <p99 latency, memory, throughput>
- Benchmarks needed: <yes/no — if yes, what shape>

## Rollout plan

- **Flag:** <feature flag name, default state>
- **Canary:** <% / duration / success criterion>
- **Rollback trigger:** <metric regression threshold>
- **Dependencies to land first:** <other PRs / migrations>

## Acceptance criteria

<Copied forward from PRD, sharpened with test hooks. Each criterion must
map to a test or a manual check. Use this format:>

| # | Criterion | Test |
|---|-----------|------|
| 1 | luhn checksum passes | unit `tests/cards.test.ts` |
| 2 | expiry in future | unit `tests/cards.test.ts` |
| 3 | rejected cards return 400 with `invalid_card` | integration `tests/api/cart.test.ts` |

## Risks & open questions

- **Risk:** <what could go wrong> · **mitigation:** <plan or "accept">
- **Open question:** <what needs a decision before implementation>

## Alternatives considered

Brief. Name 1-3 alternatives rejected, with 1-2 sentences each.

- **<Alternative>:** rejected because <reason, citing context if applicable>.

## References

- PRD: `fastpace/docs/prd/<slug>.md`
- Decisions cited: `fastpace/context/decisions.md § <date>`, `ADR <NNNN>`
- Patterns reused: `fastpace/context/patterns.md § <name>`
- Architecture: `fastpace/context/architecture.md § <section>`
```

## Threat model & compliance check

Once the ERD file exists, run these two commands (idempotent; safe to re-run with `--force` on the threat model). Both read the security section you just wrote and emit signed audit events.

```bash
fastpace threat-model <slug> --force
fastpace compliance check-erd <slug>
```

- **`threat-model`** seeds a STRIDE + LINDDUN model at `fastpace/threats/<slug>.md` from the signals in your Security section, and flags any STRIDE category that *applies but has no mitigation* as an open gap. For each open gap it reports, either (a) add the missing mitigation to the ERD's Security section, or (b) record it as an explicit accepted risk under **Risks & open questions** with a rationale. Do not leave a flagged gap silent.
- **`compliance check-erd`** resolves the frameworks from the PRD's `**Regulatory:**` constraint (or pass `--framework <slug>`), pulls the mapped controls from `framework-mapping.md`, and writes `fastpace/compliance/erd-<slug>.md` listing which controls the ERD addresses vs. leaves open. For each **open** control, add a sentence to the Security section covering it, or note in **Risks** why it's out of scope for this feature.

If the PRD declares no regulatory frameworks, `check-erd` will say so — that's fine; skip it. If either command is unavailable (license tier / not installed), skip silently and note in the ERD that the threat model / compliance check was not run.

When you show the draft (step 6), summarize for the user: STRIDE categories that apply, any open threat gaps, and per-framework addressed/open control counts.

## Citation rule

For any non-trivial design choice, cite the context file that drove it. Examples:

- Choosing retry policy → cite `patterns.md § retry-with-backoff`.
- Not logging PAN → cite `decisions.md § 2025-02-14`.
- Putting code in `api/cart/` → cite `architecture.md § modules`.
- Avoiding a repeated bug → cite `learnings.md § <date>`.

Citations in the ERD go in the body where the choice is made, not in a list at the end. Future readers see *why* next to *what*.

## Rules

- **No ad-hoc library choices.** If the ERD introduces a new dependency (npm / pip / cargo), call it out explicitly: "New dependency: `<name>@<version>` — needed for `<reason>`. Alternatives considered: `<other>`." The user must approve before you finalize.
- **No code implementations.** The ERD is a design doc. Short pseudocode / signatures are fine; full function bodies are not.
- **Security is not optional.** An empty security section fails the ERD.
- **Ground every boundary call.** If you say "this goes in module X", cite architecture.md.
- **Don't weaken acceptance criteria.** If the PRD says "reject cards with expired dates", the ERD can't silently drop that.
- **Mark `TBD` instead of guessing.** Performance numbers, canary percentages, migration timing — if the user hasn't said, write TBD + add to Open Questions.

## Integration

- After the ERD is written, tell the user: "Next: `/fp-erd-to-execplan <slug>` once this is approved, to break it into waves/epics/stories."
- The threat model at `fastpace/threats/<slug>.md` becomes an input to the risk register — mention it's available.
- If you had to flag a decision conflict, suggest `/fp-write-adr` to formally supersede it.
- If the ERD surfaced a brand-new pattern worth reusing, suggest `/fp-remember` for `patterns.md`.

## Auto-discovery (optional, off by default)

If `references.resolvers.confluence.auto_discover.enabled` or `.google-docs.auto_discover.enabled` is true in `fastpace.config.yaml`, run after step 5:

```bash
fastpace refs suggest <slug> --limit 5
```

The query uses the ERD body you just wrote (architecture-heavy text — usually surfaces different docs than the PRD did, since ERDs include module names, library choices, security concerns).

Show candidates as a numbered list and ask:

> *"Add any of these to the ERD's references? Reply with numbers (e.g. `1, 3`) or `none`."*

For each chosen item, run `fastpace refs add <slug> --url <url> --title "<title>"`. Architecture docs and security policies are common hits at this stage.

If both providers are off (default), skip silently.

## Exit criteria

- File written at `fastpace/docs/erd/<slug>.md` with `status: draft`.
- Every non-trivial design choice has a citation.
- Security section non-empty.
- Risks & Open questions non-empty (or explicitly "none — and here's why").
- Threat model generated (`fastpace/threats/<slug>.md`) and every open STRIDE gap either mitigated in the ERD or accepted under Risks. (Skip only if the command is unavailable — note that in the ERD.)
- Compliance check run if the PRD declares a regulatory framework, and every open control addressed or noted out-of-scope.
- Output: file path + acceptance-criteria count + threat-model open-gap count + suggested next command.
