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>
78 lines
5.3 KiB
Markdown
78 lines
5.3 KiB
Markdown
# AGENTS.md
|
||
|
||
Machine-readable rules for AI coding agents (Claude Code, Copilot, Cursor, …) working in
|
||
this repository. Read this on every invocation. These are **executable constraints**, not
|
||
aspirations. The full rationale lives in [constitution.md](./constitution.md) and the docs
|
||
it links — this file does not duplicate it, it points to it.
|
||
|
||
If anything here conflicts with the user's explicit instruction, the user wins. Otherwise,
|
||
constitution > this file > convenience.
|
||
|
||
---
|
||
|
||
## Stack & Versions
|
||
|
||
| Layer | Tech | Version |
|
||
|---|---|---|
|
||
| Backend | Spring Boot (Java, Maven, Jetty, JPA/Hibernate, Flyway, Spring Security, Session JDBC) | Boot 4.0.6 / Java 21 |
|
||
| API docs | springdoc-openapi (webmvc-ui), served at `/v3/api-docs` (dev profile only) | — |
|
||
| Frontend | SvelteKit / Svelte | 2.60 / 5.43 |
|
||
| Frontend lang/style | TypeScript / Tailwind CSS / Paraglide i18n (de/en/es) | TS 5.9 / TW 4.1 |
|
||
| API client | `openapi-fetch` + `openapi-typescript` (types generated from the live spec) | — |
|
||
| DB | PostgreSQL | 16 |
|
||
| Object storage | MinIO (S3-compatible) | — |
|
||
| Sidecars | `ocr-service`, `nlp-service` (Python / FastAPI) | Python 3.11 |
|
||
| Tests | JUnit + Mockito + `@WebMvcTest` + Testcontainers (backend); Vitest + `vitest-browser-svelte` + Playwright (frontend); Pytest (services) | — |
|
||
| Lint/format | ESLint 9 (+ `eslint-plugin-boundaries`) + Prettier; Semgrep (backend) | — |
|
||
| CI | Gitea Actions (`.gitea/workflows/`) | — |
|
||
|
||
App port `8080`; management port `8081`. Backend app id: `org.raddatz.familienarchiv` / `0.0.1-SNAPSHOT`.
|
||
|
||
## Architectural Constraints
|
||
|
||
- Controllers call services only — never a repository. (constitution §1.2)
|
||
- A service uses only its own domain's repository; reach other domains via their service. (constitution §1.3)
|
||
- A new backend domain goes in its own package AND is added to `ArchitectureTest`'s allow-lists in the same change. (constitution §1.7)
|
||
- Frontend cross-domain imports are allowed only where `frontend/eslint.config.js` permits; otherwise move shared code to `$lib/shared/`. (constitution §1.4)
|
||
- Never serialize a lazy-collection entity across the controller boundary — assemble a view in-transaction. (constitution §1.6 / ADR-036)
|
||
- `Person` ≠ `AppUser`; do not add account guards to Person-domain operations. (constitution §1.5)
|
||
- Every `POST/PUT/PATCH/DELETE` endpoint has `@RequirePermission(Permission.X)`. Use the enum, never `@PreAuthorize`. (constitution §2.1–2.2)
|
||
- Throw only `DomainException.notFound/forbidden/conflict/internal()` from services, each with an `ErrorCode`. (CONTRIBUTING §Error handling)
|
||
- Set `createdBy`/`updatedBy` from the session principal in the service — never bind them from a request body. (constitution §2.4)
|
||
- Add an `@Schema(requiredMode = REQUIRED)` to every always-populated field. (constitution §3.5)
|
||
- Never introduce a new runtime dependency without an ADR in `Accepted` status. (constitution §5.1)
|
||
- Render untrusted text with `{...}`; never `{@html}` on user/import data. (constitution §2.5)
|
||
- Build dates from ISO strings with a `T12:00:00` suffix. (constitution §3.7)
|
||
|
||
## Workflow Rules
|
||
|
||
- Always write a failing test before implementation code; confirm it fails, then make it pass, then refactor. (constitution §3.1)
|
||
- Run only the specific test file/class locally — never the full suite (it crashes the machine); leave the full sweep to CI.
|
||
- Run `npm run generate:api` (in `frontend/`) after ANY backend model or endpoint change — most common cause of TS errors.
|
||
- Run `npm run lint` before every commit; a fresh frontend worktree needs `npm install` first or the pre-commit hook fails.
|
||
- When adding a new `ErrorCode`, update all four sites at once (constitution §3.6).
|
||
- One logical change per commit; reference the Gitea issue (`Closes #n` / `Refs #n`) on the last line.
|
||
- Create a git worktree for new issue work — never `git checkout -b` in the main repo while another branch has in-flight work. Avoid `+` in worktree/branch names (breaks vitest browser mode).
|
||
- Pull `main` as a separate explicit step before creating a branch.
|
||
- Track work as Gitea issues (`http://192.168.178.71:3005`, repo `marcel/familienarchiv`), not todo files.
|
||
- Verify ADR and Flyway migration numbers against disk before using one — parallel worktrees make issue-body numbers go stale.
|
||
|
||
## Do Not Touch
|
||
|
||
- Generated: `frontend/src/lib/generated/api.ts`, `frontend/src/lib/paraglide/`, `frontend/.svelte-kit/`, `frontend/build/`, `backend/target/`.
|
||
- Shipped Flyway migrations — add a new forward-only migration instead.
|
||
- An `Accepted` ADR — supersede it with a new one.
|
||
- `actions/(upload|download)-artifact` version — stays at `@v3` (ADR-014).
|
||
- CI guard steps — do not remove/weaken without an ADR.
|
||
- `main` — never commit directly; branch + PR only.
|
||
- Worktree copies (`familienarchiv-*`, `.worktrees/`) and `data/` — never commit.
|
||
|
||
## Spec-Driven Development
|
||
|
||
A feature's spec is its **Gitea issue body** — there is no committed `spec.md`. The issue's
|
||
EARS requirements (`REQ-NNN`) and acceptance criteria are the contract; each maps to a test,
|
||
traced in [`.specify/rtm.md`](./rtm.md) (`REQ-ID → issue # → test`). Read the issue before
|
||
implementing. The committed [`.specify/features/_example/`](./features/_example/) is a
|
||
template/reference showing the full artifact set, not a live feature. Full workflow:
|
||
[SPEC_DRIVEN_DEVELOPMENT.md](../SPEC_DRIVEN_DEVELOPMENT.md).
|