1709 lines
31 KiB
Markdown
1709 lines
31 KiB
Markdown
# Buying Agent – Frontend MVP Specification v0.3
|
||
|
||
**Status:** Review Candidate – vor Implementierung erneut durch den Coding-Agenten zu prüfen
|
||
**Spezifikationsversion:** 0.3
|
||
**Stand:** 2026-10-04
|
||
|
||
**Ersetzt vollständig:** `buying-agent-frontend-mvp-spec-v0.2.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.3 Vorrang.
|
||
Sie präzisiert außerdem die für den Frontend-MVP notwendigen Backend-Verträge.
|
||
|
||
---
|
||
|
||
# 1. Zielbild
|
||
|
||
Der Buying Agent soll als **nutzbare PWA** einen vollständigen vertikalen Nutzerfluss abbilden.
|
||
|
||
Der Nutzer soll ohne technische Kenntnisse:
|
||
|
||
```text
|
||
BuyingProject anlegen
|
||
↓
|
||
Produktkategorie auswählen
|
||
↓
|
||
verfügbare Quellen für diese Kategorie bestimmen
|
||
↓
|
||
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
|
||
- search_run_id
|
||
```
|
||
|
||
## 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
|
||
|
||
## 3.1 Interner Katalog
|
||
|
||
Das BuyingProject referenziert eine interne `ProductCategory`.
|
||
|
||
Beispiel:
|
||
|
||
```text
|
||
ProductCategory
|
||
id = notebook
|
||
name = Notebooks
|
||
status = ACTIVE
|
||
```
|
||
|
||
Erforderlicher Endpunkt:
|
||
|
||
```text
|
||
GET /api/v1/product-categories
|
||
```
|
||
|
||
Response mindestens:
|
||
|
||
```text
|
||
id
|
||
name
|
||
status
|
||
```
|
||
|
||
Der initiale Pilot enthält mindestens:
|
||
|
||
```text
|
||
notebook
|
||
```
|
||
|
||
## 3.2 Source-Zuordnung
|
||
|
||
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
|
||
target_budget nullable
|
||
shortlist_size
|
||
status
|
||
template_id nullable
|
||
template_version nullable
|
||
criteria_version
|
||
created_at
|
||
updated_at
|
||
archived_at nullable
|
||
```
|
||
|
||
Status:
|
||
|
||
```text
|
||
ACTIVE
|
||
PURCHASED
|
||
ARCHIVED
|
||
```
|
||
|
||
Default:
|
||
|
||
```text
|
||
shortlist_size = 5
|
||
criteria_version = 1
|
||
```
|
||
|
||
## 4.1 Kein doppelter Suchpreis
|
||
|
||
Ein extern wirksames Preismaximum wird **nicht zusätzlich als BuyingProject-Feld** gehalten.
|
||
|
||
Wenn die Source einen Preisfilter unterstützt, wird das maximale Suchbudget als normales ProjectCriterion modelliert.
|
||
|
||
`target_budget` bleibt optional als spätere Ranking-/Decision-Information.
|
||
|
||
Damit existieren nicht zwei konkurrierende Wahrheiten für denselben externen Preisfilter.
|
||
|
||
---
|
||
|
||
# 5. Rolle von ProductProfile / BuyingTemplate
|
||
|
||
Das bisherige `ProductProfile` ist für neue BuyingProjects **nicht verpflichtend**.
|
||
|
||
Fachlich wird es als optionale Vorlage verstanden.
|
||
|
||
Zielbild:
|
||
|
||
```text
|
||
BuyingTemplate
|
||
"Mobiler Entwicklungsrechner"
|
||
↓ optional beim Projektstart
|
||
BuyingProject
|
||
```
|
||
|
||
Eine Vorlage kann z. B. liefern:
|
||
|
||
- vorgeschlagene Suchkriterien
|
||
- Ranking-Konfiguration
|
||
- Default-Zielbudget
|
||
- 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:
|
||
|
||
```text
|
||
template_id
|
||
template_version
|
||
```
|
||
|
||
Erforderlicher Endpunkt:
|
||
|
||
```text
|
||
GET /api/v1/buying-templates
|
||
```
|
||
|
||
Response mindestens:
|
||
|
||
```text
|
||
id
|
||
version
|
||
name
|
||
product_category_id
|
||
market
|
||
currency
|
||
description nullable
|
||
```
|
||
|
||
Die bestehende ProductProfile-Implementierung darf technisch weiterverwendet werden, solange sie nicht mehr als zwingende Voraussetzung für ein BuyingProject fungiert.
|
||
|
||
---
|
||
|
||
# 6. ProjectCriteria und Versionierung
|
||
|
||
## 6.1 Zweck
|
||
|
||
ProjectCriteria beschreiben die vom Nutzer gewählten Suchparameter eines BuyingProjects.
|
||
|
||
Sie referenzieren die dynamisch geladenen CriterionDefinitions.
|
||
|
||
## 6.2 Immutable Versions
|
||
|
||
ProjectCriteria werden nicht still überschrieben.
|
||
|
||
Ein fachlich relevanter Criteria-Wechsel erzeugt eine neue `criteria_version`.
|
||
|
||
Schema:
|
||
|
||
```text
|
||
ProjectCriterion
|
||
- id
|
||
- project_id
|
||
- criteria_version
|
||
- criterion_definition_id
|
||
- operator
|
||
- value
|
||
- enabled_for_discovery
|
||
- created_at
|
||
```
|
||
|
||
Für eine Project-/Criteria-Version gilt:
|
||
|
||
```text
|
||
(project_id, criteria_version, criterion_definition_id)
|
||
```
|
||
|
||
als fachlich eindeutige Kombination.
|
||
|
||
`BuyingProject.criteria_version` zeigt auf die aktuell aktive Version.
|
||
|
||
Änderung:
|
||
|
||
```text
|
||
aktuelle criteria_version = 3
|
||
↓
|
||
Nutzer ändert Kriterien
|
||
↓
|
||
neue immutable Kriterienmenge version 4
|
||
↓
|
||
BuyingProject.criteria_version = 4
|
||
```
|
||
|
||
SearchRuns und DiscoverySearches müssen die verwendete `criteria_version` speichern.
|
||
|
||
## 6.3 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.3 nicht Voraussetzung.
|
||
|
||
---
|
||
|
||
# 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 dokumentierte 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. Brücke CriterionDefinition -> bestehende Ranking-Engine
|
||
|
||
Die bestehende Ranking-/ProductProfile-Engine arbeitet weiterhin mit Attribut-Keys wie:
|
||
|
||
```text
|
||
ram_gb
|
||
storage_gb
|
||
weight_kg
|
||
```
|
||
|
||
Dafür erhält `CriterionDefinition` optional:
|
||
|
||
```text
|
||
scoring_attribute_key nullable
|
||
```
|
||
|
||
Beispiel:
|
||
|
||
```text
|
||
CriterionDefinition.id = <uuid>
|
||
label = "Arbeitsspeicher"
|
||
scoring_attribute_key = "ram_gb"
|
||
```
|
||
|
||
Wichtig:
|
||
|
||
- `scoring_attribute_key` ist **kein Canonical-Criterion-Layer**.
|
||
- Es ist ausschließlich ein technischer Adapter zur bestehenden Scoring-Engine.
|
||
- Source-Kriterium und interne UUID bleiben die primäre Persistenzidentität.
|
||
- Ist kein Ranking-Mapping vorhanden, bleibt `scoring_attribute_key = null`.
|
||
- Ein fehlender Mapping-Key darf keine Discovery verhindern.
|
||
|
||
So kann ein aus Geizhals beobachteter Wert:
|
||
|
||
```text
|
||
criterion_definition_id = <uuid>
|
||
normalized_value = 32
|
||
```
|
||
|
||
für einen Engine-Snapshot zusätzlich als:
|
||
|
||
```text
|
||
ram_gb = 32
|
||
```
|
||
|
||
bereitgestellt werden.
|
||
|
||
---
|
||
|
||
# 9. Source-Auswahl im Wizard
|
||
|
||
Der Nutzer soll die technische Source möglichst nicht auswählen müssen, solange nur eine geeignete Source existiert.
|
||
|
||
Nach Auswahl einer ProductCategory fragt das Frontend:
|
||
|
||
```text
|
||
GET /api/v1/product-categories/{product_category_id}/sources
|
||
```
|
||
|
||
Response mindestens:
|
||
|
||
```text
|
||
source
|
||
source_category_id
|
||
display_name
|
||
status
|
||
```
|
||
|
||
Regeln:
|
||
|
||
- genau eine aktive Source -> automatisch auswählen
|
||
- mehrere aktive Sources -> Source-Picker anzeigen
|
||
- keine aktive Source -> verständlicher Empty State
|
||
|
||
Der Nutzer muss die externe SourceCategory-ID wie `nb` nicht kennen.
|
||
|
||
---
|
||
|
||
# 10. Criterion-Katalog vor Projektanlage
|
||
|
||
Der Projekt-Wizard muss Kriterien laden können, bevor eine Project-ID existiert.
|
||
|
||
Erforderliche Endpunkte:
|
||
|
||
```text
|
||
GET /api/v1/product-categories
|
||
GET /api/v1/product-categories/{product_category_id}/sources
|
||
GET /api/v1/product-categories/{product_category_id}/available-criteria?source=geizhals
|
||
```
|
||
|
||
Backend löst intern:
|
||
|
||
```text
|
||
ProductCategory
|
||
+ Source
|
||
↓
|
||
SourceCategory
|
||
↓
|
||
CriterionDefinitions / SourceFilterDefinitions
|
||
```
|
||
|
||
auf.
|
||
|
||
`available-criteria` liefert mindestens:
|
||
|
||
```text
|
||
criterion_definition_id
|
||
label
|
||
description nullable
|
||
origin
|
||
source
|
||
product_category_id
|
||
filter_type
|
||
unit nullable
|
||
operators
|
||
options / range metadata
|
||
mapping_status
|
||
supports_discovery
|
||
scoring_attribute_key nullable
|
||
```
|
||
|
||
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.
|
||
|
||
---
|
||
|
||
# 11. Taxonomie-Lernen
|
||
|
||
Taxonomie wird on demand pro SourceCategory 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.
|
||
|
||
---
|
||
|
||
# 12. 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
|
||
```
|
||
|
||
## 12.1 Scheduling
|
||
|
||
Das Suchintervall gehört fachlich an die `DiscoverySearch`.
|
||
|
||
`BuyingProject` hält **kein zweites maßgebliches schedule_interval_minutes**.
|
||
|
||
Ein Template oder Projekt-Wizard darf einen Defaultwert vorgeben, dieser wird beim Anlegen der DiscoverySearch kopiert.
|
||
|
||
Ab dann ist:
|
||
|
||
```text
|
||
DiscoverySearch.schedule_interval_minutes
|
||
```
|
||
|
||
die maßgebliche Quelle.
|
||
|
||
Default:
|
||
|
||
```text
|
||
180 Minuten
|
||
```
|
||
|
||
---
|
||
|
||
# 13. Statuswelten strikt trennen
|
||
|
||
## 13.1 Project Lifecycle
|
||
|
||
```text
|
||
ACTIVE
|
||
PURCHASED
|
||
ARCHIVED
|
||
```
|
||
|
||
## 13.2 DiscoverySearch Status
|
||
|
||
```text
|
||
ACTIVE
|
||
OUT_OF_SYNC
|
||
BLOCKED
|
||
DISABLED
|
||
```
|
||
|
||
## 13.3 SearchRun Status
|
||
|
||
```text
|
||
RUNNING
|
||
SUCCESS
|
||
PARTIAL
|
||
FAILED
|
||
BLOCKED
|
||
TOO_BROAD
|
||
```
|
||
|
||
## 13.4 Run Diff
|
||
|
||
```text
|
||
NEW
|
||
CHANGED
|
||
UNCHANGED
|
||
MISSING
|
||
```
|
||
|
||
## 13.5 Product Lifecycle
|
||
|
||
```text
|
||
ACTIVE
|
||
DISAPPEARED
|
||
ARCHIVED
|
||
```
|
||
|
||
## 13.6 Identity / Matching
|
||
|
||
```text
|
||
MATCHED
|
||
MATCH_UNCERTAIN
|
||
```
|
||
|
||
Diese Status dürfen in DB, API und UI nicht zu einem gemeinsamen Statusfeld vermischt werden.
|
||
|
||
---
|
||
|
||
# 14. 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.
|
||
|
||
---
|
||
|
||
# 15. SearchRun Summary
|
||
|
||
SearchRun-Responses und History-Listen müssen Aggregatzähler liefern.
|
||
|
||
Mindestens:
|
||
|
||
```text
|
||
id
|
||
discovery_search_id
|
||
started_at
|
||
finished_at nullable
|
||
status
|
||
result_count
|
||
page_count
|
||
new_count
|
||
changed_count
|
||
unchanged_count
|
||
missing_count
|
||
error_code nullable
|
||
```
|
||
|
||
`disappeared_count` darf optional zusätzlich als Lifecycle-Aggregat geliefert werden, gehört aber nicht zum Run-Diff-Enum.
|
||
|
||
---
|
||
|
||
# 16. ProductObservation und Attribute
|
||
|
||
Eine Observation gehört mindestens zu:
|
||
|
||
```text
|
||
SourceProductReference
|
||
+
|
||
SearchRun
|
||
```
|
||
|
||
Schema konzeptionell:
|
||
|
||
```text
|
||
ProductObservation
|
||
- id
|
||
- source_product_reference_id
|
||
- search_run_id
|
||
- observed_at
|
||
- best_price
|
||
- currency
|
||
- availability nullable
|
||
- seller_count nullable
|
||
```
|
||
|
||
Dynamische Attribute:
|
||
|
||
```text
|
||
ProductAttributeObservation
|
||
- product_observation_id
|
||
- criterion_definition_id
|
||
- raw_name
|
||
- raw_value
|
||
- normalized_value
|
||
- unit nullable
|
||
```
|
||
|
||
Damit ist jede Beobachtung eindeutig einem Produkt und einem konkreten SearchRun zugeordnet.
|
||
|
||
---
|
||
|
||
# 17. 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.
|
||
|
||
---
|
||
|
||
# 18. 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.
|
||
|
||
---
|
||
|
||
# 19. Observation History
|
||
|
||
Erforderlicher Endpunkt:
|
||
|
||
```text
|
||
GET /api/v1/buying-projects/{project_id}/candidates/{candidate_id}/observations
|
||
```
|
||
|
||
Mindestens:
|
||
|
||
```text
|
||
observation_id
|
||
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.
|
||
|
||
---
|
||
|
||
# 20. 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
|
||
```
|
||
|
||
---
|
||
|
||
# 21. Projekt-Wizard
|
||
|
||
Route:
|
||
|
||
```text
|
||
/projects/new
|
||
```
|
||
|
||
## Schritt 1 – Basis
|
||
|
||
```text
|
||
Projektname
|
||
Produktkategorie
|
||
Markt
|
||
Währung
|
||
Zielbudget optional
|
||
Shortlist-Größe
|
||
optional BuyingTemplate
|
||
```
|
||
|
||
## Schritt 2 – Source
|
||
|
||
Frontend lädt:
|
||
|
||
```text
|
||
GET /product-categories/{id}/sources
|
||
```
|
||
|
||
Bei genau einer Source automatische Auswahl.
|
||
|
||
Bei mehreren Sources Auswahl durch Nutzer.
|
||
|
||
## Schritt 3 – Kriterien laden
|
||
|
||
Frontend lädt:
|
||
|
||
```text
|
||
GET /product-categories/{id}/available-criteria?source=...
|
||
```
|
||
|
||
Die UI zeigt Source-Kriterien als verständliche Liste.
|
||
|
||
Beispiel Notebooks:
|
||
|
||
```text
|
||
[ ] Hersteller
|
||
[ ] Arbeitsspeicher
|
||
[ ] SSD
|
||
[ ] Gewicht
|
||
[ ] Displaygröße
|
||
[ ] CPU
|
||
[ ] Grafikkarte
|
||
...
|
||
```
|
||
|
||
## Schritt 4 – 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 5 – Projekt speichern
|
||
|
||
Erst jetzt wird das BuyingProject angelegt und die ProjectCriteria-Version gespeichert.
|
||
|
||
Danach wird die initiale DiscoverySearch für die ausgewählte Source erzeugt.
|
||
|
||
---
|
||
|
||
# 22. Kriterienänderung im bestehenden Projekt
|
||
|
||
Route:
|
||
|
||
```text
|
||
/projects/:projectId/criteria
|
||
```
|
||
|
||
Ändert der Nutzer relevante ProjectCriteria:
|
||
|
||
```text
|
||
neue immutable criteria_version
|
||
BuyingProject.criteria_version = neue 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
|
||
```
|
||
|
||
---
|
||
|
||
# 23. PATCH BuyingProject
|
||
|
||
Erforderlicher Endpunkt:
|
||
|
||
```text
|
||
PATCH /api/v1/buying-projects/{id}
|
||
```
|
||
|
||
Im MVP explizit änderbar:
|
||
|
||
```text
|
||
name
|
||
target_budget
|
||
shortlist_size
|
||
status
|
||
```
|
||
|
||
Nicht über diesen PATCH ändern:
|
||
|
||
```text
|
||
product_category_id
|
||
market
|
||
currency
|
||
criteria
|
||
source
|
||
source_category
|
||
schedule_interval
|
||
```
|
||
|
||
Suchrelevante Änderungen laufen über die Criteria-/DiscoverySearch-Verträge.
|
||
|
||
Falls Kategorie/Markt/Währung später änderbar werden, benötigt dies einen expliziten Migrations-/Reinitialisierungsflow und ist nicht Teil des MVP.
|
||
|
||
---
|
||
|
||
# 24. Hauptscreens
|
||
|
||
## 24.1 Projektliste
|
||
|
||
```text
|
||
/projects
|
||
```
|
||
|
||
Anzeige:
|
||
|
||
- Name
|
||
- Kategorie
|
||
- Project Lifecycle
|
||
- letzter erfolgreicher Run
|
||
- Discovery-Status
|
||
- Kandidatenzahl
|
||
- Shortlistzahl
|
||
- NEW / CHANGED Counts
|
||
- nächste Suche
|
||
|
||
## 24.2 Projektdetail
|
||
|
||
```text
|
||
/projects/:projectId
|
||
```
|
||
|
||
Bereiche:
|
||
|
||
```text
|
||
Übersicht
|
||
Kandidaten
|
||
Shortlist
|
||
Kriterien
|
||
Historie
|
||
```
|
||
|
||
## 24.3 Kandidaten
|
||
|
||
```text
|
||
/projects/:projectId/candidates
|
||
```
|
||
|
||
Desktop:
|
||
|
||
- Tabelle / kompakte Liste
|
||
|
||
Mobile:
|
||
|
||
- Cards / List Items
|
||
|
||
## 24.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
|
||
|
||
## 24.5 Shortlist
|
||
|
||
```text
|
||
/projects/:projectId/shortlist
|
||
```
|
||
|
||
Zeigt Top-N, falls Ranking konfiguriert.
|
||
|
||
Ohne Ranking-Konfiguration:
|
||
|
||
```text
|
||
Ranking ist noch nicht konfiguriert.
|
||
```
|
||
|
||
## 24.6 Historie
|
||
|
||
```text
|
||
/projects/:projectId/history
|
||
```
|
||
|
||
SearchRuns mit:
|
||
|
||
```text
|
||
Zeitpunkt
|
||
Run Status
|
||
Trefferzahl
|
||
Page Count
|
||
NEW
|
||
CHANGED
|
||
UNCHANGED
|
||
MISSING
|
||
Fehler / BLOCKED / TOO_BROAD
|
||
```
|
||
|
||
---
|
||
|
||
# 25. 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
|
||
- scoring_attribute_key sehen/pflegen, soweit administrativ vorgesehen
|
||
- 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.
|
||
|
||
---
|
||
|
||
# 26. Frontend-Technologie
|
||
|
||
Verbindlich:
|
||
|
||
- React
|
||
- TypeScript
|
||
- Vite
|
||
- PWA
|
||
- TanStack Query
|
||
- React Router oder vergleichbare schlanke Lösung
|
||
- Playwright für E2E
|
||
|
||
Nicht erforderlich:
|
||
|
||
- Next.js
|
||
- SSR
|
||
- SEO
|
||
|
||
---
|
||
|
||
# 27. 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.
|
||
|
||
---
|
||
|
||
# 28. 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.
|
||
|
||
---
|
||
|
||
# 29. CORS
|
||
|
||
Backend muss den Frontend-Origin konfigurierbar zulassen.
|
||
|
||
Keine harte Produktions-URL im Code.
|
||
|
||
Beispiel:
|
||
|
||
```text
|
||
CORS_ALLOWED_ORIGINS
|
||
```
|
||
|
||
Lokale und produktive Origins über Environment.
|
||
|
||
---
|
||
|
||
# 30. Ports
|
||
|
||
Ports sind Deployment-Konfiguration und keine Fachlogik.
|
||
|
||
Sie werden über:
|
||
|
||
- Docker Compose
|
||
- `.env`
|
||
- `.env.example`
|
||
|
||
konfiguriert.
|
||
|
||
Keine fachliche Spec darf einen unveränderlichen Frontend-Port voraussetzen.
|
||
|
||
---
|
||
|
||
# 31. Docker Compose
|
||
|
||
Der nutzbare MVP enthält mindestens:
|
||
|
||
```text
|
||
api
|
||
postgres
|
||
frontend
|
||
```
|
||
|
||
Das Frontend muss über Root-Compose startbar sein.
|
||
|
||
Development und Production Build dürfen unterschiedliche Docker Targets verwenden.
|
||
|
||
---
|
||
|
||
# 32. CI
|
||
|
||
CI muss mindestens enthalten:
|
||
|
||
Backend:
|
||
|
||
- Unit Tests
|
||
- Integration Tests
|
||
- API E2E
|
||
|
||
Frontend:
|
||
|
||
- TypeScript typecheck
|
||
- lint
|
||
- unit/component tests
|
||
- production build
|
||
|
||
E2E:
|
||
|
||
- Playwright
|
||
- vollständiger Notebook-Pilot mit Fixture/Mock-Source
|
||
- Desktop viewport
|
||
- Mobile viewport
|
||
|
||
Live-Geizhals-Abfragen gehören nicht in CI.
|
||
|
||
---
|
||
|
||
# 33. PWA
|
||
|
||
Mindestens:
|
||
|
||
- Manifest
|
||
- installierbare App
|
||
- App Icons
|
||
- Responsive App Shell
|
||
- Offline-Fallback
|
||
|
||
Keine komplexe Offline-Synchronisation im MVP.
|
||
|
||
---
|
||
|
||
# 34. 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.
|
||
- Keine Source für diese Produktkategorie verfügbar.
|
||
- Suche ist OUT_OF_SYNC.
|
||
- Suche wurde BLOCKED.
|
||
- Ranking ist nicht konfiguriert.
|
||
|
||
---
|
||
|
||
# 35. API-Verträge – Mindestumfang
|
||
|
||
## Produktkategorien
|
||
|
||
```text
|
||
GET /api/v1/product-categories
|
||
GET /api/v1/product-categories/{id}/sources
|
||
GET /api/v1/product-categories/{id}/available-criteria?source=...
|
||
```
|
||
|
||
## Templates
|
||
|
||
```text
|
||
GET /api/v1/buying-templates
|
||
```
|
||
|
||
## 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
|
||
```
|
||
|
||
`PUT` erzeugt eine neue immutable criteria_version.
|
||
|
||
## Source / Taxonomie
|
||
|
||
```text
|
||
GET /api/v1/sources
|
||
GET /api/v1/sources/{source}/categories
|
||
POST /api/v1/sources/{source}/categories/{category}/discover-taxonomy
|
||
```
|
||
|
||
## 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
|
||
PATCH /api/v1/discovery-searches/{id}
|
||
```
|
||
|
||
`PATCH DiscoverySearch` darf im MVP mindestens ändern:
|
||
|
||
```text
|
||
schedule_interval_minutes
|
||
status ACTIVE/DISABLED
|
||
```
|
||
|
||
## 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
|
||
```
|
||
|
||
---
|
||
|
||
# 36. Nutzerfreundlichkeit
|
||
|
||
Die Standardoberfläche zeigt keine Begriffe wie:
|
||
|
||
```text
|
||
CriterionDefinition
|
||
SourceFilterDefinition
|
||
mapping_version
|
||
source_filter_id
|
||
normalized_spec_fingerprint
|
||
scoring_attribute_key
|
||
```
|
||
|
||
Stattdessen:
|
||
|
||
```text
|
||
Arbeitsspeicher
|
||
mindestens
|
||
24 GB
|
||
```
|
||
|
||
Technische Details gehören in den Admin-Bereich.
|
||
|
||
---
|
||
|
||
# 37. 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.3.
|
||
|
||
---
|
||
|
||
# 38. Tests
|
||
|
||
## Frontend Unit / Component
|
||
|
||
- dynamischer Criteria Renderer pro Filtertyp
|
||
- ProductCategory Picker
|
||
- automatische Source-Auswahl bei genau einer Source
|
||
- Source Picker bei mehreren Sources
|
||
- Projekt-Wizard
|
||
- Mapping-/Statusdarstellung
|
||
- Candidate List
|
||
- Candidate Detail
|
||
- Mobile Navigation
|
||
- Desktop Navigation
|
||
- Loading / Empty / Error States
|
||
|
||
## API Integration
|
||
|
||
- ProductCategory-Katalog laden
|
||
- Sources pro ProductCategory laden
|
||
- available-criteria vor Projektanlage laden
|
||
- Projekt ohne Profil anlegen
|
||
- Projekt optional aus Template anlegen
|
||
- Criteria versioniert speichern
|
||
- DiscoverySearch anlegen
|
||
- Suchintervall an DiscoverySearch ändern
|
||
- Search generieren
|
||
- SearchRun starten
|
||
- SearchRun Summary laden
|
||
- Candidate Summary laden
|
||
- Candidate Detail laden
|
||
- Observation History laden
|
||
- Shortlist laden
|
||
|
||
## E2E Notebook-Pilot
|
||
|
||
```text
|
||
App öffnen
|
||
→ neues Projekt
|
||
→ Notebooks wählen
|
||
→ verfügbare Source automatisch bestimmen
|
||
→ Geizhals-Kriterien laden
|
||
→ RAM >= 24 GB auswählen
|
||
→ Preismaximum als Source-Kriterium setzen
|
||
→ Projekt speichern
|
||
→ DiscoverySearch erzeugen
|
||
→ Query generieren
|
||
→ SearchRun ausführen
|
||
→ Kandidaten anzeigen
|
||
→ Kandidat öffnen
|
||
→ dynamische Attribute sehen
|
||
→ Preis / Observation History sehen
|
||
→ Kriterien ändern
|
||
→ neue criteria_version
|
||
→ OUT_OF_SYNC sehen
|
||
→ Query neu generieren
|
||
```
|
||
|
||
Wenn optional ein Ranking-Template verwendet wird:
|
||
|
||
```text
|
||
→ scoring_attribute_key Brücke verwenden
|
||
→ ProductScore sichtbar
|
||
→ Shortlist sichtbar
|
||
```
|
||
|
||
## Responsive E2E
|
||
|
||
Mindestens:
|
||
|
||
- Desktop Viewport
|
||
- Mobile Viewport
|
||
|
||
---
|
||
|
||
# 39. 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.
|
||
|
||
---
|
||
|
||
# 40. Definition of Done
|
||
|
||
## Architektur
|
||
|
||
- [ ] Keine separate Canonical-Criteria-Schicht.
|
||
- [ ] ProductCategory-Katalog existiert.
|
||
- [ ] Source-Zuordnung pro ProductCategory existiert.
|
||
- [ ] Source-Kriterien besitzen stabile interne CriterionDefinition-IDs.
|
||
- [ ] SearchFilter und Ergebnisattribute können auf dieselbe CriterionDefinition-ID gemappt werden.
|
||
- [ ] Optionales `scoring_attribute_key` verbindet Kriterien mit bestehender Ranking-Engine.
|
||
- [ ] INTERNAL-Kriterien sind möglich.
|
||
- [ ] BuyingProject ist ohne ProductProfile anlegbar.
|
||
- [ ] ProductProfile kann optional als Vorlage dienen.
|
||
- [ ] ProjectCriteria sind immutable versioniert.
|
||
- [ ] SearchRun und DiscoverySearch referenzieren criteria_version.
|
||
- [ ] DiscoverySearch-Persistenz bleibt 1:n-fähig.
|
||
- [ ] Scheduling liegt fachlich an DiscoverySearch.
|
||
- [ ] Statuswelten sind getrennt.
|
||
|
||
## API
|
||
|
||
- [ ] `GET /product-categories` existiert.
|
||
- [ ] Sources pro ProductCategory existieren.
|
||
- [ ] available-criteria funktioniert vor Projektanlage.
|
||
- [ ] BuyingTemplate-Liste existiert.
|
||
- [ ] Candidate Summary DTO enthält Preis, Attribute, Diff, Lifecycle, last_seen und Ranking-Felder.
|
||
- [ ] Candidate Detail existiert.
|
||
- [ ] Observation History existiert.
|
||
- [ ] SearchRun Summary enthält Diff-Aggregate.
|
||
- [ ] Project Summary DTO enthält Aggregate.
|
||
- [ ] PATCH-Felder sind explizit definiert.
|
||
- [ ] CORS ist konfigurierbar.
|
||
|
||
## Frontend
|
||
|
||
- [ ] React + TypeScript + Vite.
|
||
- [ ] PWA installierbar.
|
||
- [ ] Desktop-Layout.
|
||
- [ ] Mobile-Layout.
|
||
- [ ] Projektliste.
|
||
- [ ] Projekt-Wizard.
|
||
- [ ] ProductCategory Picker.
|
||
- [ ] Source wird automatisch gewählt, wenn nur eine verfügbar ist.
|
||
- [ ] 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.
|
||
- [ ] Ports über Environment/Compose konfigurierbar.
|
||
- [ ] Frontend Build/Tests in CI.
|
||
- [ ] Backend Tests grün.
|
||
- [ ] Frontend Tests grün.
|
||
- [ ] Playwright Desktop E2E grün.
|
||
- [ ] Playwright Mobile E2E grün.
|
||
- [ ] Notebook-Pilot über die UI erfolgreich.
|
||
|
||
---
|
||
|
||
# 41. Arbeitsauftrag an den Coding-Agenten
|
||
|
||
Diese Datei ersetzt `buying-agent-frontend-mvp-spec-v0.2.md` vollständig.
|
||
|
||
Bitte **noch nicht implementieren**.
|
||
|
||
Führe erneut denselben Review-Prozess durch wie bei v0.1 und v0.2.
|
||
|
||
Prüfe die aktuelle Repository-Implementierung gegen:
|
||
|
||
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`
|
||
4. `buying-agent-frontend-mvp-spec-v0.3.md`
|
||
|
||
Prüfe insbesondere explizit, ob:
|
||
|
||
- die bisherigen F1–F6 geschlossen sind,
|
||
- R1 ProductCategory-Katalog geschlossen ist,
|
||
- R2 Source-Auswahl vor Projektanlage geschlossen ist,
|
||
- R3 CriterionDefinition-UUID ↔ Scoring-Attribut-Key geschlossen ist,
|
||
- R4 ProjectCriteria-Versionierung geschlossen ist,
|
||
- die bisherigen kleineren Restlücken zu Template-API, PATCH-Semantik,
|
||
SearchRun-Zählern, Observation-Zuordnung, Scheduling, CORS, Ports,
|
||
Compose, CI und Teststack geschlossen sind.
|
||
|
||
Berichte ausschließlich:
|
||
|
||
- verbleibende echte fachliche Widersprüche,
|
||
- noch fehlende Verträge,
|
||
- technisch riskante Annahmen,
|
||
- notwendige Backend-Änderungen,
|
||
- notwendige Frontend-Änderungen.
|
||
|
||
Keine neue Fachlogik erfinden, um Lücken still zu schließen.
|
||
|
||
Wenn keine blockierenden Punkte mehr bestehen:
|
||
|
||
1. erstelle einen aktualisierten Implementierungsplan,
|
||
2. plane **vertikal** statt „Backend komplett, danach Frontend“,
|
||
3. jeder Slice muss unmittelbar über die UI testbar sein,
|
||
4. beginne die Implementierung erst nach ausdrücklicher Freigabe dieses Reviews.
|