Files
familienarchiv/.specify/templates/api-contract-stub.md
Marcel 48d1e59326
Some checks failed
SDD Gate / Contract Validate (pull_request) Waiting to run
SDD Gate / Constitution Impact (pull_request) Waiting to run
CI / Unit & Component Tests (pull_request) Has been cancelled
CI / OCR Service Tests (pull_request) Has been cancelled
CI / Backend Unit Tests (pull_request) Has been cancelled
CI / fail2ban Regex (pull_request) Has been cancelled
CI / Semgrep Security Scan (pull_request) Has been cancelled
CI / Compose Bucket Idempotency (pull_request) Has been cancelled
SDD Gate / RTM Check (pull_request) Has been cancelled
fix(sdd): add Spectral ruleset so contract-validate passes
Spectral v6 ships no implicit ruleset — the CI job exited 'no ruleset found'.
Adds .spectral.yaml (extends spectral:oas, documentation-only warnings relaxed
for design-time stubs), adds operation tags to the _example contract so it lints
clean (0 results), and aligns the api-contract-stub note.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 12:16:48 +02:00

98 lines
4.1 KiB
Markdown

# API Contract Stub
This project is **REST + OpenAPI**. The backend serves the live spec via springdoc at
`http://localhost:8080/v3/api-docs` (dev profile only), and the frontend generates its
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 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. 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).
## OpenAPI 3.1 skeleton
```yaml
openapi: 3.1.0
info:
title: Familienarchiv API — <feature name>
version: 0.0.1-SNAPSHOT
description: Design-time contract for <feature>. Source of truth is the generated /v3/api-docs.
servers:
- url: http://localhost:8080
description: Local backend (dev profile)
- url: https://archiv.raddatz.cloud
description: Production (behind Caddy)
components:
securitySchemes:
cookieAuth: # Spring Session JDBC — opaque session id in the SESSION cookie
type: apiKey
in: cookie
name: SESSION
schemas:
ErrorResponse: # shape produced by GlobalExceptionHandler
type: object
required: [code, message]
properties:
code:
type: string
description: Machine-readable ErrorCode (see ErrorCode.java / errors.ts).
example: FORBIDDEN
message:
type: string
# <YourResponseView>: # always a view, never a lazy-collection entity (ADR-036)
# type: object
# required: [id]
# properties:
# id: { type: string, format: uuid }
security:
- cookieAuth: [] # default: every path requires a session unless overridden to []
paths:
/api/<resource>:
post:
summary: <create …>
operationId: <createResource>
security:
- cookieAuth: [] # plus @RequirePermission(Permission.X) on the controller
requestBody:
required: true
content:
application/json:
schema: { $ref: '#/components/schemas/<CreateDTO>' }
responses:
'201':
description: Created
content:
application/json:
schema: { $ref: '#/components/schemas/<YourResponseView>' }
'400': { description: Validation failed, content: { application/json: { schema: { $ref: '#/components/schemas/ErrorResponse' } } } }
'401': { description: Unauthenticated, content: { application/json: { schema: { $ref: '#/components/schemas/ErrorResponse' } } } }
'403': { description: Missing permission, content: { application/json: { schema: { $ref: '#/components/schemas/ErrorResponse' } } } }
```
## Validating the contract in CI
The `sdd-gate.yml` `contract-validate` job lints any committed OpenAPI file changed in the PR:
```bash
npx @stoplight/spectral-cli lint <your-contract>.yaml
```
The ruleset is `.spectral.yaml` at the repo root (extends `spectral:oas`; documentation-only
warnings relaxed for design-time stubs). Spectral auto-discovers it. It catches malformed
specs, undefined `$ref`s, and duplicate `operationId`s; tune `.spectral.yaml` to adjust.