docs(11-04): complete Detailansicht plan
This commit is contained in:
@@ -36,7 +36,7 @@
|
|||||||
### UI — Anzeige & Triage
|
### UI — Anzeige & Triage
|
||||||
|
|
||||||
- [x] **UI-01**: Nutzer sieht eine durchsuchbare, sortierbare Trefferliste (Sortierung nach Frist, Wert, Veröffentlichungsdatum).
|
- [x] **UI-01**: Nutzer sieht eine durchsuchbare, sortierbare Trefferliste (Sortierung nach Frist, Wert, Veröffentlichungsdatum).
|
||||||
- [ ] **UI-02**: Nutzer öffnet eine Detailansicht einer Ausschreibung mit Link zur Quelle und ggf. Dokument-URLs (keine lokale Spiegelung der Vergabeunterlagen).
|
- [x] **UI-02**: Nutzer öffnet eine Detailansicht einer Ausschreibung mit Link zur Quelle und ggf. Dokument-URLs (keine lokale Spiegelung der Vergabeunterlagen).
|
||||||
- [ ] **UI-03**: Nutzer kann Treffer als gelesen/ungelesen markieren (pro Nutzer).
|
- [ ] **UI-03**: Nutzer kann Treffer als gelesen/ungelesen markieren (pro Nutzer).
|
||||||
- [ ] **UI-04**: Nutzer kann Treffer als Favorit/Merkliste markieren und eine Merklisten-Ansicht filtern (pro Nutzer).
|
- [ ] **UI-04**: Nutzer kann Treffer als Favorit/Merkliste markieren und eine Merklisten-Ansicht filtern (pro Nutzer).
|
||||||
- [x] **UI-05**: Die UI weist die Abdeckung transparent aus (Oberschwelle vs. Unterschwelle), damit „keine Treffer" nicht als Fehler missverstanden wird.
|
- [x] **UI-05**: Die UI weist die Abdeckung transparent aus (Oberschwelle vs. Unterschwelle), damit „keine Treffer" nicht als Fehler missverstanden wird.
|
||||||
@@ -88,7 +88,7 @@
|
|||||||
| FILTER-05 | Phase 11 | Complete |
|
| FILTER-05 | Phase 11 | Complete |
|
||||||
| FILTER-06 | Phase 11 | Pending |
|
| FILTER-06 | Phase 11 | Pending |
|
||||||
| UI-01 | Phase 11 | Complete |
|
| UI-01 | Phase 11 | Complete |
|
||||||
| UI-02 | Phase 11 | Pending |
|
| UI-02 | Phase 11 | Complete |
|
||||||
| UI-03 | Phase 11 | Pending |
|
| UI-03 | Phase 11 | Pending |
|
||||||
| UI-04 | Phase 11 | Pending |
|
| UI-04 | Phase 11 | Pending |
|
||||||
| UI-05 | Phase 11 | Complete |
|
| UI-05 | Phase 11 | Complete |
|
||||||
|
|||||||
@@ -386,12 +386,12 @@ Plans:
|
|||||||
4. User can mark a tender as read/unread and as favourite, and filter the results list to only favourites -- both states are per-user, not shared across the tenant
|
4. User can mark a tender as read/unread and as favourite, and filter the results list to only favourites -- both states are per-user, not shared across the tenant
|
||||||
5. The UI clearly indicates data coverage (Oberschwelle vs. Unterschwelle) so an empty or thin result set isn't mistaken for a bug
|
5. The UI clearly indicates data coverage (Oberschwelle vs. Unterschwelle) so an empty or thin result set isn't mistaken for a bug
|
||||||
|
|
||||||
**Plans**: 3/6 plans executed
|
**Plans**: 4/6 plans executed
|
||||||
|
|
||||||
- [x] 11-01-PLAN.md — Trefferliste + Freitext + Sortierung + Coverage-Banner (FILTER-01/04/05, UI-01/05)
|
- [x] 11-01-PLAN.md — Trefferliste + Freitext + Sortierung + Coverage-Banner (FILTER-01/04/05, UI-01/05)
|
||||||
- [x] 11-02-PLAN.md — Bundesland-Ableitung (NUTS + Backfill) + Region/PLZ/Bundesland-Filter (FILTER-02)
|
- [x] 11-02-PLAN.md — Bundesland-Ableitung (NUTS + Backfill) + Region/PLZ/Bundesland-Filter (FILTER-02)
|
||||||
- [x] 11-03-PLAN.md — CPV-Filter (Katalog + Divisionen) + Wert-Filter-UI (FILTER-03/05)
|
- [x] 11-03-PLAN.md — CPV-Filter (Katalog + Divisionen) + Wert-Filter-UI (FILTER-03/05)
|
||||||
- [ ] 11-04-PLAN.md — Detailansicht via ?tender=<id> + Quell-Link (UI-02)
|
- [x] 11-04-PLAN.md — Detailansicht via ?tender=<id> + Quell-Link (UI-02)
|
||||||
- [ ] 11-05-PLAN.md — Triage: gelesen/ungelesen + Favorit + Merklisten-Filter (UI-03/04)
|
- [ ] 11-05-PLAN.md — Triage: gelesen/ungelesen + Favorit + Merklisten-Filter (UI-03/04)
|
||||||
- [ ] 11-06-PLAN.md — Suchprofile speichern/bearbeiten/löschen (FILTER-06)
|
- [ ] 11-06-PLAN.md — Suchprofile speichern/bearbeiten/löschen (FILTER-06)
|
||||||
|
|
||||||
@@ -462,7 +462,7 @@ Phases execute in numeric order: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10
|
|||||||
| 8. Dashboard Widgets Vollimplementierung | 4/4 | Complete | 2026-07-01 |
|
| 8. Dashboard Widgets Vollimplementierung | 4/4 | Complete | 2026-07-01 |
|
||||||
| 9. Cert Manager Module | 6/6 | Complete | 2026-07-02 |
|
| 9. Cert Manager Module | 6/6 | Complete | 2026-07-02 |
|
||||||
| 10. Ausschreibungs-Radar Foundation & DÖE Ingestion | 6/6 | Complete | 2026-07-21 |
|
| 10. Ausschreibungs-Radar Foundation & DÖE Ingestion | 6/6 | Complete | 2026-07-21 |
|
||||||
| 11. Filter Engine, Results UI & Saved Searches | 3/6 | In Progress| |
|
| 11. Filter Engine, Results UI & Saved Searches | 4/6 | In Progress| |
|
||||||
| 12. Tender Notifications | 0/TBD | Not started | - |
|
| 12. Tender Notifications | 0/TBD | Not started | - |
|
||||||
| 13. Scraping Adapters & Cross-Source Deduplication | 0/TBD | Not started | - |
|
| 13. Scraping Adapters & Cross-Source Deduplication | 0/TBD | Not started | - |
|
||||||
| 14. RSS, Email-Alert Ingestion & Module Rollout | 0/TBD | Not started | - |
|
| 14. RSS, Email-Alert Ingestion & Module Rollout | 0/TBD | Not started | - |
|
||||||
|
|||||||
+10
-7
@@ -5,15 +5,15 @@ milestone_name: Ausschreibungs-Radar
|
|||||||
current_phase: 11
|
current_phase: 11
|
||||||
current_phase_name: filter-engine-results-ui-saved-searches
|
current_phase_name: filter-engine-results-ui-saved-searches
|
||||||
status: executing
|
status: executing
|
||||||
stopped_at: Completed 11-03-PLAN.md
|
stopped_at: Completed 11-04-PLAN.md
|
||||||
last_updated: "2026-07-21T14:16:54.557Z"
|
last_updated: "2026-07-21T14:23:31.171Z"
|
||||||
last_activity: 2026-07-21
|
last_activity: 2026-07-21
|
||||||
last_activity_desc: Phase 11 execution started
|
last_activity_desc: Phase 11 execution started
|
||||||
progress:
|
progress:
|
||||||
total_phases: 11
|
total_phases: 11
|
||||||
completed_phases: 9
|
completed_phases: 9
|
||||||
total_plans: 52
|
total_plans: 52
|
||||||
completed_plans: 48
|
completed_plans: 49
|
||||||
---
|
---
|
||||||
|
|
||||||
# Project State
|
# Project State
|
||||||
@@ -28,11 +28,11 @@ See: .planning/PROJECT.md (updated 2026-07-17)
|
|||||||
## Current Position
|
## Current Position
|
||||||
|
|
||||||
Phase: 11 (filter-engine-results-ui-saved-searches) — EXECUTING
|
Phase: 11 (filter-engine-results-ui-saved-searches) — EXECUTING
|
||||||
Plan: 4 of 6
|
Plan: 5 of 6
|
||||||
Status: Ready to execute
|
Status: Ready to execute
|
||||||
Last activity: 2026-07-21 — Phase 11 execution started
|
Last activity: 2026-07-21 — Phase 11 execution started
|
||||||
|
|
||||||
Progress: [█████████░] 92%
|
Progress: [█████████░] 94%
|
||||||
|
|
||||||
## Performance Metrics
|
## Performance Metrics
|
||||||
|
|
||||||
@@ -83,6 +83,7 @@ Progress: [█████████░] 92%
|
|||||||
| Phase 11 P01 | 8min | 3 tasks | 11 files |
|
| Phase 11 P01 | 8min | 3 tasks | 11 files |
|
||||||
| Phase 11 P02 | 4min | 3 tasks | 12 files |
|
| Phase 11 P02 | 4min | 3 tasks | 12 files |
|
||||||
| Phase 11 P03 | 9min | 4 tasks | 12 files |
|
| Phase 11 P03 | 9min | 4 tasks | 12 files |
|
||||||
|
| Phase 11 P04 | 12min | 2 tasks | 5 files |
|
||||||
|
|
||||||
## Accumulated Context
|
## Accumulated Context
|
||||||
|
|
||||||
@@ -173,6 +174,8 @@ Recent decisions affecting current work:
|
|||||||
- [Phase ?]: BUNDESLAND_OPTIONS im Web als kleine Konstante gespiegelt (kein Shared-Package) — web nutzt @tessera/shared nicht, 16-Werte-Katalog rechtfertigt keine neue Cross-Package-Abhängigkeit.
|
- [Phase ?]: BUNDESLAND_OPTIONS im Web als kleine Konstante gespiegelt (kein Shared-Package) — web nutzt @tessera/shared nicht, 16-Werte-Katalog rechtfertigt keine neue Cross-Package-Abhängigkeit.
|
||||||
- [Phase ?]: CPV-Divisions-Kurzkatalog (2-stellig, ~45 Einträge) statt EU-Vollkatalog; hasSome-Match gegen precomputed cpvDivisions-Spalte statt Raw-SQL-Präfix-Match
|
- [Phase ?]: CPV-Divisions-Kurzkatalog (2-stellig, ~45 Einträge) statt EU-Vollkatalog; hasSome-Match gegen precomputed cpvDivisions-Spalte statt Raw-SQL-Präfix-Match
|
||||||
- [Phase ?]: cpv-URL-Param als wiederholter Key (?cpv=45&cpv=71) statt Komma-Join; DTO normalisiert Einzelwert per @Transform zu Array
|
- [Phase ?]: cpv-URL-Param als wiederholter Key (?cpv=45&cpv=71) statt Komma-Join; DTO normalisiert Einzelwert per @Transform zu Array
|
||||||
|
- [Phase ?]: TenderDetail fetcht selbstständig via getTender(tenderId) im useEffect (Muster SourceConfigForm); page.tsx bleibt reiner ?tender-Param-Reader
|
||||||
|
- [Phase ?]: ResultsList.tsx modifiziert (nicht im Plan gelistet) — Rule 3: Zeilen-Klick-Handler war notwendig, um den Plan-eigenen key_link/Done-Kriterium zu erfüllen
|
||||||
|
|
||||||
### Pending Todos
|
### Pending Todos
|
||||||
|
|
||||||
@@ -210,7 +213,7 @@ Items acknowledged and carried forward from previous milestone close:
|
|||||||
|
|
||||||
## Session Continuity
|
## Session Continuity
|
||||||
|
|
||||||
Last session: 2026-07-21T14:16:54.544Z
|
Last session: 2026-07-21T14:23:31.158Z
|
||||||
Stopped at: Completed 11-03-PLAN.md
|
Stopped at: Completed 11-04-PLAN.md
|
||||||
Resume file: None
|
Resume file: None
|
||||||
Last activity: 2026-07-14 - Built LDAP per-user exclude/denylist filter (9d1323f), migration applied on live DB, verified via Playwright: sync deactivated 4 excluded service accounts (administrator/krbtgt/guest/dns-ldap), 2 real LDAP users stay active, 0 wrongly created
|
Last activity: 2026-07-14 - Built LDAP per-user exclude/denylist filter (9d1323f), migration applied on live DB, verified via Playwright: sync deactivated 4 excluded service accounts (administrator/krbtgt/guest/dns-ldap), 2 real LDAP users stay active, 0 wrongly created
|
||||||
|
|||||||
@@ -0,0 +1,152 @@
|
|||||||
|
---
|
||||||
|
phase: 11-filter-engine-results-ui-saved-searches
|
||||||
|
plan: 04
|
||||||
|
subsystem: ui
|
||||||
|
tags: [nextjs-app-router, react, vitest, testing-library]
|
||||||
|
|
||||||
|
requires:
|
||||||
|
- phase: 11-filter-engine-results-ui-saved-searches
|
||||||
|
plan: 01
|
||||||
|
provides: "Modulseite (page.tsx), ResultsList, tender-radar-api.ts Client, GET /modules/tender-radar/:id Backend-Endpunkt"
|
||||||
|
provides:
|
||||||
|
- "getTender(id): Promise<Tender> im tender-radar-api.ts Client"
|
||||||
|
- "TenderDetail.tsx: selbstständig fetchende In-Component-Detailansicht"
|
||||||
|
- "?tender=<id> URL-Verdrahtung: ResultsList-Zeile setzt Param, page.tsx liest ihn und rendert TenderDetail als Overlay"
|
||||||
|
affects: [11-05-triage, 11-06-saved-searches]
|
||||||
|
|
||||||
|
tech-stack:
|
||||||
|
added: []
|
||||||
|
patterns:
|
||||||
|
- "Selbstständig fetchende Detail-Komponente (Muster SourceConfigForm): Container reicht nur die ID durch, Fetch+Ladezustand lebt in der Komponente selbst"
|
||||||
|
- "?tender=<id> als In-Component-Overlay statt Next.js-Unterroute — Modul ist als dynamic(ssr:false)-Komponente gemountet (Anti-Pattern A5)"
|
||||||
|
|
||||||
|
key-files:
|
||||||
|
created:
|
||||||
|
- apps/web/src/app/(portal)/modules/tender-radar/components/TenderDetail.tsx
|
||||||
|
- apps/web/src/app/(portal)/modules/tender-radar/components/TenderDetail.test.tsx
|
||||||
|
modified:
|
||||||
|
- apps/web/src/lib/tender-radar-api.ts
|
||||||
|
- apps/web/src/app/(portal)/modules/tender-radar/page.tsx
|
||||||
|
- apps/web/src/app/(portal)/modules/tender-radar/components/ResultsList.tsx
|
||||||
|
|
||||||
|
key-decisions:
|
||||||
|
- "TenderDetail fetcht selbstständig via getTender(tenderId) im useEffect (Muster SourceConfigForm), statt dass page.tsx den Tender lädt und als Prop durchreicht — page.tsx bleibt ein reiner ?tender-Param-Reader, die gesamte Lade-/Fehler-/NULL-Logik lebt in einer einzigen testbaren Komponente."
|
||||||
|
- "Deviation (Rule 3, blocking): ResultsList.tsx wurde modifiziert, obwohl nicht in den files_modified des Plans gelistet. Der Plan-eigene key_link ('ResultsList-Zeile setzt ?tender=<id>') und das Done-Kriterium ('Klick auf eine Zeile öffnet die Detailansicht') sind ohne einen Klick-Handler in ResultsList technisch nicht erfüllbar — die Modifikation war notwendig, um den Plan selbst zu erfüllen."
|
||||||
|
|
||||||
|
requirements-completed: [UI-02]
|
||||||
|
|
||||||
|
coverage:
|
||||||
|
- id: D1
|
||||||
|
description: "TenderDetail rendert alle vorhandenen Tender-Felder (Titel, Auftraggeber, Region/PLZ/Bundesland, CPV, Frist, Wert, Verfahrensart, Status, Veröffentlichungsdatum) und einen sicheren sourceUrl-Link (target=_blank, rel=noopener noreferrer)"
|
||||||
|
requirement: "UI-02"
|
||||||
|
verification:
|
||||||
|
- kind: unit
|
||||||
|
ref: "apps/web/src/app/(portal)/modules/tender-radar/components/TenderDetail.test.tsx#renders a source link pointing at the tender sourceUrl with safe target/rel"
|
||||||
|
status: pass
|
||||||
|
human_judgment: false
|
||||||
|
- id: D2
|
||||||
|
description: "estimatedValue=null und deadlineAt=null rendern 'keine Wertangabe' / 'keine Frist angegeben' statt Fehler/leer (D-05 gilt auch für die Detailansicht)"
|
||||||
|
requirement: "UI-02"
|
||||||
|
verification:
|
||||||
|
- kind: unit
|
||||||
|
ref: "apps/web/src/app/(portal)/modules/tender-radar/components/TenderDetail.test.tsx#shows graceful placeholders when estimatedValue and deadlineAt are null"
|
||||||
|
status: pass
|
||||||
|
human_judgment: false
|
||||||
|
- id: D3
|
||||||
|
description: "Klarer Hinweis, dass Vergabeunterlagen nicht lokal gespiegelt werden, ist immer sichtbar; kein Live-Dokument-Fetch/Mirroring implementiert (rawPayload 100% NULL, keine Dokument-URLs vorhanden)"
|
||||||
|
requirement: "UI-02"
|
||||||
|
verification:
|
||||||
|
- kind: unit
|
||||||
|
ref: "apps/web/src/app/(portal)/modules/tender-radar/components/TenderDetail.test.tsx#always shows the no-local-mirroring notice for Vergabeunterlagen"
|
||||||
|
status: pass
|
||||||
|
human_judgment: false
|
||||||
|
- id: D4
|
||||||
|
description: "ResultsList-Zeile setzt ?tender=<id> via router.replace; page.tsx liest den Param, rendert TenderDetail als Overlay, Schließen entfernt den Param"
|
||||||
|
requirement: "UI-02"
|
||||||
|
verification:
|
||||||
|
- kind: unit
|
||||||
|
ref: "tsc --noEmit clean; voller Web-Test-Suite (117 Tests) grün — keine Regression in ResultsList/page.tsx"
|
||||||
|
status: pass
|
||||||
|
human_judgment: true
|
||||||
|
rationale: "Die eigentliche Klick-Interaktion (Zeile klicken -> Overlay öffnet -> Quell-Link öffnet neuen Tab -> Schließen entfernt Overlay) ist eine visuelle/UX-Interaktion im Browser gegen die echte Live-DB (~1671 Zeilen) und erfordert einen Docker-Rebuild + manuellen Klick-Test (User führt Docker-Rebuild selbst aus, projektinterne Regel) — Unit-Tests decken die Render-/Formatierungslogik ab, nicht die End-to-End-Klick-Interaktion im laufenden Container."
|
||||||
|
|
||||||
|
duration: 12min
|
||||||
|
completed: 2026-07-21
|
||||||
|
status: complete
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 11 Plan 04: Detailansicht (TenderDetail) Summary
|
||||||
|
|
||||||
|
**Selbstständig fetchende `?tender=<id>`-In-Component-Overlay-Detailansicht mit allen Tender-Feldern, sicherem sourceUrl-Link und explizitem Kein-Mirroring-Hinweis — keine lokale Spiegelung der Vergabeunterlagen, da `rawPayload` zu 100% NULL ist.**
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
- **Duration:** 12 min
|
||||||
|
- **Started:** 2026-07-21T16:19:40+02:00
|
||||||
|
- **Completed:** 2026-07-21T16:31:xx+02:00 (see final commit)
|
||||||
|
- **Tasks:** 2 (Task 1 TDD: RED + GREEN; Task 2 bereits durch Task 1s RED-Testfile vollständig erfüllt)
|
||||||
|
- **Files modified:** 5 (2 created, 3 modified)
|
||||||
|
|
||||||
|
## Accomplishments
|
||||||
|
|
||||||
|
- `tender-radar-api.ts`: `getTender(id): Promise<Tender>` ergänzt — `GET /modules/tender-radar/:id`, plain fetch, `credentials: 'include'` (bestehendes Backend-Endpoint aus Phase 10/11-01, keine Backend-Änderung nötig).
|
||||||
|
- `TenderDetail.tsx`: neue, selbstständig fetchende Overlay-Komponente (Muster `SourceConfigForm`). Rendert Titel, Auftraggeber, Region/PLZ/Bundesland, CPV-Codes, Abgabefrist, geschätzten Wert, Verfahrensart, Status, Veröffentlichungsdatum. `estimatedValue=null` → „keine Wertangabe", `deadlineAt=null` → „keine Frist angegeben", `cpvCodes=[]` → „keine CPV-Codes angegeben" — nichts wird verschwiegen oder wirft einen Fehler (D-05 gilt auch hier). Deutlich sichtbarer Hinweis „Vergabeunterlagen werden nicht lokal gespiegelt" über dem `sourceUrl`-Link (`target="_blank" rel="noopener noreferrer"`, T-11-09); fehlt `sourceUrl`, wird „Kein Quell-Link verfügbar." angezeigt statt eines toten Links.
|
||||||
|
- `page.tsx`: liest `useSearchParams().get('tender')`; ist der Param gesetzt, wird `<TenderDetail tenderId onClose>` als Overlay über der bestehenden Liste/Filter gerendert; Schließen (Button oder Backdrop-Klick) entfernt den Param via `router.replace`.
|
||||||
|
- `ResultsList.tsx` (Deviation, siehe unten): Zeilen sind jetzt klickbar (`cursor-pointer`, `onClick`) und setzen `?tender=<id>` — ohne diese Änderung wäre der Plan-eigene key_link nicht erfüllbar gewesen.
|
||||||
|
|
||||||
|
## Task Commits
|
||||||
|
|
||||||
|
1. **Task 1a: TenderDetail RED** — `3cc7194` (test) — failing `TenderDetail.test.tsx` (3 Tests: sourceUrl-Link + safe target/rel, NULL-graceful Wert/Frist, Kein-Mirroring-Hinweis)
|
||||||
|
2. **Task 1b: TenderDetail GREEN** — `653c63b` (feat) — `getTender()`, `TenderDetail.tsx`, `page.tsx`-Verdrahtung, `ResultsList.tsx`-Klick-Handler implementiert, 3/3 Tests grün
|
||||||
|
|
||||||
|
_Task 1 ist `tdd="true"` — RED-Commit dann GREEN-Commit._
|
||||||
|
|
||||||
|
**Task 2 (Komponententest TenderDetail):** Die drei geforderten Testfälle (a: sourceUrl-Link, b: NULL-Graceful, c: Kein-Mirroring-Hinweis) waren bereits vollständig Teil des RED-Testfiles aus Task 1 (identische Datei `TenderDetail.test.tsx`, identische Anforderungen). Es gab keine eigenständige, von Task 1 verschiedene Aktion mehr auszuführen — daher kein separater Commit für Task 2. Verifiziert durch erneutes Ausführen der Testsuite (weiterhin 3/3 grün, siehe Self-Check).
|
||||||
|
|
||||||
|
## Files Created/Modified
|
||||||
|
- `apps/web/src/lib/tender-radar-api.ts` - `getTender(id)` ergänzt
|
||||||
|
- `apps/web/src/app/(portal)/modules/tender-radar/components/TenderDetail.tsx` - Detail-Overlay-Komponente (neu)
|
||||||
|
- `apps/web/src/app/(portal)/modules/tender-radar/components/TenderDetail.test.tsx` - 3 Component-Tests (neu)
|
||||||
|
- `apps/web/src/app/(portal)/modules/tender-radar/page.tsx` - `?tender`-Param-Verdrahtung + Overlay-Rendering
|
||||||
|
- `apps/web/src/app/(portal)/modules/tender-radar/components/ResultsList.tsx` - Zeilen-Klick setzt `?tender=<id>` (Deviation)
|
||||||
|
|
||||||
|
## Decisions Made
|
||||||
|
|
||||||
|
- `TenderDetail` fetcht selbstständig via `getTender(tenderId)` im `useEffect` (Muster `SourceConfigForm.tsx`) statt dass `page.tsx` den Tender lädt und als Prop durchreicht. `page.tsx` bleibt dadurch ein reiner `?tender`-Param-Reader; Lade-/Fehler-/NULL-Zustandslogik lebt vollständig in einer einzigen, unabhängig testbaren Komponente — konsistent mit dem einzigen existierenden Precedent für eine "auf ID fetchende" Detail-Komponente im Modul.
|
||||||
|
- Backdrop-Klick schließt das Overlay zusätzlich zum expliziten „Schließen"-Button — nicht explizit im Plan gefordert, aber Standard-Overlay-UX-Erwartung (Rule 1/2-Grenzfall, unter Correctness/UX eingeordnet, kein separater Deviation-Fall da rein additiv und ohne Verhaltensänderung der geforderten Felder).
|
||||||
|
|
||||||
|
## Deviations from Plan
|
||||||
|
|
||||||
|
### Auto-fixed Issues
|
||||||
|
|
||||||
|
**1. [Rule 3 - Blocking] `ResultsList.tsx` wurde modifiziert, obwohl nicht in `files_modified` des Plans gelistet**
|
||||||
|
- **Found during:** Task 1 (Verdrahtung)
|
||||||
|
- **Issue:** Der Plan fordert explizit im `key_links`-Feld: „ResultsList-Zeile setzt ?tender=<id> → page.tsx liest useSearchParams → getTender(id) → ... → TenderDetail" und im Done-Kriterium: „Klick auf eine Zeile öffnet die Detailansicht via ?tender=<id>". Ohne einen Klick-Handler auf den Zeilen in `ResultsList.tsx` ist dieser Fluss technisch nicht herstellbar — `page.tsx` allein kann den Param nicht "von einer Zeile aus" setzen, da die Zeilen in `ResultsList` gerendert werden.
|
||||||
|
- **Fix:** `openDetail(id)`-Funktion in `ResultsList.tsx` ergänzt (identisches Muster zu vorhandenem `goToPage`/`handleSort`), Zeilen erhielten `onClick={() => openDetail(tender.id)}` + `cursor-pointer`.
|
||||||
|
- **Files modified:** `apps/web/src/app/(portal)/modules/tender-radar/components/ResultsList.tsx`
|
||||||
|
- **Commit:** `653c63b`
|
||||||
|
|
||||||
|
## Auth Gates
|
||||||
|
|
||||||
|
None.
|
||||||
|
|
||||||
|
## Issues Encountered
|
||||||
|
|
||||||
|
None.
|
||||||
|
|
||||||
|
## User Setup Required
|
||||||
|
|
||||||
|
None — keine externen Service-Konfigurationen erforderlich. Keine neuen npm-Pakete (RESEARCH Package Legitimacy Audit: keine Neuinstallation).
|
||||||
|
|
||||||
|
## Next Phase Readiness
|
||||||
|
|
||||||
|
- `?tender=<id>`-URL-Vertrag ist etabliert und stabil für Plan 11-05 (Triage: gelesen/Favorit-Buttons könnten künftig direkt in `TenderDetail` ergänzt werden) und 11-06 (Saved Searches: der `tender`-Param wird bei Saved-Search-Serialisierung nicht mitgespeichert, da er kein Filter-Kriterium ist — kein Konflikt).
|
||||||
|
- **Manuelle UAT ausstehend:** Der Docker-Stack läuft mit alten Images — für eine Live-Verifikation im Browser (Zeile klicken, Overlay-Layout prüfen, sourceUrl-Link in neuem Tab öffnen, Schließen-Verhalten) ist `docker compose build api web && docker compose up -d` erforderlich (User führt Docker-Rebuild selbst aus, keine Docker-Deploys durch Claude auf dem Testserver — projektinterne Regel). Alle automatisierten Tests (117 Web-Tests inkl. 3 neue TenderDetail-Tests) sind grün; `tsc --noEmit` fehlerfrei.
|
||||||
|
|
||||||
|
---
|
||||||
|
*Phase: 11-filter-engine-results-ui-saved-searches*
|
||||||
|
*Completed: 2026-07-21*
|
||||||
|
|
||||||
|
## Self-Check: PASSED
|
||||||
|
|
||||||
|
All 5 created/modified files verified present on disk; both task commits (3cc7194, 653c63b) verified in git log.
|
||||||
Reference in New Issue
Block a user