diff --git a/cmd/server/main.go b/cmd/server/main.go index 31f5d1e..5f2225c 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -143,6 +143,7 @@ func main() { Fristenrechner: services.NewFristenrechnerService(rules, holidays), EventDeadline: services.NewEventDeadlineService(pool, services.NewDeadlineCalculator(holidays), holidays), DeadlineSearch: services.NewDeadlineSearchService(pool), + EventCategory: nil, // wired below; cross-link order matters EventType: eventTypeSvc, Dashboard: services.NewDashboardService(pool, users), Note: services.NewNoteService(pool, projectSvc, appointmentSvc), @@ -155,6 +156,12 @@ func main() { Link: services.NewLinkService(pool), Event: services.NewEventService(pool, deadlineSvc, appointmentSvc), } + // v3 (t-paliad-133): wire EventCategoryService and cross-link + // it into DeadlineSearchService so ?event_category_slug= can + // resolve to a concept-id allow-list during search. + eventCategorySvc := services.NewEventCategoryService(pool) + svcBundle.EventCategory = eventCategorySvc + svcBundle.DeadlineSearch.SetEventCategoryService(eventCategorySvc) log.Println("Phase B services initialised") // Spawn background goroutines: CalDAV sync (one per enabled user) diff --git a/docs/plans/unified-fristenrechner-v3.md b/docs/plans/unified-fristenrechner-v3.md new file mode 100644 index 0000000..974c513 --- /dev/null +++ b/docs/plans/unified-fristenrechner-v3.md @@ -0,0 +1,1048 @@ +# Unified Fristenrechner v3 — Pathway A (Browse) vs Pathway B (Event → Frist) + +**Author:** cronus (inventor) +**Date:** 2026-05-05 +**Task:** t-paliad-133 +**Mode:** design (LOCKED 2026-05-05 10:33) — implementation now in progress on the same branch. +**Branch:** `mai/cronus/fristenrechner-v3-pathways` (worktree) +**Status:** v3 LOCKED — m approved 2026-05-05 10:33 with answers to all 12 open questions; Maria's two scope additions folded in (forum granularity at court-system level + party-perspective selector absorbing t-paliad-132). Single-branch / sequential-commits / one-final-merge per m's instruction. +**Reads with:** `docs/plans/unified-fristenrechner.md` (v2, shipped) for the concept-layer / search-backend / coverage details that v3 inherits unchanged. + +> *m, 2026-05-05 10:06:* "Aber jetzt wurde das beim Fristenrechner Etwas vermischt. Ich wollte die aktuelle 'Schnellübersicht' im Zusammenhang mit 'Was kommt nach…?'. Etwas, wo wir Filter kombinieren können. (…) Es gibt hauptsächlich zwei Ausgangspunkte: Ich möchte mich über den allgemeinen Verfahrensablauf informieren ODER ich möchte wissen, ob ich eine und was für eine Frist ich eintragen muss aufgrund eines Ereignisses. Letzteres sollten wir in zwei teilen: einen Entscheidungsbaum (Button nach Button) (…) Und dann zeigen wir eben die Resultate als Cards unten an, narrowing it down one by one. Einmal über die fixe Abfolge, einmal über Filter." + +--- + +## 0. Why v3 + +v2 shipped (16 migrations 037-046, then PR-Phase-C/D 047 + handler + frontend). The Fristenrechner page now stacks **three** entry points on `/tools/fristenrechner`: + +1. The **Phase D concept-card search bar** at the top — typed query → cards with proceeding pills inside, drill-in pill click jumps into one of the modes below. +2. The **Verfahrensablauf tile grid** (UPC / DE / EPA / DPMA proceeding tiles → date input → timeline / columns view) — original entry, "I know which proceeding I'm in, calculate me the whole tree". +3. The **"Was kommt nach…" tab** — trigger-event picker → date input → flat result list — original second entry. + +The borders between (1), (2), (3) are blurred: + +- (1) does **what (3) does** for some queries (search "Versäumnisurteil" → trigger-event card pill leads back into (3); search "Berufung" → proceeding-rule pills lead into (2)). +- (1) bypasses (2) for most concept queries — the user types and drills directly, never seeing the proceeding tile grid. +- (3) carries 100+ youpc-imported triggers most of which are unlinked to concepts — they don't surface in (1) and don't have a friendly entry from (2). + +Two goals get tangled: **"learn how a proceeding works"** and **"figure out the Frist I need to enter on a real matter"**. m's read: separate them. **v3 forks the page surface** so each mental model has its own entrypoint, and the second one (Frist-eintragen) gets two complementary navigation styles — a guided decision tree (B1) and a free filter+search (B2). + +v3 does **not** change the calculator math, the deadline_concepts data, the migrations 037-047 already shipped, or the search-backend mat-view. It restructures the **entry UX** above all of that. + +--- + +## 1. Executive summary + +The Fristenrechner landing fork: + +``` + ┌──────────────────────────────────────┐ + │ Fristenrechner │ + │ Was möchten Sie tun? │ + ├──────────────────┬───────────────────┤ + │ 📖 Pathway A │ 📅 Pathway B │ + │ Verfahrensablauf│ Frist eintragen │ + │ informieren │ aufgrund Ereignis│ + └──────────────────┴───────────────────┘ + │ + ┌─────────────────┴─────────────────┐ + ▼ ▼ + ┌──────────────────────┐ ┌─────────────────────────┐ + │ Pathway A (Browse) │ │ Pathway B (Event→Frist) │ + │ │ │ ┌──────┐ ┌────────────┐ │ + │ • UPC tile grid │ │ │ B1 │ │ B2 │ │ + │ • DE tile grid │ │ │ Tree │ │ Filter+ │ │ + │ • EPA tile grid │ │ │ │ │ Suche │ │ + │ • DPMA tile grid │ │ └──────┘ └────────────┘ │ + │ │ │ │ + │ → existing wizard │ │ → narrowing concept │ + │ (date input, │ │ cards (same shape │ + │ flags, timeline, │ │ as v2 Phase D) │ + │ columns view) │ │ │ + └──────────────────────┘ └─────────────────────────┘ +``` + +**Pathway A — Verfahrensablauf informieren (Browse / Learn).** Identical to today's tile-grid → date-input → timeline flow. The user picks a proceeding type because they know what it is and want to see the whole tree. No event-driven entry; no search bar. + +**Pathway B — Frist eintragen aufgrund Ereignis (Event → Deadline).** For users who just had something happen and need to know which Frist(en) to enter on a matter. Subdivides into: + +- **B1 — Entscheidungsbaum.** Sequential 3-5-step button cascade. Each step asks one question, offers 2-6 buttons, narrows to a candidate set of Fristen as concept cards below. +- **B2 — Filter / Suche.** Free-text search bar + filter chips (Verfahrensart · Partei · Rechtsquelle · **Gericht/System** · plus the existing Phase D pills). Filters AND together; adding a filter reduces the result set. + +Both B1 and B2 produce the **same concept-card UI** that v2 Phase D shipped — one card per concept, proceeding pills inside. Drill-in pill click hands off to Pathway A (proceeding-tree calculator) or to the trigger-event calculator. **B1 and B2 share the same underlying filter state** under the hood — the decision tree is a guided way to build a filter combination. The user can switch B1↔B2 mid-flow without losing context. + +**Data addition:** new `paliad.event_categories` table (recursive tree) + `paliad.event_category_concepts` junction. Defines the decision-tree taxonomy as data, not as a hard-coded UI tree. Purely additive; no changes to existing tables. + +**Forum filter (Q8 reversal).** v2 dropped forum-filter on the rationale "rules are shared per court system within a jurisdiction". m has now reversed that: even though the *legal source* of a deadline is jurisdiction-wide, the *user* often knows which **forum** they're working at and wants a filter. v3 brings back a **Gericht/System** filter on B2 — multi-select chips, AND-each, default all selected, narrows the concept-card result set. + +**Legacy tabs.** v2's two tabs (Verfahrensablauf / Was kommt nach…) are functionally absorbed by Pathway A and Pathway B. **Inventor recommends retire** — keep only the new fork. Defer retirement to Phase E pending m's go. + +**Phasing:** + +- **Phase A** — `paliad.event_categories` schema + seed (data only, no UX change). +- **Phase B** — landing fork UI; route to existing tile grid (A) or new Pathway-B shell (B). URL state persists choice. +- **Phase C** — B1 decision-tree component, data-driven; result-card list narrows step-by-step. +- **Phase D** — B2 filter expansion; bring back forum chip filter; ensure progressive narrowing semantics. +- **Phase E** — retire legacy tabs (`mode-procedure-tab` / `mode-event-tab`) IF m approves; otherwise keep as "Klassische Ansicht" link in the page footer. + +--- + +## 2. Verified current state + +| Area | What's there today (post-t-paliad-131) | Reused in v3 | +|---|---|---| +| `paliad.deadline_concepts` | 57 concepts seeded | Yes (no change) | +| `paliad.deadline_rules` (gained `concept_id`, `legal_source`, `condition_flag text[]`) | 137 rules across 19 fristenrechner trees | Yes (no change) | +| `paliad.trigger_events` | 100 youpc-imported (UPC) + 7 paliad-native at id ≥200 (DE/EPA cross-cutting) | Yes (no change) | +| `paliad.deadline_search` matview | UNION of rule + trigger rows, GIN-indexed | Yes — v3 read path stays identical | +| `GET /api/tools/fristenrechner/search` handler | Phase D concept-card endpoint | Yes — extended with new `forum=` query param (§4) | +| `frontend/src/fristenrechner.tsx` | search bar + chips + 2 tabs (Verfahrensablauf / Was kommt nach…) | Reshape: split into landing fork → Pathway A page-fragment, Pathway B shell with B1/B2 toggle | +| `frontend/src/client/fristenrechner.ts` (≈1500 lines) | wizard logic for both modes | Pathway A keeps existing flow verbatim; Pathway B reorganises search-result rendering into the new shell | +| `frontend/src/client/fristenrechner-search.ts` (Phase D, ≈600 lines) | search → cards → drill-in | Reused as the engine of B2; the DOM scaffolding moves into the Pathway B shell | + +**No migrations are reverted.** v3 builds on top of the data layer that v2 shipped. Phase A adds two new tables; nothing in 037-047 changes. + +--- + +## 3. UX surface + +### 3.1 Landing fork + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ Fristenrechner │ +│ Berechnung von Verfahrensfristen — UPC, DE, EPA, DPMA │ +│ │ +│ ┌────────────────────────┐ ┌─────────────────────────────────┐ │ +│ │ 📖 │ │ 📅 │ │ +│ │ Verfahrensablauf │ │ Frist eintragen │ │ +│ │ informieren │ │ aufgrund Ereignis │ │ +│ │ │ │ │ │ +│ │ Verfahrenstyp wählen │ │ Ein Ereignis ist eingetreten — │ │ +│ │ und alle dazugehörigen │ │ ich brauche die richtige Frist │ │ +│ │ Fristen auf einer Zeit-│ │ für meine Akte. │ │ +│ │ leiste sehen. │ │ │ │ +│ │ │ │ → Schritt-für-Schritt │ │ +│ │ → UPC / DE / EPA / DPMA│ │ → Filter / Suche │ │ +│ └────────────────────────┘ └─────────────────────────────────┘ │ +│ │ +│ ───────── oder direkt zu einer Frist springen ────────── │ +│ │ +│ [ Klageerwiderung ] [ Berufung ] [ Einspruch ] [ Replik ] [ … ] │ +│ (chips → Pathway B + B2 prefilled) │ +└──────────────────────────────────────────────────────────────────┘ +``` + +**Default landing:** the fork itself. No automatic forwarding into either pathway — both choices are first-class. + +**URL state (sharable, bookmarkable):** + +| URL | Surface | +|---|---| +| `/tools/fristenrechner` | Landing fork | +| `/tools/fristenrechner?path=a` | Pathway A (tile grid) | +| `/tools/fristenrechner?path=a&proc=UPC_INF` | Pathway A, proceeding pre-selected (existing behaviour) | +| `/tools/fristenrechner?path=b` | Pathway B, default mode (B1 if user hasn't chosen yet, otherwise the last mode) | +| `/tools/fristenrechner?path=b&mode=tree` | Pathway B, B1 decision tree | +| `/tools/fristenrechner?path=b&mode=tree&b1=cms-eingang.gericht.hinweisbeschluss` | B1 with the path pre-walked to that node | +| `/tools/fristenrechner?path=b&mode=filter` | Pathway B, B2 filter+search | +| `/tools/fristenrechner?path=b&mode=filter&q=klageerwiderung&forum=upc,de_lg` | B2 with query + forum filter pre-applied | + +The Phase D quick-pick chips relocate from "above tabs" to "below the fork" with the new framing **"oder direkt zu einer Frist springen"**. Chip click navigates to `?path=b&mode=filter&q=