docs(11): phase context from user requirements — filters, triage, saved searches
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,98 @@
|
|||||||
|
# Phase 11: Filter Engine, Results UI & Saved Searches - Context
|
||||||
|
|
||||||
|
**Gathered:** 2026-07-21
|
||||||
|
**Status:** Ready for planning
|
||||||
|
**Mode:** mvp (vertical slices UI→API→DB)
|
||||||
|
|
||||||
|
<domain>
|
||||||
|
## Phase Boundary
|
||||||
|
|
||||||
|
Die Anzeige- und Interaktionsschicht des Ausschreibungs-Radar-Moduls. Phase 10 hat die globale `Tender`-Tabelle befüllt (aktuell ~1671 echte DÖE-Einträge). Diese Phase macht sie für Endnutzer nutzbar: durchsuchbare/sortierbare Trefferliste, Filter (Freitext, Region/PLZ/Bundesland, CPV, Frist, Wert), Detailansicht, persönliche Suchprofile und persönliche Triage (gelesen/ungelesen, Favoriten) — plus transparente Abdeckungs-Anzeige (Oberschwelle vs. Unterschwelle), damit „keine Treffer" nicht als Bug missverstanden wird.
|
||||||
|
|
||||||
|
Requirements: FILTER-01, FILTER-02, FILTER-03, FILTER-04, FILTER-05, FILTER-06, UI-01, UI-02, UI-03, UI-04, UI-05.
|
||||||
|
|
||||||
|
Nicht in dieser Phase: E-Mail-Benachrichtigungen (Phase 12), Scraping-Adapter + Cross-Source-Dedup (Phase 13), RSS/E-Mail-Quellen + ausgeschlossene-Portale-Transparenz UI-06 + i18n-Rollout (Phase 14), CSV/Excel-Export (Backlog).
|
||||||
|
</domain>
|
||||||
|
|
||||||
|
<decisions>
|
||||||
|
## Implementation Decisions
|
||||||
|
|
||||||
|
Bestätigt durch User-Abfrage 2026-07-21 (alle Filter + alle Triage-Funktionen gewählt):
|
||||||
|
|
||||||
|
### Filter (alle in dieser Phase)
|
||||||
|
- **D-01:** Freitext-Suche über Titel + Auftraggeber (`buyerName`). FILTER-01. (REQUIREMENTS nennt Titel/Beschreibung — Beschreibung liegt ggf. in `rawPayload`; Freitext auf indexierte Felder Titel+buyerName, `rawPayload`-Volltext ist Claude's Discretion.)
|
||||||
|
- **D-02:** Region / PLZ / Bundesland. FILTER-02. Felder liegen vor (`region`, `plz`, `bundesland`).
|
||||||
|
- **D-03:** CPV-Code / Branche — hierarchische Auswahl mit Autocomplete. FILTER-03. `cpvCodes` liegt als Array vor. Hierarchie/Autocomplete-Datenquelle (CPV-Katalog) = Research-Punkt.
|
||||||
|
- **D-04:** Abgabefrist inkl. Option „nur noch offene" (Standard-Ansicht). FILTER-04. `deadlineAt` liegt vor.
|
||||||
|
- **D-05:** Geschätzter Auftragswert min/max. FILTER-05. **Ausschreibungen ohne Wertangabe (`estimatedValue` null) dürfen NIE ausgeschlossen oder zu Fehlern führen** — sie erscheinen weiter, nur nicht bei aktivem min/max-Wertfilter, oder mit klarer „keine Wertangabe"-Markierung (genaue Semantik = Plan-Entscheidung, aber „graceful" ist Pflicht-Erfolgskriterium).
|
||||||
|
|
||||||
|
### Trefferliste & Detail
|
||||||
|
- **D-06:** Durchsuchbare, sortierbare Liste — Sortierung nach Frist, Wert, Veröffentlichungsdatum. UI-01.
|
||||||
|
- **D-07:** Detailansicht pro Ausschreibung: alle Felder + Link zur Quelle (`sourceUrl`) + ggf. Dokument-URLs aus dem Notice. **Keine lokale Spiegelung der Vergabeunterlagen** — nur Links. UI-02.
|
||||||
|
|
||||||
|
### Persönliche Funktionen (pro Nutzer, mandantenbewusst)
|
||||||
|
- **D-08:** Suchprofile: Filter-Kombination benannt speichern, bearbeiten, löschen. **Pro Nutzer**, auf den eigenen Mandanten gescoped. FILTER-06.
|
||||||
|
- **D-09:** Gelesen/Ungelesen pro Nutzer. UI-03.
|
||||||
|
- **D-10:** Favorit/Merkliste pro Nutzer + Merklisten-Filter in der Liste. UI-04.
|
||||||
|
- **D-11:** Triage-Zustände (gelesen, favorit) und Suchprofile sind **per-user**, NICHT tenant-weit geteilt.
|
||||||
|
|
||||||
|
### Abdeckungs-Transparenz
|
||||||
|
- **D-12:** UI weist Datenabdeckung aus: Oberschwelle vs. Unterschwelle. UI-05. Aktuell nur DÖE-Quelle (Oberschwelle-lastig) — die Anzeige verhindert, dass eine dünne/leere Liste als Fehler gelesen wird. Genaue Formulierung/Platzierung = Plan-Entscheidung; der Hinweis MUSS aber existieren.
|
||||||
|
|
||||||
|
### Claude's Discretion
|
||||||
|
- Query-Architektur: serverseitige Filter/Sortierung/Pagination über die globale `Tender`-Tabelle (kein `forTenant`-Scoping — Tender ist global), Prisma `where`-Aufbau, Indizes für Filter-Performance.
|
||||||
|
- Neue **per-user/per-tenant** Tabellen für Suchprofile + Triage (read/favourite) — Namen, Schema, Unique-Constraints. `FavoriteLink` existiert bereits für ein anderes Feature; NICHT wiederverwenden, eigenes Tender-Triage-Modell.
|
||||||
|
- CPV-Hierarchie/Autocomplete-Umsetzung (statischer Katalog vs. abgeleitet aus vorhandenen `cpvCodes`).
|
||||||
|
- Frontend-Aufteilung: Liste, Filter-Panel, Detailseite, Suchprofil-Verwaltung — Komponenten + TanStack-Query-Hooks.
|
||||||
|
</decisions>
|
||||||
|
|
||||||
|
<canonical_refs>
|
||||||
|
## Canonical References
|
||||||
|
|
||||||
|
**Downstream agents MUST read these before planning or implementing.**
|
||||||
|
|
||||||
|
### Phasen-Vorgaben
|
||||||
|
- `.planning/ROADMAP.md` § Phase 11 — Ziel + 5 Erfolgskriterien (Liste+Filter, Detail, Suchprofile, Triage, Abdeckungs-Anzeige). **Mode: mvp.**
|
||||||
|
- `.planning/REQUIREMENTS.md` — FILTER-01..06, UI-01..05.
|
||||||
|
|
||||||
|
### Phase-10-Fundament (verbindlich — darauf baut alles auf)
|
||||||
|
- `apps/api/prisma/schema.prisma` → Modell `Tender` (globale Tabelle, Felder: title, buyerName, cpvCodes[], region, plz, bundesland, deadlineAt, estimatedValue, procedureType, status, sourceUrl, sourcePortal, publishedAt, rawPayload …) und `TenderSourcePollConfig`.
|
||||||
|
- `apps/api/src/tenders/` — bestehendes `TendersController` (`GET /modules/tender-radar` Liste mit page/limit/status, `GET /:id` Detail), `TenderQueryDto`, Module-Registrierung. **Filter/Sort erweitern diese vorhandenen Read-Endpunkte.**
|
||||||
|
- `apps/web/src/app/(portal)/modules/tender-radar/` — bestehende Modulseite (aktuell Platzhalter „Ausschreibungen werden erfasst.") + `tender-radar-api.ts` Client + Settings-Seite. Die Modulseite wird zur echten Trefferliste ausgebaut.
|
||||||
|
- **Route-Order-Falle beachten** (Phase-10-Bug): statische Routen VOR `@Get(':id')` deklarieren, sonst 404-Shadowing. Siehe `10-VERIFICATION.md` Re-Verification.
|
||||||
|
|
||||||
|
### Milestone-Research
|
||||||
|
- `.planning/research/ARCHITECTURE.md` — global-vs-tenant-Split (Tender global; Suchprofile/Triage per-user/tenant), Schema-Konventionen.
|
||||||
|
- `.planning/research/SUMMARY.md` — Build-Order, Modul-Architektur.
|
||||||
|
</canonical_refs>
|
||||||
|
|
||||||
|
<code_context>
|
||||||
|
## Existing Code Insights
|
||||||
|
|
||||||
|
### Reusable Assets
|
||||||
|
- `apps/api/src/tenders/tenders.controller.ts` / `tenders.module.ts` — vorhandene Read-Endpunkte; Filter/Sortierung/Pagination hier erweitern (nicht neues Modul).
|
||||||
|
- `apps/web/.../modules/tender-radar/` — bestehende Modulseite, `tender-radar-api.ts`, Settings-Form als UI-/Client-Muster.
|
||||||
|
- Bestehende Modul-UIs (Cert-Manager, DKV, Domaincheck) als Template für Listen-/Detail-/Formular-Layout, shadcn/ui-Komponenten, TanStack-Query-Nutzung.
|
||||||
|
- `apps/api/src/prisma/prisma-tenant.extension.ts` (`forTenant`) — für die NEUEN per-user/per-tenant Tabellen (Suchprofile, Triage) zwingend nutzen; die globale `Tender`-Tabelle bleibt ungescoped.
|
||||||
|
- Auth/User-Kontext (JWT, `@CurrentUser`-Muster) für per-user Triage/Profile.
|
||||||
|
|
||||||
|
### Established Patterns
|
||||||
|
- shadcn/ui + Tailwind, next-intl (DE/EN), TanStack Query für Client-Datenabruf.
|
||||||
|
- Prisma-Migrationen als handgeschriebene timestamped Ordner unter `apps/api/prisma/migrations/`.
|
||||||
|
- Native `fetch` im API; `/api-proxy/*`-Rewrite im Web.
|
||||||
|
|
||||||
|
### Integration Points
|
||||||
|
- Neue Tabellen: Suchprofil (per user+tenant) und Tender-Triage (per user, Status gelesen + favorit). Migration erforderlich.
|
||||||
|
- Trefferliste konsumiert erweiterten `GET /modules/tender-radar` (Filter-Query-Params).
|
||||||
|
- Detailseite konsumiert `GET /modules/tender-radar/:id`.
|
||||||
|
- Sidebar-/Modul-Routing existiert bereits (`/modules/procurement/tender-radar`).
|
||||||
|
</code_context>
|
||||||
|
|
||||||
|
<specifics>
|
||||||
|
## Specific Ideas
|
||||||
|
|
||||||
|
- User-Frust-Auslöser adressieren: aktuell zeigt die Modulseite NICHTS. Kern dieser Phase = die 1671 vorhandenen Einträge sichtbar, durchsuchbar und triagierbar machen.
|
||||||
|
- „nur noch offene" als sinnvoller Default-Filter (D-04) — Nutzer will bietbare, aktuelle Vergaben, nicht abgelaufene.
|
||||||
|
- Wert-ohne-Angabe graceful behandeln (D-05) ist explizites Erfolgskriterium — nicht rausfiltern, nicht crashen.
|
||||||
|
- Abdeckungs-Hinweis (D-12) ist bewusst drin, weil bei nur einer Quelle (DÖE) eine dünne Liste sonst wie ein Defekt wirkt — genau die Verwirrung, die der User gerade hatte.
|
||||||
|
</specifics>
|
||||||
Reference in New Issue
Block a user