Records the visual-brainstorm outcome for #827's grouped view: a cluster becomes one
contained card (event/tag as header, first 5 letters + show-more), the leftover bin
collapses to a count-only drawer, derived/world fixtures stay plain, and REQ-001/003/014/020
are amended. Mockups under .superpowers/brainstorm/ (gitignored).
Refs #827#847
Record the three #827 forks (client-side regroup transport, computed letter→event
link reusing timeline_event_documents, filter-then-group composition with #780)
as ADR-045, trace REQ-001..019 (+005b) into the RTM as Done, and list the new
timeline components in the frontend domain inventory.
Refs #827
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Closes#837
Makes `PersonRelationship` fully editable (type, related person, dates, notes), migrates its dates from `Integer fromYear/toYear` to `LocalDate + DatePrecision` (mirroring the #773 person pattern, ADR-039 / V76), activates the previously-dead `notes` column, and gives the Zeitstrahl's derived **Heirat** events full date precision for free.
Both Open Decisions confirmed as adopted: **no `@Version`** (last-write-wins, single-writer archive) and **`DELETE` ownership-mismatch aligned 403 → 404** (anti-enumeration, matching the new `PUT`).
## What's in it
- **V78** migrates `person_relationships.from_year/to_year` → `from_date`/`to_date` + NOT-NULL `*_date_precision` (default `UNKNOWN`); pre-check abort on corrupt years, `YYYY-01-01`/`YEAR` backfill, 5 named CHECK constraints, year columns dropped.
- **`PUT /api/persons/{id}/relationships/{relId}`** (`@RequirePermission(WRITE_ALL)`) re-runs every create invariant (self / coherence / order / reverse-PARENT_OF / duplicate) and re-flags family membership; orientation preserved per viewpoint.
- New `ErrorCode.INVALID_RELATIONSHIP_DATES` registered in all four sites (§3.6).
- `TimelineEventService` sources the derived marriage date from `SPOUSE_OF.fromDate` + precision.
- Frontend: `RelationshipDateField` (DAY/MONTH/YEAR), upsert-capable `AddRelationshipForm` (pre-fill + notes + in-flight submit lock), `RelationshipChip` Edit affordance, `updateRelationship` server action, read-view date range + notes, `formatRelationshipDateRange` helper. `api.ts` regenerated.
- Docs: ADR-044, db-orm/db-relationships diagrams, DEPLOYMENT §5 deploy note, RTM REQ-001…REQ-019.
## Requirements
All 19 EARS requirements implemented red/green and marked `Done` in `.specify/rtm.md`.
## Test plan
- **Backend** (targeted, green): `RelationshipMigrationTest` (Testcontainers pg16, 8), `RelationshipServiceTest` (22), `RelationshipControllerTest` (15), `RelationshipServiceIntegrationTest` (real DB, 10), `DerivedEventsAssemblyTest` (17), `ArchitectureTest` (14); `clean package` builds.
- **Frontend** (green): `relationshipDates.spec.ts`, `AddRelationshipForm.svelte.spec.ts`, `RelationshipChip.svelte.spec.ts`, `PersonRelationshipsCard.svelte.test.ts`, `page.server.spec.ts`, `messages.spec.ts`. `npm run check` = 798 (below the ~834 baseline); `npm run lint` clean.
## Notes for reviewers
- **Spec deviation:** the edit form was built by making `AddRelationshipForm` upsert-capable rather than a duplicate `EditRelationshipForm` (DRY); RTM rows reference `AddRelationshipForm.svelte.spec.ts`.
- `api.ts` regenerated from the live spec; only relationship-relevant hunks remain (one springdoc `PageableObject` field-reorder pruned).
- **Deploy:** V78 is one-way and not rolling-deploy-safe — stop old JAR → start new JAR (Flyway runs first); targeted `pg_restore -t person_relationships` for rollback. No maintenance window.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Marcel <marcel@familienarchiv>
Reviewed-on: #841
Adds the events/new + events/[id]/edit children to both CLAUDE.md route tables
and the frontend C4 people-stories diagram (new zeitstrahlEvents component +
backend relation), and traces REQ-001..017 (feature timeline-curator-forms) in
.specify/rtm.md mirroring the sibling #776/#777/#778/#779 timeline rows.
Refs #781
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Add 20 REQ-NNN rows for issue #777 (all Done) to .specify/rtm.md
- Update CLAUDE.md timeline package description with TimelineService/TimelineController
- Extend l3-backend-timeline.puml with TimelineService/TimelineController components
and their edges to PersonService and DocumentService
Refs #777
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add GLOSSARY.md entries for derived event, DerivedEventType, derivedType,
and assembleDerivedEvents() to cover the vocabulary introduced by #776.
Update l3-backend-timeline.puml: remove stale "planned, #775" labels,
add Rel from TimelineEventService to personDomain for assembleDerivedEvents
batch-fetch calls, document the on-read strategy in the component notes.
Refs #776
Co-Authored-By: claude-sonnet-4-6 <noreply@anthropic.com>
Covers three pre-implementation decisions for issue #776:
1. On-read assembly, never persisted (no migration)
2. Synthetic prefixed String ids (birth:/death:/marriage:)
3. assembleDerivedEvents() as the public cross-issue contract on TimelineService
Refs #776
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two ADR-041 files landed on main in parallel (sdd-adoption and
renovate-runner-setup). Renames the SDD one to 042 and repoints its references
(SPEC_DRIVEN_DEVELOPMENT, constitution, .specify/adrs/README, sdd-gate.yml).
The renovate ADR keeps 041; its references are left untouched. Riding this PR
per request.
Refs #778
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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>
Records the decision to layer SDD (EARS requirements, OpenSpec-style delta
artifacts, a versioned constitution, and AGENTS.md) on top of the existing
Gitea-issue + multi-persona-review workflow. Numbered 041 to extend the
existing docs/adr/ archive rather than starting a parallel one.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
R9 doc-sync: add TIMELINE_EVENT_NOT_FOUND, TIMELINE_EVENT_CONFLICT,
TIMELINE_TITLE_TOO_LONG, and the generic CONFLICT to the valid-error-codes
list in CLAUDE.md and the error-code reference in docs/ARCHITECTURE.md. Per #775.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
title is VARCHAR(255) with no planned service-level check; ADR-040's
consequences listed the optimistic-lock and forgery obligations for #775 but
not this one, so an over-long title would have surfaced as a raw
DataIntegrityViolationException -> HTTP 500. Mirrors GESCHICHTE_TITLE_TOO_LONG.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The issue body's milestone-relative ordinals ("issue 3", "issue 5") become
unreadable once the milestone closes. Resolved against the Zeitstrahl milestone:
issue 3 = #775 (CRUD API: service/controller/DTO), issue 5 = #777 (assembly
endpoint with the per-person filter). Mapping anchored by issue 6 = #778
(date-label helper) and issue 9 = #781 (curator forms) in #774's forward notes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add timeline/ to the root and backend package tables, TimelineEvent to the
domain-model entity tables, TimelineEvent/EventType/Zeitstrahl to the
glossary, a new l3-backend-timeline C4 component diagram, and the
timeline_events table + two join tables (with their CHECKs and cascade FKs)
to the db-orm and db-relationships ER diagrams. Bumps the db-orm snapshot to
V77.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Records the architectural commitment for the timeline domain: views-not-
entities for issue 3 (ADR-036 rationale), DatePrecision import coupling
(ADR-025), the UNKNOWN-forbidden / SEASON-APPROX-legal precision contract,
the strict biconditional RANGE CHECK as a deliberate divergence from
Document, the @Version + NOT NULL audit-trail decisions, the optimistic-
lock-to-conflict translation contract (CWE-209), the server-populated-only
createdBy/updatedBy forgery guard (CWE-639), and the EventType stable
frontend styling contract.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replace Person birthYear/deathYear integers with birthDate/deathDate +
DatePrecision so known exact birthdays render precisely. Migration,
re-import preservation rule, and bounded blast radius captured; becomes
issue 1 the timeline's derived events depend on.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Hand-curated, year-banded vertical timeline weaving derived person
life-events, curated personal/historical events, and date-placed
letters. Includes proposed sub-issue breakdown for a milestone.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
lesereisen-reader-spec.html — Issue #752
LR-0 type selector on /geschichten/new
LR-1 REISE badge on the list
LR-2 Journey reader (ordered cards, interlude asides, no position numbers)
lesereisen-editor-spec.html — Issue #753
LE-1 empty JourneyEditor layout
LE-2 editor with mixed items (documents + interludes, drag handles)
LE-3 inline note-editing state
LE-4 mobile layout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
GLOSSARY entry for NameMatches (direct vs partial name-match strength and how
the search layer maps it); person/README adds resolveByName to the public
surface. No ADR — the matching rule is localized and justified inline.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Capture the why behind deploying Ollama to prod/staging compose: the
corrected init recipe (supersedes ADR-028 §10's never-functional curl
loop), the OLLAMA_KEEP_ALIVE=-1 pin (so a future maintainer doesn't
optimize it away and reintroduce the post-idle cold-load 503), the
30->60s timeout NFR, and the memswap==mem hard-OOM trade-off.
Addresses #759 review (Markus #3, Nora #2).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The diagram declared Container(ollama, ...) twice — an alias collision that
renders a duplicate box. It also declared the backend->ollama relationship
twice. Keep the richer 'Ollama LLM Service' declaration and the more
specific 'NL query parsing (POST /api/generate)' relationship; drop the
duplicates.
Addresses #759 review (Markus #2).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
docker-compose.prod.yml declares the volume as `ollama-models` (hyphen),
so the compose-project-prefixed name is `archiv-production_ollama-models`,
not the underscored `archiv-production_ollama_models` the model-upgrade
guide documented. The documented `docker volume rm` would not have matched
the real volume.
Addresses #759 review (Tobias #2).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
application.yaml sets app.ollama.timeout-seconds: 60 (raised from 30 to
absorb the cold model load on the first query after an Ollama restart),
but DEPLOYMENT.md still documented 30. A doc that contradicts the shipped
value is a traceability defect.
Addresses #759 review (Markus, Felix, Elicit).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Markus (architect): document SearchFilterBar + the search/ components
(SmartModeToggle, InterpretationChipRow, SmartSearchStatus,
DisambiguationPicker) and the POST /api/search/nl relation.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Both the first-time model pull runbook (from this branch) and the model
upgrade procedure (from main) belong in DEPLOYMENT.md.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Covers the SmartModeToggle pill (inside the search input, Google AI Mode
style), InterpretationChipRow anatomy, DisambiguationPicker, and all
status/error/empty states as full-result-area panels.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Addresses Elicit's and Sara's review concerns on PR #749:
- Expand §6 ollama_models section into a full model upgrade runbook (step-by-step
docker volume rm + recreate, including production volume name prefix)
- Add re-deploy idempotency note to §3.4 (init container exits quickly when model
already present on the volume)
- Add NL search smoke test to §3.4 (curl command distinguishing 200 from 503
NL_SEARCH_UNAVAILABLE)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Updated OLLAMA_API_KEY env vars table from 0.6.5 to 0.6.5 or 0.30.6 to
match both tested versions. Added an explicit warning in §3.4 that
docker compose up -d --wait blocks for 60–90 min on first deploy when the
model pull has not yet completed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
§12 stated OLLAMA_API_KEY guards against lateral movement — contradicts
§7's empirical finding that it is not enforced. Replaced with an accurate
note referencing §7. Stale pre-merge placeholder in Consequences ("Three
TBD items must be resolved") removed; all three are resolved. §7 section
title updated from "0.6.5" to "0.6.5 and 0.30.6" to match the body text.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- OLLAMA_API_KEY: non-enforcement confirmed on both 0.6.5 and 0.30.6
- read_only: true: confirmed working on both 0.6.5 and 0.30.6
- Peak RSS during pull: ~108 MiB (well under 2g limit)
- All TBD placeholders resolved
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace all references to the CX32 VPS (8 GB RAM, Hetzner Cloud) with the
actual production server: a Hetzner Serverbörse dedicated server with an
Intel Core i7-6700 (4C/8T, 3.4 GHz) and 64 GB RAM.
Affected files:
- .claude/personas/devops.md — monthly cost line + upgrade example
- docs/infrastructure/production-compose.md — sizing section + cost table
- docs/DEPLOYMENT.md — OCR memory table + OCR_MEM_LIMIT env var description
- docs/adr/004-pdfbox-thumbnails.md — thumbnailExecutor memory ceiling note
- docs/adr/021-tmpdir-persistent-volume-staging.md — OOMKill rationale in alternatives
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>