refactor(sdd): make the feature spec issue-only (no committed spec.md)

The Gitea issue body is the single source of truth for a spec; the only
per-feature artifact in git is the RTM row (REQ-ID -> issue # -> test). Drops
per-feature spec.md/tasks.md/checklist files from the workflow (the _example
stays as a template/reference). Updates the guide, ADR-041, AGENTS.md, CLAUDE.md,
templates, the RTM (adds an Issue column), the implement/review-pr skills, and
replaces the file-spec CI jobs with an rtm-check.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-06-13 12:14:32 +02:00
committed by marcel
parent fa6677a7c5
commit c160ab3223
13 changed files with 178 additions and 202 deletions

View File

@@ -6,19 +6,21 @@ TypeScript client from it with `npm run generate:api` (`openapi-typescript` →
`frontend/src/lib/generated/api.ts`). There is no GraphQL in this stack.
> **The live spec is generated from the Java controllers — it is the source of truth.** A
> hand-written contract under `.specify/features/<name>/api-contract.yaml` is a *design
> artifact*: it pins the intended shape during spec review and is checked against the
> generated spec once the endpoint exists. Keep it OpenAPI **3.1**, and keep
> `@Schema(requiredMode = REQUIRED)` on the Java side as the real driver of `required`.
> hand-written stub is a *design artifact*: it pins the intended shape during spec review.
> Issue-only: paste the stub inline into the issue's `## API / Contract Stub` section. Keep it
> OpenAPI **3.1**, and keep `@Schema(requiredMode = REQUIRED)` on the Java side as the real
> driver of `required`.
## How to use this stub
1. Copy the skeleton below to `.specify/features/<name>/api-contract.yaml`.
2. Fill in the paths/methods/schemas your feature adds. Every mutating path documents the
`403`/`401` responses and the `cookieAuth` security requirement (matching the real
`@RequirePermission` gate).
3. The `sdd-gate.yml` CI job lints any changed `api-contract.yaml` with Spectral
(`npx @stoplight/spectral-cli lint`). Run it locally the same way before pushing.
1. Fill in the skeleton below with the paths/methods/schemas your feature adds, and paste it
into the issue's `## API / Contract Stub` section.
2. Every mutating path documents the `403`/`401` responses and the `cookieAuth` security
requirement (matching the real `@RequirePermission` gate).
3. If you prefer a standalone, lintable file (e.g. for a large contract), commit it on the
**feature branch** as `<feature>.openapi.yaml` — the `sdd-gate.yml` CI job lints any
committed OpenAPI contract with Spectral (`npx @stoplight/spectral-cli lint`). It never
needs to predate the issue.
4. After the endpoint ships, run `npm run generate:api` and diff the generated types against
this contract; reconcile any drift (the generated spec wins — update the contract).

View File

@@ -1,10 +1,10 @@
<!--
Feature Spec template — copy this into a Gitea issue body (or .specify/features/<name>/spec.md).
Replace every <placeholder>. Delete this comment block before submitting.
Feature Spec template — paste this into the Gitea issue body (issue-only: this IS the spec;
there is no committed spec.md). The .gitea/ISSUE_TEMPLATE/feature.md mirror gives the same
structure with the right labels. Replace every <placeholder>. Delete this comment before submitting.
EARS = Easy Approach to Requirements Syntax. Every requirement uses one of the five patterns
shown in ## Requirements and carries a unique REQ-NNN id (three-digit, scoped to THIS feature).
Companion artifacts live beside this file: design.md, api-contract.yaml, threat-model.md,
adr-NNN-*.md, tasks.md, checklist-results.md.
Use plain code-path references (not relative markdown links) — links don't resolve inside a Gitea issue.
-->
# <Feature title — match the Gitea issue: "As a <role> I want <capability> so <reason>">
@@ -13,10 +13,10 @@
<Business motivation in 24 sentences: who needs this and why now.>
Constitution principles this feature depends on:
- [§<n> <principle name>](../../constitution.md#<anchor>) — <why it applies>
Constitution principles this feature depends on (see `.specify/constitution.md`):
- §<n> <principle name> — <why it applies>
Related: <links to prior issues / ADRs / specs>.
Related: <links to prior issues / ADRs>.
## User Journey
@@ -51,7 +51,7 @@ Related: <links to prior issues / ADRs / specs>.
## API / Contract Stub
<Inline stub OR link to `./api-contract.yaml`. Name the new/changed paths, methods, request/response shapes, status codes, and `@RequirePermission`.>
<Inline OpenAPI stub. Name the new/changed paths, methods, request/response shapes, status codes, and `@RequirePermission`. Use the `.specify/templates/api-contract-stub.md` skeleton as a writing aid.>
## Data Model Changes
@@ -59,7 +59,7 @@ Related: <links to prior issues / ADRs / specs>.
## Security Considerations
<STRIDE categories touched (Spoofing/Tampering/Repudiation/Information disclosure/DoS/Elevation). For AI-agent/tool features, also ASTRIDE. Link to `./threat-model.md` if the feature has a non-trivial attack surface.>
<STRIDE categories touched (Spoofing/Tampering/Repudiation/Information disclosure/DoS/Elevation). For AI-agent/tool features, also ASTRIDE. Include an inline STRIDE table (use `.specify/templates/threat-model.md`) if the feature has a non-trivial attack surface.>
## Open Questions
@@ -75,7 +75,7 @@ Related: <links to prior issues / ADRs / specs>.
| REQ-001 | <T-1> | <test name> | Planned |
| REQ-002 | <T-2> | <test name> | Planned |
<Mirror these rows into [.specify/rtm.md](../../rtm.md). Fill Task/Test IDs as work progresses.>
<After approval, add one committed row per REQ-NNN to `.specify/rtm.md` with this issue's number. Fill Task/Test IDs as work progresses.>
## Persona Review Results

View File

@@ -1,12 +1,14 @@
<!--
Threat model template — STRIDE + ASTRIDE. Lives at .specify/features/<name>/threat-model.md.
Required when a feature adds a new trust boundary, handles uploads, exposes a new mutating
endpoint, or invokes an AI agent/tool. The Security persona gates this file. Delete this comment.
Threat model template — STRIDE + ASTRIDE. WRITING AID: fill this in and paste the result into
the issue's "## Security Considerations" section (issue-only — the threat model lives in the
issue body, not a committed file). Required when a feature adds a new trust boundary, handles
uploads, exposes a new mutating endpoint, or invokes an AI agent/tool. The Security persona
gates it during /review-issue. Delete this comment.
-->
# Threat Model — <Feature name>
**Feature spec:** [./spec.md](./spec.md)
**Feature spec:** Gitea issue #<n>
**Date:** <YYYY-MM-DD>
**Author:** <name>