arch: Candidate-Schema — vier offene Entscheidungen (Day-Planner Phase 1) #454
Labels
No labels
app/archiv
app/einkaufslisten
app/imap-client
app/wissensbasis
arch-answered
arch-question
area/api
area/auth
area/infra
area/mobile
area/shared
area/ui
area/web
portfolio-status
prio/high
prio/low
prio/medium
roadmap/public
size/l
size/m
size/s
size/xl
size/xs
status/blocked
status/needs-info
type/bug
type/chore
type/docs
type/feature
type/idea
type/refactor
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
admin-mrrm/mrrmlabapp#454
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Kontext
Day-Planner-Epic #360 hat das Konzept eines
Candidate-Layers als Sources→Planner-Zwischenstück eingeführt. Phase 1 (#453) entwirft das Schema; vier Architektur-Entscheidungen sind offen und müssen vor Schema-Commit fallen, weil sie die Migration formen.Konkrete Entscheidung gebraucht
Vier Schema-Designs, die zusammen die Candidate-Tabelle formen — bitte einzeln entscheiden + kurz begründen:
1. Mandant: Candidate-Tabelle pro User oder global mit
ownerSub?ownerSub: eine Tabelle, alle Candidates, Row-Filter via WHERE. Standard im Rest der API.2. Refs: separate Join-Tabelle
candidate_refsoder JSONB-Feld?refs: { listId?, mailId?, trackingId?, calendarEventId?, ... }als JSONB-Spalte. Einfacher Schema-Append, weniger JOINs.candidate_refs-Tabelle:(candidate_id, ref_type, ref_id). Bessere Indizierbarkeit/Foreign-Keys, klare Beziehung zu Source-Tabellen.3.
lifecycleState: Enum oder mehrere Boolean-Flags?lifecycleState∈ {pending,planned,done,obsolete, ...}. Eine Quelle der Wahrheit.isPlanned,isDone,isObsolete. Flexibler Kombinatorik, aber widersprüchliche Zustände möglich.4. Done-Rückmeldung an die Source
Wenn ein Candidate auf
donegeht (z.B. Mail beantwortet, Paket abgeholt) — wie weiß die Source es, damit sie nicht erneut denselben Candidate erzeugt?sourceRef).candidate.done→ Source-Listener), klarer Event-Flow, aber zusätzliche Infrastruktur.manual,derived-all-items,auto-on-event,time-elapsed); Source muss nur lesen, nicht reagieren.Constraints
CLAUDE.md: forward-only und backward-compatible.tracking-todo-writer, #143/#144/#145) müssen schrittweise migriert werden können — kein Big-Bang.@mrrmlab/shared-types.Dringlichkeit
Phase-1-Schema-Spike (#453) wartet auf die Entscheidungen. Folge-Phasen (Tracking-Refactor, Mail-Source #178, Habit-Source, Planner v0) blocken auf Phase 1. Keine harte Deadline, aber Schema-Drift teuer wenn später revidiert.
Bezug
Alle vier Fragen sind durch ADR 0001 — Candidate-Modell als Unit-of-Planning (
docs/adr/0001-candidate-model.md, Status: Accepted, 2026-05-20) bereits entschieden. Kurzfassung:ownerSub(text not null), UNIQUE(ownerSub, source, sourceRef)candidates.schema.tslistId,subTodoListId,mailId,trackingId,calendarEventId) — NICHT JSONB, NICHT join-TabellelifecycleStatepending | planned | done | obsoleteonCandidateDone(sourceRef), idempotent, best-effort. Candidate ist Source-of-Truth.Implementierung:
apps/api/src/modules/candidates/candidates.schema.tsapps/api/drizzle/0017_slim_lady_bullseye.sqlapps/api/test/integration/candidates-schema.int-spec.tsSchließe das Issue als superseded by ADR 0001. Falls neue Edge-Cases auftauchen, separate arch-question mit konkretem Trigger.