feat(sdd): add .specify scaffold — constitution, AGENTS, personas, templates, example, RTM

Introduces the SDD root: a v1.0.0 constitution and machine-readable AGENTS.md
grounded in the project's real conventions; six EARS-aware persona spec-review
checklists that cross-reference .claude/personas/; feature-spec/ADR/threat-model/
api-contract templates; a fully worked _example feature; a living RTM; and an
adrs/ pointer that reuses the existing docs/adr/ archive.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-06-13 11:56:31 +02:00
parent 982a437523
commit 01f51854f6
21 changed files with 1266 additions and 0 deletions

36
.specify/rtm.md Normal file
View File

@@ -0,0 +1,36 @@
# Requirements Traceability Matrix (RTM)
> Living document. One row per `REQ-NNN` across all in-flight and shipped features. It links
> a requirement to the design that realises it, the code that implements it, and the
> test(s) that prove it — so any requirement can be traced end to end, and any orphan
> (a requirement with no test, or a test with no requirement) is visible.
## How to update
1. When a `spec.md` is approved, copy its `## Traceability` rows here with `Status: Planned`.
2. As tasks land, fill `Implementation File(s)` and flip `Status``In progress``Done`.
3. `REQ-ID`s are **scoped per feature**, so always qualify with the Feature column — `REQ-001`
in *avatar* is not `REQ-001` in another feature.
4. The `sdd-gate.yml` CI job (`traceability-check`) warns (non-blocking, for now) when a
`spec.md` contains a `REQ-NNN` that does not appear in this file. Keep it in sync to keep
the warning quiet; it flips to blocking once adoption settles (see the workflow's TODO).
## Status legend
`Planned` · `In progress` · `Done` · `Deferred`
## Matrix
| REQ-ID | Requirement Summary | Feature | Design Artifact | Implementation File(s) | Test(s) | Status |
|---|---|---|---|---|---|---|
| REQ-001 | Store avatar at `avatars/{userId}`, overwrite | profile-picture-upload (_example) | features/_example/design.md; adr-001 | `UserService` (planned) | `UserServiceAvatarTest#storesUnderUserKey`, `#replaceLeavesNoOrphan` | Planned |
| REQ-002 | Upload self avatar → 200 + avatarUrl | profile-picture-upload (_example) | features/_example/design.md; api-contract.yaml | `UserAvatarController`, `UserService` (planned) | `UserAvatarControllerTest#uploadReturnsAvatarUrl` | Planned |
| REQ-003 | Delete self avatar → avatarUrl null | profile-picture-upload (_example) | features/_example/api-contract.yaml | `UserAvatarController` (planned) | `UserAvatarControllerTest#deleteClearsAvatar` | Planned |
| REQ-004 | No avatar → null + initials placeholder | profile-picture-upload (_example) | features/_example/design.md | `UserProfileView`, avatar component (planned) | `avatar-placeholder.svelte.spec.ts` | Planned |
| REQ-005 | ADMIN_USER may delete others' avatar | profile-picture-upload (_example) | features/_example/api-contract.yaml | `UserAvatarController` (planned) | `UserAvatarControllerTest#adminDeletesOthersAvatar` | Planned |
| REQ-006 | Unauthenticated → 401, store nothing | profile-picture-upload (_example) | features/_example/threat-model.md | `SecurityConfig`, controller (planned) | `UserAvatarControllerTest#unauthenticatedReturns401` | Planned |
| REQ-007 | Non-image → 400 UNSUPPORTED_FILE_TYPE | profile-picture-upload (_example) | features/_example/design.md | `UserService` (planned) | `UserAvatarControllerTest#rejectsNonImage` | Planned |
| REQ-008 | Over 2 MB → 400 AVATAR_TOO_LARGE | profile-picture-upload (_example) | features/_example/design.md | `UserService`, `ErrorCode` (planned) | `UserAvatarControllerTest#rejectsOversize` | Planned |
| REQ-009 | Non-admin on others → 403 FORBIDDEN | profile-picture-upload (_example) | features/_example/threat-model.md | `UserAvatarController` (planned) | `UserAvatarControllerTest#nonAdminForbiddenOnOthers` | Planned |
<!-- Append real features below this line. Keep the header row above. -->