Processes all 7 CLAUDE.md files according to the 3-bucket classification. Migration targets (CONTRIBUTING.md, docs/ARCHITECTURE.md, docs/DEPLOYMENT.md, domain READMEs) are introduced by DOC-2/4/5/6 — this PR must merge last. ### scripts/CLAUDE.md → scripts/README.md New `scripts/README.md` with full script documentation (preserving the ⚠️ destructive-operation warning on reset-db.sh). `scripts/CLAUDE.md` reduced to a pointer + "document new scripts in README.md" reminder. ### .devcontainer/CLAUDE.md → .devcontainer/README.md New `.devcontainer/README.md` with all configuration, usage, and limitations. `devcontainer/CLAUDE.md` reduced to a single pointer line. ### docs/CLAUDE.md → docs/README.md New `docs/README.md` covering the folder structure, ADR guide, infrastructure docs, and specs folder. `docs/CLAUDE.md` reduced to pointer + ADR reminder. ### ocr-service/CLAUDE.md Reduced to pointer to `ocr-service/README.md` (content migrated in DOC-6). Kept LLM reminders: single-node constraint, ALLOWED_PDF_HOSTS SSRF risk. ### backend/CLAUDE.md - Layering Rules → pointer to docs/ARCHITECTURE.md - Error Handling → pointer to CONTRIBUTING.md + reminder - Security/Permissions → pointer to docs/ARCHITECTURE.md + reminder - Package Structure → tagged TODO post-REFACTOR-1 - Fixed errors.ts path to frontend/src/lib/shared/errors.ts - Added ANNOTATE_ALL + BLOG_WRITE to permission list - Key Entities, Entity Code Style, Services → kept (Bucket-2) ### root CLAUDE.md - Stack, Infrastructure, Dev Container → pointers - Layering Rules, Error Handling, Security, OpenAPI, API Client, Date Handling, UI Components, Frontend Error Handling → pointers + reminders - Package Structure → tagged TODO post-REFACTOR-1 - Domain Model, Entity Code Style, Form Actions, Styling → kept (Bucket-2) ### frontend/CLAUDE.md - API Client Pattern, Date Handling → pointers + reminders - Key UI Components → pointer to domain READMEs - Styling, Form Actions, How to Run, Vite Proxy, i18n → kept (Bucket-2) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
277 lines
11 KiB
Markdown
277 lines
11 KiB
Markdown
# CLAUDE.md
|
|
|
|
> For a human-readable project overview, see [README.md](./README.md).
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
> For a human-readable project overview, see [README.md](./README.md).
|
|
|
|
## Project Overview
|
|
|
|
**Familienarchiv** is a family document archival system — a full-stack web app for digitizing, organizing, and searching family documents. Key features: file uploads (stored in MinIO/S3), metadata management, Excel/ODS batch import, full-text search, conversation threads between family members, and role-based access control.
|
|
|
|
## Collaboration
|
|
|
|
See [COLLABORATING.md](./COLLABORATING.md) for the full rules: issue tracking workflow, commit message conventions, and the Research → Plan → Implement → Validate cycle.
|
|
|
|
See [CODESTYLE.md](./CODESTYLE.md) for coding standards: Clean Code, DRY/KISS trade-offs (KISS wins), and SOLID principles applied to this stack.
|
|
|
|
---
|
|
|
|
## Stack
|
|
|
|
→ See [README.md §Tech Stack](./README.md#tech-stack)
|
|
|
|
- **Backend**: Spring Boot 4.0 (Java 21, Maven, Jetty, JPA/Hibernate, Flyway, Spring Security, Spring Session JDBC)
|
|
- **Frontend**: SvelteKit 2 with Svelte 5, TypeScript, Tailwind CSS 4, Paraglide.js (i18n: de/en/es)
|
|
- **Database**: PostgreSQL 16
|
|
- **Object Storage**: MinIO (S3-compatible)
|
|
- **Infrastructure**: Docker Compose
|
|
|
|
## Common Commands
|
|
|
|
### Running the Full Stack
|
|
|
|
```bash
|
|
docker-compose up -d
|
|
```
|
|
|
|
### Backend (Spring Boot)
|
|
|
|
```bash
|
|
cd backend
|
|
|
|
./mvnw spring-boot:run # Run locally
|
|
./mvnw clean package # Build JAR (with tests)
|
|
./mvnw clean package -DskipTests
|
|
./mvnw test # Run all tests
|
|
./mvnw test -Dtest=ClassName # Run a single test class
|
|
```
|
|
|
|
### Frontend (SvelteKit)
|
|
|
|
```bash
|
|
cd frontend
|
|
|
|
npm install
|
|
npm run dev # Dev server (port 3000)
|
|
npm run build # Production build
|
|
npm run preview # Preview production build
|
|
|
|
npm run lint # Prettier + ESLint check
|
|
npm run format # Auto-fix formatting
|
|
npm run check # svelte-check (type checking)
|
|
npm run test # Vitest unit tests
|
|
npm run generate:api # Regenerate TypeScript API types from OpenAPI spec
|
|
# (requires backend running with --spring.profiles.active=dev)
|
|
```
|
|
|
|
---
|
|
|
|
## Backend Architecture
|
|
|
|
### Package Structure
|
|
|
|
<!-- TODO: rewrite post-REFACTOR-1 — see Epic 4 -->
|
|
|
|
```
|
|
backend/src/main/java/org/raddatz/familienarchiv/
|
|
├── audit/ Audit logging
|
|
├── config/ Infrastructure config (Minio, Async, Web)
|
|
├── dashboard/ Dashboard analytics + StatsController/StatsService
|
|
├── document/ Document domain (entities, controller, service, repository, DTOs)
|
|
│ ├── annotation/ DocumentAnnotation, AnnotationService, AnnotationController
|
|
│ ├── comment/ DocumentComment, CommentService, CommentController
|
|
│ └── transcription/ TranscriptionBlock, TranscriptionService, TranscriptionBlockQueryService
|
|
├── exception/ DomainException, ErrorCode, GlobalExceptionHandler
|
|
├── filestorage/ FileService (S3/MinIO)
|
|
├── geschichte/ Geschichte (story) domain
|
|
├── importing/ MassImportService
|
|
├── notification/ Notification domain + SseEmitterRegistry
|
|
├── ocr/ OCR domain — OcrService, OcrBatchService, training
|
|
├── person/ Person domain
|
|
│ └── relationship/ PersonRelationship sub-domain
|
|
├── security/ SecurityConfig, Permission, @RequirePermission, PermissionAspect
|
|
├── tag/ Tag domain
|
|
└── user/ User domain — AppUser, UserGroup, UserService, auth controllers
|
|
```
|
|
|
|
### Layering Rules
|
|
|
|
→ See [docs/ARCHITECTURE.md §Layering rule](./docs/ARCHITECTURE.md#layering-rule)
|
|
|
|
**LLM reminder:** controllers never call repositories directly; services never reach into another domain's repository — always call the other domain's service instead.
|
|
|
|
### Domain Model
|
|
|
|
| Entity | Table | Key relationships |
|
|
| ----------- | ------------- | ------------------------------------------------------------------------------------- |
|
|
| `Document` | `documents` | ManyToOne `sender` (Person), ManyToMany `receivers` (Person), ManyToMany `tags` (Tag) |
|
|
| `Person` | `persons` | Referenced by documents as sender/receiver |
|
|
| `Tag` | `tag` | ManyToMany with documents via `document_tags` |
|
|
| `AppUser` | `app_users` | ManyToMany `groups` (UserGroup) |
|
|
| `UserGroup` | `user_groups` | Has a `Set<String> permissions` |
|
|
|
|
**`DocumentStatus` lifecycle:** `PLACEHOLDER → UPLOADED → TRANSCRIBED → REVIEWED → ARCHIVED`
|
|
|
|
- `PLACEHOLDER`: created during Excel import, no file yet
|
|
- `UPLOADED`: file has been stored in S3
|
|
|
|
### Entity Code Style
|
|
|
|
All entities use these Lombok annotations:
|
|
|
|
```java
|
|
@Entity
|
|
@Table(name = "table_name")
|
|
@Data
|
|
@NoArgsConstructor
|
|
@AllArgsConstructor
|
|
@Builder
|
|
public class MyEntity {
|
|
@Id
|
|
@GeneratedValue(strategy = GenerationType.UUID)
|
|
@Schema(requiredMode = Schema.RequiredMode.REQUIRED) // marks field as required in OpenAPI spec
|
|
private UUID id;
|
|
// ...
|
|
}
|
|
```
|
|
|
|
- `@Schema(requiredMode = REQUIRED)` must be added to every field the backend always populates (id, non-null fields). This drives the TypeScript type generation.
|
|
- Collections use `@Builder.Default` with `new HashSet<>()` as the default.
|
|
- Timestamps use `@CreationTimestamp` / `@UpdateTimestamp`.
|
|
|
|
### Services
|
|
|
|
Services are annotated with `@Service`, `@RequiredArgsConstructor`, and optionally `@Slf4j`.
|
|
|
|
- Write methods are annotated `@Transactional`.
|
|
- Read methods are not annotated (default non-transactional is fine).
|
|
- Each service owns its domain's repository. Cross-domain data access goes through the other domain's service.
|
|
|
|
### DTOs
|
|
|
|
Input DTOs live flat in the domain package. Response types are the model entities themselves (no response DTOs).
|
|
|
|
- `@Schema(requiredMode = REQUIRED)` on every field the backend always populates — drives TypeScript generation.
|
|
|
|
### Error Handling
|
|
|
|
→ See [CONTRIBUTING.md §Error handling](./CONTRIBUTING.md#error-handling)
|
|
|
|
**LLM reminder:** use `DomainException.notFound/forbidden/conflict/internal()` from service methods — never throw raw exceptions. When adding a new `ErrorCode`: (1) add to `ErrorCode.java`, (2) mirror in `frontend/src/lib/shared/errors.ts`, (3) add i18n keys in `messages/{de,en,es}.json`.
|
|
|
|
### Security / Permissions
|
|
|
|
→ See [docs/ARCHITECTURE.md §Permission system](./docs/ARCHITECTURE.md#permission-system)
|
|
|
|
**LLM reminder:** `@RequirePermission(Permission.WRITE_ALL)` is **required** on every `POST`, `PUT`, `PATCH`, `DELETE` endpoint — not optional. Do not mix with Spring Security's `@PreAuthorize`. Available permissions: `READ_ALL`, `WRITE_ALL`, `ADMIN`, `ADMIN_USER`, `ADMIN_TAG`, `ADMIN_PERMISSION`, `ANNOTATE_ALL`, `BLOG_WRITE`.
|
|
|
|
### OpenAPI / API Types
|
|
|
|
→ See [CONTRIBUTING.md §Walkthrough B — Add a new endpoint](./CONTRIBUTING.md#4-walkthrough-b--add-a-new-endpoint)
|
|
|
|
**LLM reminder:** always run `npm run generate:api` in `frontend/` after any backend model or endpoint change — this is the most common cause of TypeScript type errors.
|
|
|
|
---
|
|
|
|
## Frontend Architecture
|
|
|
|
### Route Structure
|
|
|
|
```
|
|
frontend/src/routes/
|
|
├── +layout.svelte Global header (sticky), nav links, logout
|
|
├── +layout.server.ts Loads current user, injects auth cookie
|
|
├── +page.svelte Home / document search
|
|
├── +page.server.ts Load: search documents; no actions
|
|
├── documents/
|
|
│ ├── [id]/+page.svelte Document detail (view + file preview)
|
|
│ └── [id]/edit/ Edit form (all metadata + file upload)
|
|
│ └── new/ Create form (same fields, empty)
|
|
├── persons/
|
|
│ ├── +page.svelte Person list with search
|
|
│ ├── [id]/+page.svelte Person detail (inline edit + merge)
|
|
│ └── new/ Create person form
|
|
├── conversations/ Bilateral conversation timeline
|
|
├── admin/ User + group + tag management
|
|
└── login/ logout/ Auth pages
|
|
```
|
|
|
|
### API Client Pattern
|
|
|
|
→ See [CONTRIBUTING.md §Frontend API client](./CONTRIBUTING.md#frontend-api-client)
|
|
|
|
**LLM reminder:** check `!result.response.ok` (not `result.error` — breaks when spec has no error responses defined); cast errors as `result.error as unknown as { code?: string }`; use `result.data!` after an ok check.
|
|
|
|
### Form Actions Pattern
|
|
|
|
```typescript
|
|
// +page.server.ts
|
|
export const actions = {
|
|
default: async ({ request, fetch }) => {
|
|
const formData = await request.formData();
|
|
const name = formData.get("name") as string;
|
|
// ...
|
|
return fail(400, { error: "message" }); // on error
|
|
throw redirect(303, "/target"); // on success
|
|
},
|
|
};
|
|
```
|
|
|
|
### Date Handling
|
|
|
|
→ See [CONTRIBUTING.md §Date handling](./CONTRIBUTING.md#date-handling)
|
|
|
|
**LLM reminder:** always append `T12:00:00` when constructing `new Date()` from an ISO date string — prevents UTC timezone off-by-one errors.
|
|
|
|
### UI Component Library
|
|
|
|
→ See per-domain READMEs: [`frontend/src/lib/person/README.md`](./frontend/src/lib/person/README.md), [`frontend/src/lib/tag/README.md`](./frontend/src/lib/tag/README.md), [`frontend/src/lib/document/README.md`](./frontend/src/lib/document/README.md), [`frontend/src/lib/shared/README.md`](./frontend/src/lib/shared/README.md)
|
|
|
|
### Styling Conventions (Tailwind CSS 4)
|
|
|
|
Brand color utilities (defined in `layout.css`):
|
|
|
|
| Class | Value | Usage |
|
|
| ------------ | --------- | -------------------------------- |
|
|
| `brand-navy` | `#002850` | Primary text, buttons, headers |
|
|
| `brand-mint` | `#A6DAD8` | Accents, hover underlines, icons |
|
|
| `brand-sand` | `#E4E2D7` | Page background, card borders |
|
|
|
|
Typography:
|
|
|
|
- `font-serif` (Merriweather) — body text, document titles, names
|
|
- `font-sans` (Montserrat) — labels, metadata, UI chrome
|
|
|
|
Card pattern for content sections:
|
|
|
|
```svelte
|
|
<div class="bg-white shadow-sm border border-brand-sand rounded-sm p-6">
|
|
<h2 class="text-xs font-bold uppercase tracking-widest text-gray-400 mb-5">Section Title</h2>
|
|
<!-- content -->
|
|
</div>
|
|
```
|
|
|
|
Back button pattern — use the shared `<BackButton>` component from `$lib/shared/primitives/BackButton.svelte`. Do not use a static `<a href>` for back navigation.
|
|
|
|
### Error Handling (Frontend)
|
|
|
|
→ See [CONTRIBUTING.md §Error handling](./CONTRIBUTING.md#error-handling)
|
|
|
|
**LLM reminder:** when adding a new `ErrorCode`: (1) add to `ErrorCode.java`, (2) add to `ErrorCode` type in `frontend/src/lib/shared/errors.ts`, (3) add a `case` in `getErrorMessage()`, (4) add i18n keys in `messages/{de,en,es}.json`.
|
|
|
|
---
|
|
|
|
## Infrastructure
|
|
|
|
→ See [docs/DEPLOYMENT.md](./docs/DEPLOYMENT.md)
|
|
|
|
## API Testing
|
|
|
|
HTTP test files are in `backend/api_tests/` for use with the VS Code REST Client extension.
|
|
|
|
## Dev Container
|
|
|
|
→ See [.devcontainer/README.md](./.devcontainer/README.md)
|