1330 lines
24 KiB
Markdown
1330 lines
24 KiB
Markdown
# Buying Agent – Frontend MVP Specification v0.2
|
||
|
||
**Status:** Review Candidate – vor Implementierung erneut durch den Coding-Agenten zu prüfen
|
||
**Spezifikationsversion:** 0.2
|
||
**Stand:** 2026-10-04
|
||
**Ersetzt vollständig:** `buying-agent-frontend-mvp-spec-v0.1.md`
|
||
|
||
**Gilt zusammen mit:**
|
||
1. `buying-agent-v0.1-spec-v1.1.md`
|
||
2. `buying-agent-architecture-addendum-v1.md`
|
||
3. `buying-agent-source-discovery-spec-v0.1.md`
|
||
|
||
Bei Widersprüchen innerhalb des Frontend-/MVP-Bereichs hat diese v0.2 Vorrang.
|
||
Sie präzisiert außerdem die für das Frontend notwendigen Backend-Verträge.
|
||
|
||
---
|
||
|
||
# 1. Zielbild
|
||
|
||
Der Buying Agent soll nicht nur ein Backend-Skeleton sein, sondern als **nutzbare PWA** einen vollständigen vertikalen Nutzerfluss abbilden.
|
||
|
||
Der Nutzer soll ohne technische Kenntnisse:
|
||
|
||
```text
|
||
BuyingProject anlegen
|
||
↓
|
||
Produktkategorie auswählen
|
||
↓
|
||
verfügbare Kriterien aus der Source-Taxonomie laden
|
||
↓
|
||
gewünschte Suchparameter auswählen und Werte setzen
|
||
↓
|
||
externe Suche generieren
|
||
↓
|
||
SearchRun starten / Status verfolgen
|
||
↓
|
||
Kandidaten sehen
|
||
↓
|
||
Shortlist / Ranking sehen, soweit konfiguriert
|
||
↓
|
||
Kandidat öffnen
|
||
↓
|
||
Attribute, Preise, Historie und bisherigen Status sehen
|
||
↓
|
||
Kriterien anpassen
|
||
↓
|
||
neue Suche ausführen
|
||
```
|
||
|
||
Die Oberfläche soll einfach bleiben. Die technische Komplexität verbleibt im Backend.
|
||
|
||
---
|
||
|
||
# 2. Grundsätzliche Architektur
|
||
|
||
## 2.1 Backend bleibt System of Record
|
||
|
||
Das Frontend enthält keine fachliche Kernlogik.
|
||
|
||
Es konsumiert ausschließlich die versionierte `/api/v1`-API.
|
||
|
||
Fachliche Entscheidungen über:
|
||
|
||
- Taxonomie
|
||
- Mapping
|
||
- Query-Generierung
|
||
- Produktidentität
|
||
- Diffing
|
||
- Ranking
|
||
- Historisierung
|
||
- Lifecycle
|
||
|
||
liegen im Backend.
|
||
|
||
## 2.2 Keine Canonical-Criteria-Schicht
|
||
|
||
Es wird **keine separate globale Canonical-Criteria-Ontologie** eingeführt.
|
||
|
||
Für eine unterstützte Source/Kategorie bildet deren gelernte Taxonomie zunächst den primären Kriterienkatalog.
|
||
|
||
Jedes Source-Kriterium erhält lediglich eine stabile interne ID:
|
||
|
||
```text
|
||
CriterionDefinition.id = interne UUID
|
||
```
|
||
|
||
Diese ID dient als Persistenz- und Referenzidentität.
|
||
|
||
Sie ist keine Behauptung, dass das Kriterium global quellenunabhängig kanonisch sei.
|
||
|
||
## 2.3 Source-Kriterien und Ergebnisattribute werden verbunden
|
||
|
||
Ein Kriterium muss sowohl mit dem Suchfilter als auch mit den aus Suchergebnissen bzw. Produktdetailseiten extrahierten Attributen verbunden werden können.
|
||
|
||
Beispiel:
|
||
|
||
```text
|
||
CriterionDefinition
|
||
id = <uuid>
|
||
origin = SOURCE
|
||
source = geizhals
|
||
category = notebook
|
||
label = "Arbeitsspeicher"
|
||
|
||
SourceFilterMapping:
|
||
Geizhals Filter 17023 -> CriterionDefinition.id
|
||
|
||
SourceAttributeMapping:
|
||
"RAM" -> CriterionDefinition.id
|
||
"Arbeitsspeicher" -> CriterionDefinition.id
|
||
ggf. source_attribute_id -> CriterionDefinition.id
|
||
```
|
||
|
||
Eine Produktbeobachtung soll dann auf dieselbe interne CriterionDefinition referenzieren:
|
||
|
||
```text
|
||
ProductAttributeObservation
|
||
- source_product_reference_id
|
||
- criterion_definition_id
|
||
- raw_name
|
||
- raw_value
|
||
- normalized_value
|
||
- unit
|
||
- observed_at
|
||
```
|
||
|
||
## 2.4 INTERNAL-Kriterien
|
||
|
||
Zusätzliche interne Kriterien werden nur angelegt, wenn für die Kaufentscheidung relevante Eigenschaften von der Source-Taxonomie nicht angeboten werden.
|
||
|
||
Beispiele:
|
||
|
||
- externer Akku-Benchmark
|
||
- Reparierbarkeit
|
||
- Testscore
|
||
- Lautstärke unter Last
|
||
|
||
```text
|
||
CriterionDefinition.origin = INTERNAL
|
||
```
|
||
|
||
Diese besitzen naturgemäß keinen Source-Filter, können aber später von anderen Datenquellen befüllt werden.
|
||
|
||
---
|
||
|
||
# 3. Produktkategorien
|
||
|
||
Das BuyingProject referenziert eine interne `ProductCategory`.
|
||
|
||
Beispiel:
|
||
|
||
```text
|
||
ProductCategory
|
||
id = notebook
|
||
name = Notebooks
|
||
```
|
||
|
||
Die Source-spezifische Kategorie wird separat gemappt:
|
||
|
||
```text
|
||
SourceCategory
|
||
source = geizhals
|
||
external_category_key = nb
|
||
product_category_id = notebook
|
||
```
|
||
|
||
Damit ist das BuyingProject nicht direkt an `geizhals/nb` gekoppelt.
|
||
|
||
---
|
||
|
||
# 4. BuyingProject
|
||
|
||
Ein BuyingProject ist die konkrete Instanz eines Kaufvorhabens.
|
||
|
||
Es kann **ohne ProductProfile** angelegt werden.
|
||
|
||
Mindestens:
|
||
|
||
```text
|
||
id
|
||
workspace_id nullable
|
||
name
|
||
product_category_id
|
||
market
|
||
currency
|
||
budget_target nullable
|
||
budget_maximum nullable
|
||
shortlist_size
|
||
schedule_interval_minutes
|
||
status
|
||
created_at
|
||
updated_at
|
||
archived_at nullable
|
||
```
|
||
|
||
Status:
|
||
|
||
```text
|
||
ACTIVE
|
||
PURCHASED
|
||
ARCHIVED
|
||
```
|
||
|
||
Default:
|
||
|
||
```text
|
||
shortlist_size = 5
|
||
schedule_interval_minutes = 180
|
||
```
|
||
|
||
---
|
||
|
||
# 5. Rolle von ProductProfile / BuyingTemplate
|
||
|
||
Das bisherige `ProductProfile` ist für neue BuyingProjects **nicht verpflichtend**.
|
||
|
||
Fachlich wird es künftig als optionale Vorlage verstanden.
|
||
|
||
Zielbild:
|
||
|
||
```text
|
||
BuyingTemplate
|
||
"Mobiler Entwicklungsrechner"
|
||
↓ optional beim Projektstart
|
||
BuyingProject
|
||
```
|
||
|
||
Eine Vorlage kann z. B. liefern:
|
||
|
||
- vorgeschlagene Suchkriterien
|
||
- Ranking-Konfiguration
|
||
- Default-Budget
|
||
- Kategorie
|
||
- Markt / Währung
|
||
|
||
Beim Erstellen eines Projekts werden relevante Werte in die Projektkonfiguration übernommen.
|
||
|
||
Spätere Änderungen an der Vorlage verändern bestehende Projekte **nicht rückwirkend**.
|
||
|
||
Zur Nachvollziehbarkeit darf gespeichert werden:
|
||
|
||
```text
|
||
template_id
|
||
template_version
|
||
```
|
||
|
||
Die bestehende ProductProfile-Implementierung darf technisch weiterverwendet werden, solange sie nicht mehr als zwingende Voraussetzung für ein BuyingProject fungiert.
|
||
|
||
---
|
||
|
||
# 6. ProjectCriteria
|
||
|
||
## 6.1 Zweck
|
||
|
||
ProjectCriteria beschreiben die vom Nutzer gewählten Suchparameter eines BuyingProjects.
|
||
|
||
Sie referenzieren die dynamisch geladenen CriterionDefinitions.
|
||
|
||
Beispiel:
|
||
|
||
```text
|
||
ProjectCriterion
|
||
- id
|
||
- project_id
|
||
- criterion_definition_id
|
||
- operator
|
||
- value
|
||
- enabled_for_discovery
|
||
- created_at
|
||
- updated_at
|
||
```
|
||
|
||
## 6.2 Standard-UI
|
||
|
||
Die Standardoberfläche zeigt **keine** technischen Ranking-Parameter wie:
|
||
|
||
- weight
|
||
- acceptable
|
||
- ideal
|
||
- strategy
|
||
- scoring_version
|
||
|
||
Der Nutzer wählt lediglich:
|
||
|
||
```text
|
||
Kriterium
|
||
Operator
|
||
Wert / Wertebereich
|
||
für externe Suche aktiv ja/nein
|
||
```
|
||
|
||
Optional kann später eine einfache Kennzeichnung wie „Muss“ / „Wunsch“ ergänzt werden, sie ist für v0.2 nicht Voraussetzung.
|
||
|
||
## 6.3 Beispiel
|
||
|
||
```text
|
||
Arbeitsspeicher >= 24 GB
|
||
Preis <= 1700 EUR
|
||
Gewicht <= 1.5 kg
|
||
```
|
||
|
||
Die verfügbaren Operatoren und UI-Controls werden aus der SourceFilterDefinition bzw. CriterionDefinition abgeleitet.
|
||
|
||
---
|
||
|
||
# 7. Ranking-Konfiguration
|
||
|
||
Discovery und Ranking bleiben getrennte fachliche Bereiche.
|
||
|
||
ProjectCriteria dürfen keine versteckten Scoring-Regeln erzwingen.
|
||
|
||
Ein Projekt kann optional eine Ranking-Konfiguration besitzen.
|
||
|
||
Mögliche Herkunft:
|
||
|
||
1. aus einem BuyingTemplate/ProductProfile übernommen
|
||
2. später explizit durch Advanced UI
|
||
3. später von KI vorgeschlagen
|
||
4. später durch eine Default-Strategie erzeugt
|
||
|
||
Für den MVP gilt:
|
||
|
||
- Ein Projekt ohne Ranking-Konfiguration darf trotzdem Discovery ausführen.
|
||
- In diesem Zustand zeigt das Frontend Kandidaten, aber kennzeichnet Ranking als `NOT_CONFIGURED`.
|
||
- Für den Notebook-Pilot kann das vorhandene Profil `mobile-development-notebook` als optionale Vorlage genutzt werden, damit ProductScore/Shortlist end-to-end getestet werden können.
|
||
- Es dürfen keine stillen, nicht dokumentierten Scoring-Regeln erfunden werden.
|
||
|
||
---
|
||
|
||
# 8. Criterion-Katalog vor Projektanlage
|
||
|
||
Der Projekt-Wizard muss Kriterien laden können, bevor eine Project-ID existiert.
|
||
|
||
Erforderliche Endpunkte:
|
||
|
||
```text
|
||
GET /api/v1/sources
|
||
GET /api/v1/sources/{source}/categories
|
||
GET /api/v1/sources/{source}/categories/{category}/available-criteria
|
||
```
|
||
|
||
`available-criteria` liefert mindestens:
|
||
|
||
```text
|
||
criterion_definition_id
|
||
label
|
||
description nullable
|
||
origin
|
||
source
|
||
category
|
||
filter_type
|
||
unit nullable
|
||
operators
|
||
options / range metadata
|
||
mapping_status
|
||
supports_discovery
|
||
```
|
||
|
||
Nur Source-Kriterien mit nutzbarer Filterdefinition werden als externe Suchparameter angeboten.
|
||
|
||
INTERNAL-Kriterien dürfen separat sichtbar sein, wenn sie für die Kategorie bekannt sind.
|
||
|
||
---
|
||
|
||
# 9. Taxonomie-Lernen
|
||
|
||
Taxonomie wird on demand pro Kategorie gelernt.
|
||
|
||
Initial:
|
||
|
||
```text
|
||
Geizhals -> Notebooks
|
||
```
|
||
|
||
Die gelernte Taxonomie soll später im Admin-Bereich bearbeitbar sein.
|
||
|
||
Mapping-Status:
|
||
|
||
```text
|
||
DISCOVERED
|
||
LEARNED_UNVERIFIED
|
||
VERIFIED
|
||
BROKEN
|
||
DISABLED
|
||
```
|
||
|
||
Nur `VERIFIED` darf automatisch für produktive Source-Query-Generierung verwendet werden.
|
||
|
||
Technisch eindeutige automatische Verifikation ist zulässig, wenn der Backend-Service einen reproduzierbaren Roundtrip sicher nachweisen kann.
|
||
|
||
---
|
||
|
||
# 10. DiscoverySearch
|
||
|
||
Persistenz bleibt **1:n**:
|
||
|
||
```text
|
||
BuyingProject
|
||
└── DiscoverySearch[]
|
||
```
|
||
|
||
Für den ersten MVP gilt als fachliche Einschränkung:
|
||
|
||
```text
|
||
maximal eine aktive DiscoverySearch
|
||
pro BuyingProject + Source + SourceCategory
|
||
```
|
||
|
||
Diese Einschränkung darf nicht als dauerhafte 1:1-Beziehung in das Datenmodell eingebaut werden.
|
||
|
||
Mindestens:
|
||
|
||
```text
|
||
id
|
||
buying_project_id
|
||
source_id
|
||
source_category_id
|
||
criteria_version
|
||
mapping_version
|
||
generated_url
|
||
status
|
||
schedule_interval_minutes
|
||
next_run_at nullable
|
||
last_successful_run_at nullable
|
||
created_at
|
||
updated_at
|
||
```
|
||
|
||
---
|
||
|
||
# 11. Statuswelten strikt trennen
|
||
|
||
## 11.1 Project Lifecycle
|
||
|
||
```text
|
||
ACTIVE
|
||
PURCHASED
|
||
ARCHIVED
|
||
```
|
||
|
||
## 11.2 DiscoverySearch / SearchRun Status
|
||
|
||
Je nach fachlicher Ebene:
|
||
|
||
```text
|
||
RUNNING
|
||
SUCCESS
|
||
PARTIAL
|
||
FAILED
|
||
BLOCKED
|
||
TOO_BROAD
|
||
OUT_OF_SYNC
|
||
```
|
||
|
||
`OUT_OF_SYNC` gehört fachlich zur Search-Konfiguration.
|
||
|
||
`TOO_BROAD` beschreibt den Zustand bzw. das Ergebnis einer DiscoverySearch/SearchRun-Ausführung.
|
||
|
||
## 11.3 Run Diff
|
||
|
||
```text
|
||
NEW
|
||
CHANGED
|
||
UNCHANGED
|
||
MISSING
|
||
```
|
||
|
||
## 11.4 Product Lifecycle
|
||
|
||
```text
|
||
ACTIVE
|
||
DISAPPEARED
|
||
ARCHIVED
|
||
```
|
||
|
||
## 11.5 Identity / Matching
|
||
|
||
```text
|
||
MATCHED
|
||
MATCH_UNCERTAIN
|
||
```
|
||
|
||
Diese Status dürfen in DB, API und UI nicht zu einem gemeinsamen Statusfeld vermischt werden.
|
||
|
||
---
|
||
|
||
# 12. Diff- und Lifecycle-Regeln
|
||
|
||
Nur vollständige erfolgreiche Full Runs dürfen fehlende Produkte ableiten.
|
||
|
||
```text
|
||
SUCCESS Full Run:
|
||
- NEW
|
||
- CHANGED
|
||
- UNCHANGED
|
||
- MISSING
|
||
```
|
||
|
||
`PARTIAL` darf **keine** MISSING-/DISAPPEARED-Transition auslösen.
|
||
|
||
Lifecycle:
|
||
|
||
```text
|
||
1 vollständiger Run fehlend -> MISSING im Run-Diff
|
||
3 aufeinanderfolgende vollständige Runs fehlend -> Product Lifecycle DISAPPEARED
|
||
```
|
||
|
||
Wiederauftauchen reaktiviert bestehende SourceProductReference, sofern Identity ausreichend sicher ist.
|
||
|
||
---
|
||
|
||
# 13. Candidate Summary DTO
|
||
|
||
Listen und Shortlist müssen genügend Daten liefern, damit das Frontend nicht für jede Zeile Einzelrequests benötigt.
|
||
|
||
Mindestens:
|
||
|
||
```text
|
||
candidate_id
|
||
source_product_reference_id
|
||
title
|
||
manufacturer nullable
|
||
model nullable
|
||
source_url
|
||
current_best_price nullable
|
||
currency nullable
|
||
current_dynamic_attributes
|
||
product_score nullable
|
||
product_eligibility nullable
|
||
ranking_status
|
||
shortlist_status
|
||
current_diff_status
|
||
product_lifecycle_status
|
||
match_status
|
||
first_seen_at
|
||
last_seen_at
|
||
```
|
||
|
||
`current_dynamic_attributes` ist metadata-driven und keine feste Notebook-Struktur.
|
||
|
||
---
|
||
|
||
# 14. Candidate Detail DTO
|
||
|
||
Erforderlicher Endpunkt:
|
||
|
||
```text
|
||
GET /api/v1/buying-projects/{project_id}/candidates/{candidate_id}
|
||
```
|
||
|
||
Mindestens:
|
||
|
||
```text
|
||
Candidate Summary
|
||
+
|
||
alle aktuellen normalisierten Attribute
|
||
+
|
||
Source-Metadaten
|
||
+
|
||
aktuelle Observation
|
||
+
|
||
Ranking-/Eligibility-Daten, soweit vorhanden
|
||
```
|
||
|
||
Das Frontend darf keine Gründe/Empfehlungen behaupten, die nicht tatsächlich persistiert sind.
|
||
|
||
---
|
||
|
||
# 15. Observation History
|
||
|
||
Erforderlicher Endpunkt:
|
||
|
||
```text
|
||
GET /api/v1/buying-projects/{project_id}/candidates/{candidate_id}/observations
|
||
```
|
||
|
||
Mindestens:
|
||
|
||
```text
|
||
observed_at
|
||
best_price
|
||
currency
|
||
availability nullable
|
||
seller_count nullable
|
||
dynamic_attributes
|
||
search_run_id
|
||
```
|
||
|
||
Diese Historie ermöglicht:
|
||
|
||
- Preisentwicklung
|
||
- Attributänderungen
|
||
- Last Seen
|
||
- Verlauf über SearchRuns
|
||
|
||
Kein HTML-Archiv.
|
||
|
||
---
|
||
|
||
# 16. Project Summary DTO
|
||
|
||
Die Projektliste soll nicht N+1-Requests erzeugen.
|
||
|
||
Erforderlich:
|
||
|
||
```text
|
||
GET /api/v1/buying-projects
|
||
```
|
||
|
||
Pro Projekt mindestens:
|
||
|
||
```text
|
||
id
|
||
name
|
||
product_category
|
||
status
|
||
last_successful_run_at nullable
|
||
next_run_at nullable
|
||
discovery_status nullable
|
||
candidate_count
|
||
shortlist_count
|
||
new_count
|
||
changed_count
|
||
missing_count
|
||
current_search_result_count nullable
|
||
```
|
||
|
||
---
|
||
|
||
# 17. Projekt-Wizard
|
||
|
||
Route:
|
||
|
||
```text
|
||
/projects/new
|
||
```
|
||
|
||
## Schritt 1 – Basis
|
||
|
||
```text
|
||
Projektname
|
||
Produktkategorie
|
||
Markt
|
||
Währung
|
||
Budget Ziel optional
|
||
Budget Maximum optional
|
||
Shortlist-Größe
|
||
Suchintervall
|
||
optional BuyingTemplate
|
||
```
|
||
|
||
## Schritt 2 – Kriterien laden
|
||
|
||
Nach Kategorieauswahl:
|
||
|
||
```text
|
||
GET available-criteria
|
||
```
|
||
|
||
Die UI zeigt die Source-Kriterien als verständliche Liste.
|
||
|
||
Beispiel Notebooks:
|
||
|
||
```text
|
||
[ ] Hersteller
|
||
[ ] Arbeitsspeicher
|
||
[ ] SSD
|
||
[ ] Gewicht
|
||
[ ] Displaygröße
|
||
[ ] CPU
|
||
[ ] Grafikkarte
|
||
...
|
||
```
|
||
|
||
## Schritt 3 – Parameter setzen
|
||
|
||
Nach Aktivierung eines Kriteriums:
|
||
|
||
```text
|
||
Arbeitsspeicher
|
||
Operator: mindestens
|
||
Wert: 24 GB
|
||
```
|
||
|
||
Control-Typen:
|
||
|
||
```text
|
||
BOOLEAN
|
||
ENUM
|
||
MULTI_ENUM
|
||
NUMERIC_RANGE
|
||
NUMERIC_THRESHOLD
|
||
TEXT
|
||
```
|
||
|
||
Das UI rendert dynamisch.
|
||
|
||
Keine hartcodierten Notebook-Felder.
|
||
|
||
## Schritt 4 – Projekt speichern
|
||
|
||
Erst jetzt wird das BuyingProject angelegt und die ProjectCriteria werden gespeichert.
|
||
|
||
---
|
||
|
||
# 18. Kriterienänderung im bestehenden Projekt
|
||
|
||
Route:
|
||
|
||
```text
|
||
/projects/:projectId/criteria
|
||
```
|
||
|
||
Ändert der Nutzer relevante ProjectCriteria:
|
||
|
||
```text
|
||
criteria_version++
|
||
DiscoverySearch.status = OUT_OF_SYNC
|
||
```
|
||
|
||
Das Frontend zeigt:
|
||
|
||
> Suchparameter wurden geändert. Die externe Suche muss aktualisiert werden.
|
||
|
||
Aktion:
|
||
|
||
```text
|
||
Suche aktualisieren
|
||
```
|
||
|
||
Backend:
|
||
|
||
```text
|
||
generate-query
|
||
→ VERIFIED Mappings verwenden
|
||
→ neue URL speichern
|
||
→ optional SearchRun starten
|
||
```
|
||
|
||
---
|
||
|
||
# 19. Hauptscreens
|
||
|
||
## 19.1 Projektliste
|
||
|
||
```text
|
||
/projects
|
||
```
|
||
|
||
Anzeige:
|
||
|
||
- Name
|
||
- Kategorie
|
||
- Project Lifecycle
|
||
- letzter erfolgreicher Run
|
||
- Discovery-Status
|
||
- Kandidatenzahl
|
||
- Shortlistzahl
|
||
- NEW / CHANGED Counts
|
||
- nächste Suche
|
||
|
||
## 19.2 Projektdetail
|
||
|
||
```text
|
||
/projects/:projectId
|
||
```
|
||
|
||
Bereiche:
|
||
|
||
```text
|
||
Übersicht
|
||
Kandidaten
|
||
Shortlist
|
||
Kriterien
|
||
Historie
|
||
```
|
||
|
||
## 19.3 Kandidaten
|
||
|
||
```text
|
||
/projects/:projectId/candidates
|
||
```
|
||
|
||
Desktop:
|
||
|
||
- Tabelle / kompakte Liste
|
||
|
||
Mobile:
|
||
|
||
- Cards / List Items
|
||
|
||
## 19.4 Kandidatendetail
|
||
|
||
```text
|
||
/projects/:projectId/candidates/:candidateId
|
||
```
|
||
|
||
Zeigt nur tatsächlich vorhandene Daten:
|
||
|
||
- Titel / Hersteller / Modell
|
||
- aktueller Preis
|
||
- dynamische Attribute
|
||
- Eligibility / ProductScore, soweit vorhanden
|
||
- Ranking Status
|
||
- Diff Status
|
||
- Product Lifecycle
|
||
- Match Status
|
||
- First Seen / Last Seen
|
||
- Observation History
|
||
|
||
Nicht anzeigen, solange Backend es nicht erzeugt:
|
||
|
||
- Deep-Enrichment-Ergebnisse
|
||
- Review-Zusammenfassungen
|
||
- finale Kaufentscheidung
|
||
- nicht persistierte Begründungen
|
||
|
||
## 19.5 Shortlist
|
||
|
||
```text
|
||
/projects/:projectId/shortlist
|
||
```
|
||
|
||
Zeigt Top-N, falls Ranking konfiguriert.
|
||
|
||
Ohne Ranking-Konfiguration:
|
||
|
||
```text
|
||
Ranking ist noch nicht konfiguriert.
|
||
```
|
||
|
||
## 19.6 Historie
|
||
|
||
```text
|
||
/projects/:projectId/history
|
||
```
|
||
|
||
SearchRuns mit:
|
||
|
||
```text
|
||
Zeitpunkt
|
||
Run Status
|
||
Trefferzahl
|
||
Page Count
|
||
NEW
|
||
CHANGED
|
||
MISSING
|
||
Fehler / BLOCKED / TOO_BROAD
|
||
```
|
||
|
||
---
|
||
|
||
# 20. Admin-Bereich
|
||
|
||
Routen:
|
||
|
||
```text
|
||
/admin/sources
|
||
/admin/sources/:source/categories
|
||
/admin/sources/:source/categories/:category
|
||
```
|
||
|
||
Funktionen:
|
||
|
||
- Kategorien sehen
|
||
- Taxonomie laden/neu laden
|
||
- SourceFilterDefinitions sehen
|
||
- Optionen / Ranges sehen
|
||
- CriterionDefinitions sehen
|
||
- SearchFilter-Mapping sehen
|
||
- SourceAttributeMappings sehen
|
||
- Mapping-Status ändern
|
||
- kleine Mapping-Korrekturen durchführen
|
||
- BROKEN / DISABLED erkennen
|
||
|
||
Technische IDs sind nur hier sichtbar.
|
||
|
||
Das Frontend generiert keine Source-URL-Encodings selbst.
|
||
|
||
---
|
||
|
||
# 21. Frontend-Technologie
|
||
|
||
Verbindlich:
|
||
|
||
- React
|
||
- TypeScript
|
||
- Vite
|
||
- PWA
|
||
- TanStack Query
|
||
- React Router oder vergleichbare schlanke Lösung
|
||
|
||
Nicht erforderlich:
|
||
|
||
- Next.js
|
||
- SSR
|
||
- SEO
|
||
|
||
Begründung:
|
||
|
||
Die Anwendung ist eine private/interne App und benötigt keine suchmaschinenoptimierte öffentliche Seitenauslieferung.
|
||
|
||
---
|
||
|
||
# 22. Responsive Architektur
|
||
|
||
Von Anfang an zwei bewusste Hauptlayouts.
|
||
|
||
## Desktop
|
||
|
||
```text
|
||
Sidebar + Hauptinhalt + optional Detailbereich
|
||
```
|
||
|
||
## Mobile
|
||
|
||
```text
|
||
Bottom Navigation / kompakte Navigation
|
||
+ Vollbild-Detailseiten
|
||
+ projektinterne Tabs
|
||
```
|
||
|
||
Keine bloße Verkleinerung des Desktop-Layouts.
|
||
|
||
---
|
||
|
||
# 23. Mitai-Bezug
|
||
|
||
Wenn der Mitai-Quellcode dem Coding-Agenten im Repository oder über einen konkret angegebenen Pfad zugänglich ist, sollen passende Muster wiederverwendet werden:
|
||
|
||
- PWA-Shell
|
||
- Responsive Breakpoints
|
||
- Navigation
|
||
- Layout
|
||
- ggf. Basiskomponenten
|
||
|
||
Ohne zugänglichen Pfad darf der Agent keine Annahmen über konkrete Mitai-Komponenten treffen.
|
||
|
||
Dann nur dieselben Architekturprinzipien umsetzen.
|
||
|
||
---
|
||
|
||
# 24. CORS
|
||
|
||
Backend muss den Frontend-Origin konfigurierbar zulassen.
|
||
|
||
Keine harte Produktions-URL im Code.
|
||
|
||
Beispiel:
|
||
|
||
```text
|
||
CORS_ALLOWED_ORIGINS
|
||
```
|
||
|
||
Lokale Entwicklung:
|
||
|
||
```text
|
||
http://localhost:<frontend-port>
|
||
```
|
||
|
||
Produktive Origins über Environment.
|
||
|
||
---
|
||
|
||
# 25. Docker Compose
|
||
|
||
Der nutzbare MVP enthält mindestens:
|
||
|
||
```text
|
||
api
|
||
postgres
|
||
frontend
|
||
```
|
||
|
||
Das Frontend muss über Compose startbar sein.
|
||
|
||
Development und Production Build dürfen unterschiedliche Docker Targets verwenden.
|
||
|
||
Root-Compose bleibt zentrale Startstelle.
|
||
|
||
---
|
||
|
||
# 26. CI
|
||
|
||
CI muss mindestens enthalten:
|
||
|
||
Backend:
|
||
|
||
- Unit Tests
|
||
- Integration Tests
|
||
- API E2E
|
||
|
||
Frontend:
|
||
|
||
- TypeScript typecheck
|
||
- lint
|
||
- unit/component tests
|
||
- production build
|
||
|
||
E2E:
|
||
|
||
- vollständiger Notebook-Pilot mit Fixture/Mock-Source
|
||
- Desktop viewport
|
||
- Mobile viewport
|
||
|
||
Live-Geizhals-Abfragen gehören nicht in CI.
|
||
|
||
---
|
||
|
||
# 27. PWA
|
||
|
||
Mindestens:
|
||
|
||
- Manifest
|
||
- installierbare App
|
||
- App Icons
|
||
- Responsive App Shell
|
||
- Offline-Fallback
|
||
|
||
Keine komplexe Offline-Synchronisation im MVP.
|
||
|
||
---
|
||
|
||
# 28. Loading / Empty / Error States
|
||
|
||
Jeder wesentliche Screen braucht:
|
||
|
||
```text
|
||
Loading
|
||
Empty
|
||
Error
|
||
Retry
|
||
```
|
||
|
||
Beispiele:
|
||
|
||
- Noch keine Projekte vorhanden.
|
||
- Noch keine Kandidaten gefunden.
|
||
- Noch kein SearchRun ausgeführt.
|
||
- Taxonomie wurde noch nicht geladen.
|
||
- Suche ist OUT_OF_SYNC.
|
||
- Suche wurde BLOCKED.
|
||
- Ranking ist nicht konfiguriert.
|
||
|
||
---
|
||
|
||
# 29. API-Verträge – Mindestumfang
|
||
|
||
## Projekte
|
||
|
||
```text
|
||
GET /api/v1/buying-projects
|
||
POST /api/v1/buying-projects
|
||
GET /api/v1/buying-projects/{id}
|
||
PATCH /api/v1/buying-projects/{id}
|
||
```
|
||
|
||
## Kriterien
|
||
|
||
```text
|
||
GET /api/v1/buying-projects/{id}/criteria
|
||
PUT /api/v1/buying-projects/{id}/criteria
|
||
```
|
||
|
||
## Source / Kategorien
|
||
|
||
```text
|
||
GET /api/v1/sources
|
||
GET /api/v1/sources/{source}/categories
|
||
POST /api/v1/sources/{source}/categories/{category}/discover-taxonomy
|
||
GET /api/v1/sources/{source}/categories/{category}/available-criteria
|
||
```
|
||
|
||
## Admin Mapping
|
||
|
||
```text
|
||
GET /api/v1/sources/{source}/categories/{category}/filters
|
||
GET /api/v1/criterion-mappings
|
||
POST /api/v1/criterion-mappings
|
||
PATCH /api/v1/criterion-mappings/{id}
|
||
GET /api/v1/source-attribute-mappings
|
||
POST /api/v1/source-attribute-mappings
|
||
PATCH /api/v1/source-attribute-mappings/{id}
|
||
```
|
||
|
||
## Discovery Search
|
||
|
||
```text
|
||
GET /api/v1/buying-projects/{id}/discovery-searches
|
||
POST /api/v1/buying-projects/{id}/discovery-searches
|
||
POST /api/v1/discovery-searches/{id}/generate-query
|
||
POST /api/v1/discovery-searches/{id}/run
|
||
```
|
||
|
||
## SearchRuns
|
||
|
||
```text
|
||
GET /api/v1/discovery-searches/{id}/runs
|
||
GET /api/v1/search-runs/{id}
|
||
```
|
||
|
||
## Candidates
|
||
|
||
```text
|
||
GET /api/v1/buying-projects/{id}/candidates
|
||
GET /api/v1/buying-projects/{id}/candidates/{candidateId}
|
||
GET /api/v1/buying-projects/{id}/candidates/{candidateId}/observations
|
||
GET /api/v1/buying-projects/{id}/shortlist
|
||
```
|
||
|
||
---
|
||
|
||
# 30. Nutzerfreundlichkeit
|
||
|
||
Die Standardoberfläche zeigt keine Begriffe wie:
|
||
|
||
```text
|
||
CriterionDefinition
|
||
SourceFilterDefinition
|
||
mapping_version
|
||
source_filter_id
|
||
normalized_spec_fingerprint
|
||
```
|
||
|
||
Stattdessen:
|
||
|
||
```text
|
||
Arbeitsspeicher
|
||
mindestens
|
||
24 GB
|
||
```
|
||
|
||
Technische Details gehören in den Admin-Bereich.
|
||
|
||
---
|
||
|
||
# 31. KI-Erweiterung – bewusst vorbereitet, nicht implementiert
|
||
|
||
Später soll KI den heute manuellen Kriterien-Auswahlschritt übernehmen können.
|
||
|
||
Ziel:
|
||
|
||
```text
|
||
Nutzer beschreibt Wunsch in natürlicher Sprache
|
||
↓
|
||
KI erhält verfügbare Source-Kriterien
|
||
↓
|
||
KI schlägt konkrete Filterparameter vor
|
||
↓
|
||
Nutzer bestätigt / korrigiert
|
||
↓
|
||
ProjectCriteria werden gespeichert
|
||
```
|
||
|
||
Wichtig:
|
||
|
||
Die KI soll Source-Kriterien möglichst aus dem tatsächlich verfügbaren Katalog auswählen.
|
||
|
||
INTERNAL-Kriterien dürfen nur vorgeschlagen werden, wenn sie im System bekannt sind und eine Datenquelle bzw. Bewertungsstrategie existiert.
|
||
|
||
Keine KI-Implementierung in v0.2.
|
||
|
||
---
|
||
|
||
# 32. Tests
|
||
|
||
## Frontend Unit / Component
|
||
|
||
- dynamischer Criteria Renderer pro Filtertyp
|
||
- Projekt-Wizard
|
||
- Mapping-/Statusdarstellung
|
||
- Candidate List
|
||
- Candidate Detail
|
||
- Mobile Navigation
|
||
- Desktop Navigation
|
||
- Loading / Empty / Error States
|
||
|
||
## API Integration
|
||
|
||
- Kategorie-Katalog laden
|
||
- available-criteria vor Projektanlage laden
|
||
- Projekt ohne Profil anlegen
|
||
- Projekt optional aus Template anlegen
|
||
- Criteria speichern
|
||
- Search generieren
|
||
- SearchRun starten
|
||
- Candidate Summary laden
|
||
- Candidate Detail laden
|
||
- Observation History laden
|
||
- Shortlist laden
|
||
|
||
## E2E Notebook-Pilot
|
||
|
||
```text
|
||
App öffnen
|
||
→ neues Projekt
|
||
→ Notebooks wählen
|
||
→ Geizhals-Kriterien laden
|
||
→ RAM >= 24 GB auswählen
|
||
→ Preismaximum setzen
|
||
→ Projekt speichern
|
||
→ Query generieren
|
||
→ SearchRun ausführen
|
||
→ Kandidaten anzeigen
|
||
→ Kandidat öffnen
|
||
→ dynamische Attribute sehen
|
||
→ Preis / Observation History sehen
|
||
→ Kriterien ändern
|
||
→ OUT_OF_SYNC sehen
|
||
→ Query neu generieren
|
||
```
|
||
|
||
Wenn optional ein Ranking-Template verwendet wird:
|
||
|
||
```text
|
||
→ ProductScore sichtbar
|
||
→ Shortlist sichtbar
|
||
```
|
||
|
||
## Responsive E2E
|
||
|
||
Mindestens:
|
||
|
||
- Desktop Viewport
|
||
- Mobile Viewport
|
||
|
||
---
|
||
|
||
# 33. Nicht Bestandteil dieses Slices
|
||
|
||
- Auth / Login
|
||
- RBAC
|
||
- Einladungen
|
||
- Multi-User UI
|
||
- Keepa
|
||
- Idealo
|
||
- LLM-Automation
|
||
- Deep Enrichment
|
||
- finale Decision Engine
|
||
- Kaufautomatisierung
|
||
- Warenkorb
|
||
- komplexe Benachrichtigungen
|
||
|
||
Die Architektur darf diese Erweiterungen nicht verbauen.
|
||
|
||
---
|
||
|
||
# 34. Definition of Done
|
||
|
||
## Architektur
|
||
|
||
- [ ] Keine separate Canonical-Criteria-Schicht.
|
||
- [ ] Source-Kriterien besitzen stabile interne CriterionDefinition-IDs.
|
||
- [ ] SearchFilter und Ergebnisattribute können auf dieselbe CriterionDefinition-ID gemappt werden.
|
||
- [ ] INTERNAL-Kriterien sind möglich.
|
||
- [ ] BuyingProject ist ohne ProductProfile anlegbar.
|
||
- [ ] ProductProfile kann optional als Vorlage dienen.
|
||
- [ ] DiscoverySearch-Persistenz bleibt 1:n-fähig.
|
||
- [ ] Statuswelten sind getrennt.
|
||
|
||
## API
|
||
|
||
- [ ] Source-Kategorie-Katalog existiert.
|
||
- [ ] available-criteria funktioniert vor Projektanlage.
|
||
- [ ] Candidate Summary DTO enthält Preis, Attribute, Diff, Lifecycle, last_seen und Ranking-Felder.
|
||
- [ ] Candidate Detail existiert.
|
||
- [ ] Observation History existiert.
|
||
- [ ] Project Summary DTO enthält Aggregate.
|
||
- [ ] CORS ist konfigurierbar.
|
||
|
||
## Frontend
|
||
|
||
- [ ] React + TypeScript + Vite.
|
||
- [ ] PWA installierbar.
|
||
- [ ] Desktop-Layout.
|
||
- [ ] Mobile-Layout.
|
||
- [ ] Projektliste.
|
||
- [ ] Projekt-Wizard.
|
||
- [ ] Kriterien dynamisch aus Source-Taxonomie.
|
||
- [ ] Keine notebook-spezifisch hartcodierten Criteria Controls.
|
||
- [ ] Projekt-Detail.
|
||
- [ ] Kandidatenliste.
|
||
- [ ] Kandidatendetail.
|
||
- [ ] Observation History.
|
||
- [ ] Shortlist, wenn Ranking verfügbar.
|
||
- [ ] Admin-Bereich für Taxonomie/Mappings.
|
||
- [ ] OUT_OF_SYNC sichtbar und korrigierbar.
|
||
- [ ] Loading / Empty / Error States.
|
||
|
||
## Integration
|
||
|
||
- [ ] Frontend in Docker Compose.
|
||
- [ ] Frontend Build/Tests in CI.
|
||
- [ ] Backend Tests grün.
|
||
- [ ] Frontend Tests grün.
|
||
- [ ] Desktop E2E grün.
|
||
- [ ] Mobile E2E grün.
|
||
- [ ] Notebook-Pilot über die UI erfolgreich.
|
||
|
||
---
|
||
|
||
# 35. Arbeitsauftrag an den Coding-Agenten
|
||
|
||
Diese Datei ersetzt `buying-agent-frontend-mvp-spec-v0.1.md` vollständig.
|
||
|
||
Bitte **noch nicht implementieren**.
|
||
|
||
Führe zunächst denselben Review-Prozess durch wie bei der v0.1:
|
||
|
||
1. Prüfe die aktuelle Repository-Implementierung gegen:
|
||
- `buying-agent-v0.1-spec-v1.1.md`
|
||
- `buying-agent-architecture-addendum-v1.md`
|
||
- `buying-agent-source-discovery-spec-v0.1.md`
|
||
- `buying-agent-frontend-mvp-spec-v0.2.md`
|
||
|
||
2. Prüfe insbesondere, ob die in deinem vorherigen Frontend-MVP-Review identifizierten Blocker F1–F6 und die weiteren Lücken mit v0.2 vollständig geschlossen sind.
|
||
|
||
3. Berichte ausschließlich:
|
||
- verbleibende echte fachliche Widersprüche,
|
||
- noch fehlende Verträge,
|
||
- technisch riskante Annahmen,
|
||
- notwendige Backend-Änderungen,
|
||
- notwendige Frontend-Änderungen.
|
||
|
||
4. Keine neue Fachlogik erfinden, um Lücken still zu schließen.
|
||
|
||
5. Wenn keine blockierenden Punkte mehr bestehen, erstelle einen aktualisierten Implementierungsplan für einen **vertikalen End-to-End-MVP**, sodass jeder Schritt über das Frontend prüfbar wird.
|
||
|
||
6. Implementierung erst nach ausdrücklicher Freigabe dieses Reviews.
|