Files
familienarchiv/CLAUDE.md
Marcel 558b3ebe07
All checks were successful
CI / Unit & Component Tests (pull_request) Successful in 3m44s
CI / OCR Service Tests (pull_request) Successful in 17s
CI / Backend Unit Tests (pull_request) Successful in 4m53s
CI / fail2ban Regex (pull_request) Successful in 40s
CI / Compose Bucket Idempotency (pull_request) Successful in 56s
docs: align ErrorCode 4-step checklist in CLAUDE.md; note frontend sync in ARCHITECTURE.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 16:16:32 +02:00

12 KiB

CLAUDE.md

For a human-readable project overview, see 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.

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 for the full rules: issue tracking workflow, commit message conventions, and the Research → Plan → Implement → Validate cycle.

See 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

  • 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

docker-compose up -d

Backend (Spring Boot)

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)

cd frontend

npm install
npm run dev         # Dev server (port 5173)
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

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

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:

@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

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) 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.

Security / Permissions

→ See 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

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 / +layout.server.ts   Global layout, auth cookie
├── +page.svelte / +page.server.ts       Home / document search dashboard
├── documents/
│   ├── [id]/               Document detail (view + file preview)
│   ├── [id]/edit/          Edit form (all metadata + file upload)
│   ├── new/                Upload form
│   └── bulk-edit/          Multi-document edit
├── persons/
│   ├── [id]/               Person detail
│   ├── [id]/edit/          Person edit form
│   └── new/                Create person form
├── briefwechsel/           Bilateral conversation timeline (Briefwechsel)
├── aktivitaeten/           Unified activity feed (Chronik)
├── geschichten/            Stories — list, [id], [id]/edit, new
├── stammbaum/              Family tree (Stammbaum)
├── enrich/                 Enrichment workflow — [id], done
├── admin/                  User, group, tag, OCR, system management
├── hilfe/transkription/    Transcription help page
├── profile/                User profile settings
├── users/[id]/             Public user profile page
├── login/ logout/ register/
└── forgot-password/ reset-password/

API Client Pattern

→ See 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

// +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

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/tag/README.md, frontend/src/lib/document/README.md, frontend/src/lib/shared/README.md

Styling Conventions (Tailwind CSS 4)

Brand color tokens (defined in layout.css):

Token / Utility CSS variable Usage
brand-navy --palette-navy Tailwind utility — buttons, headers, primary text
brand-mint --palette-mint Tailwind utility — accents, hover underlines, icons
--palette-sand --palette-sand Palette constant only — use bg-canvas or bg-surface

Typography:

  • font-serif (Tinos) — body text, document titles, names
  • font-sans (Montserrat) — labels, metadata, UI chrome

Card pattern for content sections:

<div class="rounded-sm border border-line bg-surface shadow-sm p-6">
    <h2 class="text-xs font-bold uppercase tracking-widest text-ink-3 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

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

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