Workstream 5: Dynamische Suche & Filter (Phase 3)
Implementiert die Startseite mit Tabs (Fahrzeuge/Geräte/Wehren), Namens-/
Funkrufnamen-Suche und ein dynamisch aus dem aktiven Merkmal-Katalog erzeugtes
Filter-UI (Slider/Multi-Select/Tri-State Switch) plus Status-Filter.
Kern:
- src/lib/search/types.ts: uuid-IDs durchgängig (SearchHit, FacetDef, FilterValue).
- src/lib/search/parse-params.ts: typisiertes Parsen von f.<uuid>=… (number lo..hi,
enum CSV, boolean ja/nein) + q + bereit; Ungültiges wird still verworfen.
- src/lib/search/facets.ts: lädt nur status='active', geltungsbereich in (typ,'both'),
typ<>'text'; min/max je number, Optionen sortiert je enum.
- src/lib/search/query-vehicles.ts: Name+Funkrufname (OR) + Status + UND-verknüpfte
EXISTS-Filter je merkmal_id; Allrad-Regel via expandNameQuery; keine Sortierung.
- src/lib/search/query-equipment.ts: wie Fahrzeuge, ohne Allrad, mit categoryId.
- src/lib/search/query-brigades.ts: Name/Ort/PLZ, nur aktive Wehren.
- src/lib/admin/codes.ts: gemeinsame Allrad-Namensregel (HLFA->HLF, Allrad impliziert);
Eigentum Admin-WS, hier rein/testbar bereitgestellt und importiert.
- src/lib/db/indexes-trgm.sql: nur pg_trgm-GIN-Indizes auf vehicles.name/funkrufname
(idempotent); merkmal_values-Indizes bleiben Eigentum des DB-WS.
UI:
- src/components/search: SearchTabs, SearchBar (debounced q), FilterPanel (dispatch +
Status-Switch), useSearchParams (router.replace ohne Reload, atomares setParams),
StandortBar; facets/{NumberRange,Enum,Boolean}; results/{ResultList,Vehicle,Equipment,
Brigade}Row mit Empty-State und offenem ETA-Slot.
- src/app/(app)/{page,fahrzeuge,geraete,wehren}: Server Components mit requireSession()
als erster Zeile (default-deny in der Tiefe zusätzlich zum Layout-Gate). /fahrzeuge
sortiert bei gesetztem Standort via searchHitsToGeoCandidates + orderByEintreffzeit.
Tests:
- Units (ohne DB): codes, parse-params, query-vehicles (SQL-Render via PgDialect).
- tests/e2e/search.spec.ts geschrieben (deferred — kein Server/DB in Sandbox).
Verifiziert offline: tsc --noEmit (0 Fehler), eslint (0), drizzle-kit check (ok),
vitest src/lib (57 grün), next build (Compiled successfully, Routen registriert).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -30,6 +30,26 @@ export const de = {
|
||||
luftlinie: "Luftlinie (geschätzt)",
|
||||
adresse: "Adresse",
|
||||
adressePlaceholder: "Adresse oder Ort",
|
||||
suchbegriff: "Suchbegriff",
|
||||
suchbegriffPlaceholder: "Name oder Funkrufname …",
|
||||
nameOrtPlz: "Name, Ort oder PLZ …",
|
||||
filter: "Filter",
|
||||
filterZuruecksetzen: "Filter zurücksetzen",
|
||||
keineFilter: "Keine Filter verfügbar.",
|
||||
nurEinsatzbereit: "Nur einsatzbereit",
|
||||
von: "von",
|
||||
bis: "bis",
|
||||
egal: "egal",
|
||||
ja: "Ja",
|
||||
nein: "Nein",
|
||||
tabFahrzeuge: "Fahrzeuge",
|
||||
tabGeraete: "Geräte",
|
||||
tabWehren: "Wehren",
|
||||
treffer: "Treffer",
|
||||
standort: "Standort für Eintreffzeit",
|
||||
keinFunkrufname: "kein Funkrufname",
|
||||
eintreffzeitOffen: "Eintreffzeit: Standort wählen",
|
||||
ergebnisse: "Ergebnisse",
|
||||
},
|
||||
detail: {
|
||||
eckdaten: "Eckdaten",
|
||||
|
||||
Reference in New Issue
Block a user