Files
familienarchiv/.specify/constitution.md
Marcel 01f51854f6 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>
2026-06-13 11:56:31 +02:00

6.7 KiB

Familienarchiv Constitution

Version: v1.0.0 Status: Ratified Date: 2026-06-13 Adoption ADR: docs/adr/041-sdd-adoption.md

The non-negotiable rules of this project. Every spec, every PR, and every AI agent is bound by this document. Rules here are deliberately few and absolute — guidance and rationale live in CLAUDE.md, COLLABORATING.md, CODESTYLE.md, CONTRIBUTING.md, and the ADR archive (docs/adr/). When this file conflicts with any of those, this file wins — open an ADR to change it.

Versioning is semantic: MAJOR = a rule removed or weakened (existing code may now violate the constitution), MINOR = a rule added or tightened, PATCH = wording only. Any change requires the Sync Impact review in the last section.


1. Architecture Principles

  1. The backend is organised package-by-domain under org.raddatz.familienarchiv; a new domain lives in its own package, never spread across layer packages.
  2. Controllers never call repositories directly — a controller calls only services.
  3. A service accesses only its own domain's repository; cross-domain data is fetched through the other domain's service, never its repository.
  4. The frontend mirrors the backend domain split under frontend/src/lib/<domain>/, and cross-domain imports are allowed only where frontend/eslint.config.js (boundaries/dependencies) permits them.
  5. A Person (historical subject) and an AppUser (login account) are distinct domains and never share an identity or an account guard.
  6. Lazy-collection-bearing entities are never serialized across the controller boundary; the owning service assembles an explicit view inside the transaction (see ADR-036).
  7. A new backend domain package is added to ArchitectureTest's package allow-lists in the same change that introduces it.
  8. Synchronous cross-domain side effects use in-transaction domain events, not direct service-to-service write calls (see ADR-006).

2. Security Defaults

  1. Every POST, PUT, PATCH, and DELETE endpoint carries @RequirePermission(Permission.X) — there is no unguarded mutating endpoint.
  2. Authorization uses the typed Permission enum and @RequirePermission, never magic-string @PreAuthorize.
  3. All user input is validated at the system boundary (controller / form action), and validation failures return a typed ErrorCode, never a raw exception.
  4. Audit fields (createdBy/updatedBy) are set from the session principal inside the service and are never bound from a request body.
  5. Untrusted text is rendered through Svelte's default {...} escaping; {@html} is never used on user- or import-derived strings.
  6. Secrets are read only from environment variables (see .env.example); no secret, token, password, or DSN is ever committed to the repository or written to a log.
  7. Logs never contain PII beyond a stable user/entity UUID — no names, email addresses, document contents, or transcription text.
  8. Every state-mutating endpoint is covered by an Unwanted-behavior requirement (EARS If) describing the unauthenticated/unauthorized response.
  9. A dependency security audit runs on every CI run (npm audit --audit-level=high frontend, Semgrep .semgrep/security.yml backend) and nightly; a high finding blocks merge.

3. Code Quality Rules

  1. All new behavior is driven by a failing test written before the implementation (Red → Green → Refactor); a passing-on-first-run test proves nothing and is rejected.
  2. KISS beats DRY — no premature abstraction; an abstraction is introduced only on the third real caller.
  3. Each commit does exactly one logical thing and references its Gitea issue (Closes #n / Refs #n) on the last line of the body.
  4. No backwards-compatibility shims are added for code that has no callers.
  5. Every entity/DTO field the backend always populates carries @Schema(requiredMode = REQUIRED), and npm run generate:api is run after any backend model or endpoint change.
  6. A new ErrorCode is added in all four places at once: ErrorCode.java, frontend/src/lib/shared/errors.ts, getErrorMessage(), and messages/{de,en,es}.json.
  7. Dates built from an ISO date string append T12:00:00 to avoid UTC off-by-one.
  8. npm run lint (Prettier + ESLint, including the domain boundary rule) passes before every commit.

4. Do-Not-Touch List

  1. Do not edit generated artifacts: frontend/src/lib/generated/api.ts, frontend/src/lib/paraglide/, frontend/.svelte-kit/, frontend/build/, backend/target/.
  2. Do not edit an Accepted ADR — supersede it with a new, higher-numbered ADR.
  3. Do not upgrade actions/upload-artifact / download-artifact past @v3 (Gitea act_runner lacks the v4 protocol — ADR-014).
  4. Do not remove or weaken a CI guard step (banned-pattern greps, self-tested regexes) without an ADR recording why.
  5. Do not commit to main directly — all work flows through a branch and a PR.
  6. Do not edit a Flyway migration that has shipped; add a new forward-only migration instead.
  7. Do not commit the worktree copy directories (familienarchiv-*, .worktrees/) or data/.

5. Dependency Policy

  1. A new runtime dependency (backend pom.xml or frontend dependencies) requires an ADR in Accepted status before it is merged.
  2. A new dependency must be version-pinned in the manifest, and any exact pin (no caret) carries a comment stating why it cannot float (see the @vitest/browser-playwright pin).
  3. Renovate manages dependency-update PRs; a major-version bump is treated as a feature requiring its own spec and review, not an auto-merge.
  4. A dependency with an unresolved high+ advisory is not merged; it is pinned to a safe version or replaced.

6. Sync Impact

When this constitution changes, the author MUST, in the same PR:

  1. Bump the Version header per the semantic rule above and record the change in docs/adr/041-sdd-adoption.md's revision log (or a superseding ADR for a MAJOR change).
  2. Re-read and reconcile every file that restates a rule changed here: CLAUDE.md, COLLABORATING.md, CODESTYLE.md, CONTRIBUTING.md, .specify/AGENTS.md, and the affected .specify/personas/*.md checklists.
  3. Update any .specify/templates/* section that quotes a changed rule.
  4. Run the constitution-diff CI job locally (or read its PR comment) and resolve every file it lists.
  5. Announce the version bump in the PR description so reviewers re-read the constitution before approving.