removed documentation

This commit is contained in:
Ida Dittrich 2025-12-08 10:54:53 +01:00
parent a09506b7a7
commit ad14e272f3
56 changed files with 0 additions and 28293 deletions

View file

@ -1,418 +0,0 @@
# Datenmodell Architektur-Planungs-App
## Übersicht
Dieses Datenmodell bildet die Grundlage für eine Schweizer Architektur-Planungs-App zur Verwaltung von Bauprojekten, Parzellen, Dokumenten und regulatorischen Kontextinformationen.
## Wichtige Hinweise zum Datenmodell
**Objektmodell vs. Datenbank-Repräsentation:**
Dieses Dokument beschreibt ein **Objektmodell** für die Arbeit im Code. Es handelt sich **NICHT** um ein relationales Datenbankmodell mit Junction Tables.
- **Im Code-Modell**: Alle Beziehungen werden als Objektreferenzen oder Listen von Objekten dargestellt (z.B. `dokumente: list[Dokument]`, `parzellen: list[Parzelle]`).
- **Für die Datenbank-Serialisierung**: Bei der Persistierung können Junction Tables verwendet werden, um n:m-Beziehungen in der Datenbank abzubilden. Dies ist jedoch ein Implementierungsdetail der Datenbank-Schicht und gehört nicht zum Hauptmodell.
**Systemattribute:**
Alle Datenobjekte haben automatisch die folgenden Systemattribute:
- `_createdAt`: Float (Timestamp UTC)
- `_createdBy`: String (User-ID)
- `_modifiedAt`: Float (Timestamp UTC)
- `_modifiedBy`: String (User-ID)
**Timestamps:**
- Alle Timestamps sind im Float-Format UTC im Datenmodell gespeichert.
- Die Darstellung im UI erfolgt mit der lokalen Zeitzone des Benutzers.
## Datenfluss-Diagramm
```mermaid
---
title: Hauptflüsse - Architektur-Planungs-App
---
flowchart LR
subgraph Admin[Administrative Ebene]
Land[Land<br/>Schweiz]
Kanton[Kanton<br/>z.B. Zürich]
Gemeinde[Gemeinde<br/>z.B. Zürich Stadt]
Land --> Kanton
Kanton --> Gemeinde
end
subgraph Geo[Geografische Daten]
GeoPolylinie[GeoPolylinie<br/>Linie/Polygon]
GeoPunkt[GeoPunkt<br/>Koordinaten]
GeoPolylinie --> GeoPunkt
end
subgraph Core[Kern-Business-Logik]
Projekt[Projekt<br/>Bauprojekt]
Parzelle[Parzelle<br/>Grundstück mit<br/>Bauparametern]
Gemeinde --> Parzelle
Projekt --> Parzelle
Projekt --> GeoPolylinie
Parzelle --> GeoPolylinie
end
subgraph Support[Unterstützende Daten]
Dokument[Dokument<br/>Dateien & URLs]
Kontext[Kontext<br/>Zusatzinfos]
end
style Land fill:#50C878,stroke:#2D7A4A,stroke-width:2px,color:#fff
style Kanton fill:#50C878,stroke:#2D7A4A,stroke-width:2px,color:#fff
style Gemeinde fill:#50C878,stroke:#2D7A4A,stroke-width:2px,color:#fff
style Parzelle fill:#FF6B6B,stroke:#C92A2A,stroke-width:4px,color:#fff
style Projekt fill:#FF6B6B,stroke:#C92A2A,stroke-width:4px,color:#fff
style Dokument fill:#F5A623,stroke:#C17D11,stroke-width:2px,color:#fff
style GeoPolylinie fill:#F5A623,stroke:#C17D11,stroke-width:2px,color:#fff
style GeoPunkt fill:#F5A623,stroke:#C17D11,stroke-width:2px,color:#fff
style Kontext fill:#F5A623,stroke:#C17D11,stroke-width:2px,color:#fff
```
---
## Alle Datenobjekte als Tabellen
### Übersichtstabelle
| Objekt | Typ | Beschreibung | Hauptfelder |
|--------|-----|--------------|-------------|
| **Projekt** | Kernentität | Bauprojekt mit Status und Perimeter | id, label, statusProzess, perimeter, baulinie, parzellen |
| **Parzelle** | Hauptentität | Grundstück mit Bauparametern | id, label, plz, bauzone, AZ, BZ, perimeter, baulinie, laermschutzzone, hochwasserschutzzone, grundwasserschutzzone |
| **Dokument** | Unterstützend | Dateien und URLs mit Versionierung | id, label, dokumentTyp, quelle, mimeType, kategorienTags |
| **Kontext** | Unterstützend | Flexible Zusatzinformationen | id, thema, inhalt |
| **GeoPolylinie** | Hilfsobjekt | Geometrische Linie/Polygon | id, closed, punkte |
| **Land** | Admin | Nationale Ebene | id, label, abk |
| **Kanton** | Admin | Kantonale Ebene mit Baurecht | id, label, abk, Baureglement |
| **Gemeinde** | Admin | Gemeinde-Ebene mit BZO | id, label, plz, BZO |
| **GeoPunkt** | Hilfsobjekt | 3D-Koordinate | koordinatensystem, x, y, z, referenz |
| **GeoTag** | Enum | Geopunkt-Kategorien | - |
| **JaNein** | Enum | Drei-wertiger Status | "", "Ja", "Nein" |
| **StatusProzess** | Enum | Projektstatus | 7 Werte |
| **DokumentTyp** | Enum | Dokumenttyp | 6 Werte |
---
## Zentrale Entitäten
### 1. Projekt
**Das Kernobjekt, das ein Bauprojekt repräsentiert.**
| Feld | Datentyp | Pflicht | Beschreibung |
|------|----------|---------|--------------|
| `id` | UUID | ✓ | Eindeutiger Identifier |
| `label` | String | ✓ | Projektbezeichnung |
| `statusProzess` | Enum[StatusProzess] | - | Projektstatus: Eingang, Analyse, Studie, Planung, Baurechtsverfahren, Umsetzung, Archiv |
| `perimeter` | GeoPolylinie | - | Umhüllende aller Parzellen des Projektes |
| `baulinie` | GeoPolylinie | - | Baulinie des Projektes |
| `parzellen` | list[Parzelle] | - | Alle Parzellen des Projektes |
| `dokumente` | list[Dokument] | - | Projektspezifische Dokumente |
| `kontextInformationen` | list[Kontext] | - | Projektspezifische Kontextinfos |
---
### 2. Parzelle
**Repräsentiert ein Grundstück mit allen baurechtlichen Eigenschaften als ein einheitliches Objekt.**
#### Grunddaten
| Feld | Datentyp | Pflicht | Beschreibung |
|------|----------|---------|--------------|
| `id` | UUID | ✓ | Eindeutiger Identifier |
| `label` | String | ✓ | Parzellenbezeichnung |
| `parzellenAliasTags` | list[String] | - | Weitere Parzellennamen oder Flurnamen |
| `eigentuemerschaft` | String | - | Eigentümer der Parzelle |
| `strasseNr` | String | - | Straße und Hausnummer |
| `plz` | String | - | Postleitzahl der Parzelle (insbesondere bei Gemeinden mit mehreren PLZ) |
#### Geografischer Kontext
| Feld | Datentyp | Pflicht | Beschreibung |
|------|----------|---------|--------------|
| `perimeter` | GeoPolylinie | - | Parzellengrenze als geschlossene GeoPolylinie |
| `baulinie` | GeoPolylinie | - | Baulinie der Parzelle |
| `kontextGemeinde` | Gemeinde | - | Gemeinde der Parzelle |
#### Bebauungsparameter
| Feld | Datentyp | Pflicht | Beschreibung |
|------|----------|---------|--------------|
| `bauzone` | String | - | Bauzonenbezeichnung (z.B. W3, WG2, etc.) |
| `az` | Float | - | Ausnützungsziffer |
| `bz` | Float | - | Bebauungsziffer |
| `vollgeschossZahl` | Integer | - | Anzahl zulässiger Vollgeschosse |
| `anrechenbarDachgeschoss` | Float | - | Anrechenbarer Anteil Dachgeschoss (0.0 - 1.0) |
| `anrechenbarUntergeschoss` | Float | - | Anrechenbarer Anteil Untergeschoss (0.0 - 1.0) |
| `gebaeudehoeheMax` | Float | - | Maximale Gebäudehöhe in Metern |
#### Abstandsregelungen
| Feld | Datentyp | Pflicht | Beschreibung |
|------|----------|---------|--------------|
| `regelnGrenzabstand` | list[String] | - | Regelungen zum Grenzabstand |
| `regelnMehrlaengenzuschlag` | list[String] | - | Regelungen zum Mehrlängenzuschlag |
| `regelnMehrhoehenzuschlag` | list[String] | - | Regelungen zum Mehrhöhenzuschlag |
#### Eigenschaften (Ja/Nein)
| Feld | Datentyp | Pflicht | Beschreibung |
|------|----------|---------|--------------|
| `parzelleBebaut` | JaNein | - | Ist die Parzelle bebaut? ("", "Ja", "Nein") |
| `parzelleErschlossen` | JaNein | - | Ist die Parzelle erschlossen? ("", "Ja", "Nein") |
| `parzelleHanglage` | JaNein | - | Liegt die Parzelle in Hanglage? ("", "Ja", "Nein") |
#### Schutzzonen
| Feld | Datentyp | Pflicht | Beschreibung |
|------|----------|---------|--------------|
| `laermschutzzone` | String | - | Lärmschutzzone (z.B. "II") |
| `hochwasserschutzzone` | String | - | Hochwasserschutzzone (z.B. "tief") |
| `grundwasserschutzzone` | String | - | Grundwasserschutzzone |
#### Beziehungen
| Feld | Datentyp | Pflicht | Beschreibung |
|------|----------|---------|--------------|
| `parzellenNachbarschaft` | list[Parzelle] | - | Nachbarparzellen |
| `dokumente` | list[Dokument] | - | Parzellenspezifische Dokumente |
| `kontextInformationen` | list[Kontext] | - | Parzellenspezifische Kontextinfos |
---
### 3. Dokument
**Unterstützendes Datenobjekt zur Verwaltung von Dateien und URLs mit Versionierung.**
| Feld | Datentyp | Pflicht | Beschreibung |
|------|----------|---------|--------------|
| `id` | UUID | ✓ | Eindeutiger Identifier |
| `label` | String | ✓ | Dokumentbezeichnung |
| `versionsbezeichnung` | String | - | Versionsnummer oder -bezeichnung (z.B. "v1.0", "Rev. A") |
| `dokumentTyp` | Enum[DokumentTyp] | - | Typ des Dokuments (siehe DokumentTyp-Enum) |
| `dokumentReferenz` | String | ✓ | Dateipfad oder URL |
| `quelle` | String | - | Quelle des Dokuments |
| `mimeType` | String | - | MIME-Type des Dokuments (z.B. "application/pdf", "image/png") |
| `kategorienTags` | list[String] | - | Kategorisierung des Dokuments |
**Hinweis:**
Aktuelle Dokumente (z.B. aktuelle Baureglemente, BZO) können anhand des `dokumentTyp`-Attributs identifiziert werden. Die entsprechenden Dokumente finden sich in der `dokumente`-Liste der jeweiligen Entität (Kanton, Gemeinde).
#### Beispiel-Kategorien (nicht abschliessend)
| Kategorie | Beschreibung |
|-----------|--------------|
| `Kataster Objekte` | Amtliche Vermessung |
| `Kataster Werkeleitungen` | Leitungskataster |
| `Kataster Belastete Standorte` | Altlasten |
| `Kataster Bäume` | Baumkataster |
| `Zonenplan` | Zonenpläne |
| `Planungs- und Baugesetz (PGB)` | Kantonale Baugesetze |
| `Bau- und Zonenordnung (BZO)` | Gemeinde BZO |
| `Parkplatzverordnung` | Parkplatzregelungen |
| `Eigentümerauskunft` | Grundbuch-Auszüge Eigentümer |
| `Grundbuchauszug` | Vollständige Grundbuch-Auszüge |
| `Bauherrschaft` | Dokumente von der Bauherrschaft |
| `Planung` | Planungsdokumente |
---
### 4. Geografische Entitäten
#### GeoPolylinie
**Repräsentiert eine Linie oder ein Polygon aus mehreren GeoPunkten.**
| Feld | Datentyp | Pflicht | Beschreibung |
|------|----------|---------|--------------|
| `id` | UUID | ✓ | Eindeutiger Identifier |
| `closed` | Boolean | ✓ | Ist die GeoPolylinie geschlossen (Polygon)? |
| `punkte` | list[GeoPunkt] | ✓ | Liste der GeoPunkte, die die GeoPolylinie bilden |
**Verwendung:**
- Parzellenperimeter (geschlossene GeoPolylinie)
- Baulinie (offene oder geschlossene GeoPolylinie)
- Projektperimeter (geschlossene GeoPolylinie)
#### GeoPunkt
**Repräsentiert einen 3D-Punkt mit Referenzangabe.**
| Feld | Datentyp | Pflicht | Beschreibung |
|------|----------|---------|--------------|
| `koordinatensystem` | String | ✓ | Koordinatensystem (z.B. "LV95", "EPSG:2056") |
| `x` | Float | ✓ | Ostwert (E) [m], typisch 2'480'000 - 2'840'000 |
| `y` | Float | ✓ | Nordwert (N) [m], typisch 1'070'000 - 1'300'000 |
| `z` | Float | - | Höhe über Meer [m] |
| `referenz` | Enum[GeoTag] | - | Kategorisierung des Punktes |
**Verwendung:**
- Als Teil einer GeoPolylinie (Parzellenperimeter, Baulinie)
- Einzelne Referenzpunkte
#### GeoTag (Enum)
| Kategorie | Beschreibung |
|-----------|--------------|
| `K1` | Fixpunkt höchster Genauigkeit |
| `K2` | Fixpunkt mittlerer Genauigkeit |
| `K3` | Fixpunkt niedriger Genauigkeit |
| `Geometer` | Vom Geometer vermessener Punkt |
**Beispiel (Zürich Hauptbahnhof):**
- `koordinatensystem`: "LV95" oder "EPSG:2056"
- `x`: 2'683'140 [m]
- `y`: 1'247'850 [m]
- `z`: 408 [m]
- `referenz`: "K1" (oder ein anderer GeoTag-Wert)
---
### 5. Administrative Hierarchie
#### Land
| Feld | Datentyp | Pflicht | Beschreibung |
|------|----------|---------|--------------|
| `id` | UUID | ✓ | Eindeutiger Identifier |
| `label` | String | ✓ | Landesname (z.B. "Schweiz") |
| `abk` | String | - | Abkürzung (z.B. "CH") |
| `dokumente` | list[Dokument] | - | Nationale Gesetze |
| `kontextInformationen` | list[Kontext] | - | Nationale Kontextinformationen |
---
#### Kanton
| Feld | Datentyp | Pflicht | Beschreibung |
|------|----------|---------|--------------|
| `id` | UUID | ✓ | Eindeutiger Identifier |
| `label` | String | ✓ | Kantonsname (z.B. "Zürich") |
| `id_land` | [land] | eindeutiger Link zum land, also in welchem land kanton liegt |
| `abk` | String | - | Abkürzung (z.B. "ZH") |
| `dokumente` | list[Dokument] | - | Kantonale Dokumente |
| `kontextInformationen` | list[Kontext] | - | Kantonsspezifische Kontextinfos |
---
#### Gemeinde
| Feld | Datentyp | Pflicht | Beschreibung |
|------|----------|---------|--------------|
| `id` | UUID | ✓ | Eindeutiger Identifier |
| `label` | String | ✓ | Gemeindename (z.B. "Zürich") |
| `id_kanton` | [kanton] | eindeutiger Link zur gemeinde, also im welchem kanton gemeinde liegt |
| `plz` | String | - | Postleitzahl (bei Gemeinden mit mehreren PLZ kann dies eine Haupt-PLZ sein) |
| `dokumente` | list[Dokument] | - | Gemeindedokumente |
| `kontextInformationen` | list[Kontext] | - | Gemeindespezifische Kontextinfos |
**Hinweis:**
Bei Gemeinden mit mehreren Postleitzahlen (z.B. Zürich, Bern) wird die konkrete PLZ der Parzelle im Attribut `plz` der Parzelle erfasst.
---
### 6. Kontext
**Unterstützendes Datenobjekt für flexible Zusatzinformationen und Hinweise.**
| Feld | Datentyp | Pflicht | Beschreibung |
|------|----------|---------|--------------|
| `id` | UUID | ✓ | Eindeutiger Identifier |
| `thema` | String | ✓ | Bezeichnung des Themas |
| `inhalt` | String | ✓ | Detaillierte Information (Text) |
**Verwendung:**
Kontext-Objekte werden als Listen in den jeweiligen Entitäten gespeichert:
- `projekt.kontextInformationen: list[Kontext]`
- `parzelle.kontextInformationen: list[Kontext]`
- `land.kontextInformationen: list[Kontext]`
- `kanton.kontextInformationen: list[Kontext]`
- `gemeinde.kontextInformationen: list[Kontext]`
#### Beispielthemen (nicht abschliessend)
| Themenbereich | Beispiele |
|---------------|-----------|
| **Nutzung** | Vorgaben zur Erdgeschossnutzung (Wohnen erlaubt oder Pflicht für Gewerbe) |
| **Rechte** | Dienstbarkeiten (Wegrechte, Nähebaurechte, etc.) |
| **Parkierung** | Anforderung Parkplätze (Berechnung / Reduktionsfaktoren) |
| **Ausnützung** | Ausnützungsübertragungen |
| **Umwelt** | Schadstoffbelastungen auf Parzellen |
| **Planung** | Aktive Gestaltungspläne |
| **Lärm** | Lärmempfindlichkeitsstufen |
| **Energie** | Mögliche Wärmenutzung (Wärmeverbundnetze; Fernwärme, Anergie) |
| **Natur** | Baumbestand auf privaten Grundstücken |
| **Schutz** | Isos (Ortsbild, Schutzstatus, Denkmalschutz, Weilergebiet, etc.) |
| **Gefahren** | Naturgefahren (z.B. Objektschutzmassnahmen (Hochwasser)) |
| **Revision** | Verweis auf aktuell in oder zukünftig in Revision befindlichen Normen/Gesetze (z.B. Revision PBG mit aktuell negativer Vorwirkung) |
**Design-Rationale:**
Das Kontext-Objekt ermöglicht flexibles Hinzufügen von projektspezifischen, parzellen-spezifischen oder regionalen Informationen ohne Schemaänderungen.
---
### 7. Hilfsentitäten & Enumerationen
#### JaNein (Enum)
**Drei-wertiger Zustand für optionale Ja/Nein-Fragen.**
| Wert | Bedeutung |
|------|-----------|
| `""` (leer) | Unbekannt / Nicht erfasst |
| `"Ja"` | Ja / Zutreffend |
| `"Nein"` | Nein / Nicht zutreffend |
**Verwendung:**
- `parzelleBebaut`: Ist die Parzelle bebaut?
- `parzelleErschlossen`: Ist die Parzelle erschlossen?
- `parzelleHanglage`: Liegt die Parzelle in Hanglage?
---
#### StatusProzess (Enum)
**Projektstatus zur Nachverfolgung des Projektfortschritts.**
| Wert | Beschreibung |
|------|--------------|
| `Eingang` | Projekt wurde eingereicht |
| `Analyse` | Projekt wird analysiert |
| `Studie` | Machbarkeitsstudie läuft |
| `Planung` | Planungsphase |
| `Baurechtsverfahren` | Baubewilligung läuft |
| `Umsetzung` | Bauprojekt in Umsetzung |
| `Archiv` | Projekt abgeschlossen |
---
#### DokumentTyp (Enum)
**Dokumenttyp zur Kategorisierung von Dokumenten, insbesondere für kantonale und kommunale Dokumente.**
| Wert | Beschreibung |
|------|--------------|
| `kantonBaureglementAktuell` | Aktuelles Baureglement (Kanton) |
| `kantonBaureglementRevision` | Baureglement in Revision (Kanton) |
| `kantonBauverordnungAktuell` | Aktuelle Bauverordnung (Kanton) |
| `kantonBauverordnungRevision` | Bauverordnung in Revision (Kanton) |
| `gemeindeBzoAktuell` | Aktuelle Bau- und Zonenordnung (BZO) (Gemeinde) |
| `gemeindeBzoRevision` | BZO in Revision (Gemeinde) |
**Verwendung:**
- Dokumente in der `dokumente`-Liste von Kanton oder Gemeinde können über `dokumentTyp` identifiziert werden
- Ermöglicht die Suche nach aktuellen oder in Revision befindlichen Dokumenten
---
## Q & A
1. **Versionierung**: Sollen Änderungen an Parzellen historisiert werden? --> Vorerst nicht
2. **Mehrsprachigkeit**: Labels in DE/FR/IT? --> Wir im Pydantic Model später umgesetzt
3. **Benutzer & Rollen**: Wer darf was bearbeiten? --> In der App über Roles und Permissions gesteuert
4. **Workflow-Engine**: Für Statusübergänge und Genehmigungen? --> In der App über Workflow-Engine gesteuert
5. **Integration**: Anbindung an amtliche Geodaten (z.B. Swisstopo API)? --> In der App über Integrationen gesteuert
6. **Berechnungen**: Sollen Ausnützungsberechnungen automatisiert werden? --> In der App über Berechnungen gesteuert
---
## Nächste Schritte
1. **Validierung**: Review mit PEK
2. **Prototyp**: Implementierung der Datenmodell-Klassen
3. **GIS-Integration**: PostGIS aufsetzen, Test-Geodaten importieren
4. **API-Design**: RESTful API (FastAPI) mit OpenAPI-Dokumentation

File diff suppressed because it is too large Load diff

View file

@ -1,209 +0,0 @@
# Architecture Overview
High-level architecture diagram of the Gateway project.
```mermaid
graph TB
%% Entry Point
App[app.py<br/>FastAPI Application]
%% Middleware Layer
App --> Security[Security<br/>Auth, CSRF, JWT, Token Refresh]
App --> CORS[CORS Middleware]
%% API Layer
App --> Routes[Routes<br/>API Endpoints]
%% Business Logic Layer
Routes --> Features[Features<br/>Business Logic Modules]
Routes --> Services[Services<br/>Service Layer]
%% Features can use Services
Features --> Services
%% Data Access Layer
Services --> Interfaces[Interfaces<br/>Data Access Layer]
Features --> Interfaces
%% External Connections
Interfaces --> Connectors[Connectors<br/>External System Connections]
Interfaces --> Database[(Database<br/>PostgreSQL)]
%% Connectors connect to external systems
Connectors --> Database
Connectors --> External[External Systems<br/>Jira, ClickUp, Google, etc.]
%% Shared Resources
App -.-> Shared[Shared Modules<br/>Configuration, Logging, Utils]
Routes -.-> Shared
Features -.-> Shared
Services -.-> Shared
Interfaces -.-> Shared
%% Data Models used throughout
Routes -.-> DataModels[Data Models<br/>Request/Response Schemas]
Features -.-> DataModels
Services -.-> DataModels
Interfaces -.-> DataModels
%% Feature Lifecycle Management
App --> FeaturesLifecycle[Features Lifecycle<br/>Startup/Shutdown Management]
FeaturesLifecycle --> Features
%% Styling
classDef entryPoint fill:#e1f5ff,stroke:#01579b,stroke-width:3px
classDef apiLayer fill:#f3e5f5,stroke:#4a148c,stroke-width:2px
classDef businessLogic fill:#e8f5e9,stroke:#1b5e20,stroke-width:2px
classDef dataAccess fill:#fff3e0,stroke:#e65100,stroke-width:2px
classDef external fill:#fce4ec,stroke:#880e4f,stroke-width:2px
classDef shared fill:#f5f5f5,stroke:#424242,stroke-width:1px,stroke-dasharray: 5 5
class App entryPoint
class Routes,Security,CORS apiLayer
class Features,Services businessLogic
class Interfaces,Connectors dataAccess
class Database,External external
class Shared,DataModels,FeaturesLifecycle shared
```
## Data Flow Diagram
The following sequence diagram shows how data flows through the same architectural layers from the architecture diagram above.
```mermaid
sequenceDiagram
participant Client
participant App as app.py<br/>FastAPI Application
participant Security as Security<br/>Auth, CSRF, JWT
participant Routes as Routes<br/>API Endpoints
participant Features as Features<br/>Business Logic
participant Services as Services<br/>Service Layer
participant Interfaces as Interfaces<br/>Data Access Layer
participant Connectors as Connectors<br/>External Connections
participant Database as Database<br/>PostgreSQL
participant External as External Systems<br/>Jira, ClickUp, etc.
%% Request Flow
Client->>App: HTTP Request
App->>Security: Validate Auth & CSRF
Security-->>App: Authenticated
App->>Routes: Validated Request
Routes->>Routes: Validate Data Models
alt Route delegates to Features
Routes->>Features: Delegate Request
Features->>Services: Use Service (optional)
Services-->>Features: Service Result
Features->>Interfaces: Request Data Access
else Route delegates to Services
Routes->>Services: Delegate Request
Services->>Interfaces: Request Data Access
end
Interfaces->>Connectors: Query Request
alt Database Query
Connectors->>Database: Execute Query
Database-->>Connectors: Raw Data
else External API Call
Connectors->>External: API Call
External-->>Connectors: API Response
end
%% Response Flow
Connectors-->>Interfaces: Raw Data
Interfaces->>Interfaces: Transform to Domain Objects
Interfaces-->>Features: Domain Objects
Interfaces-->>Services: Domain Objects
Features->>Features: Process Business Logic
Services->>Services: Process Service Logic
Features-->>Routes: Processed Data
Services-->>Routes: Processed Data
Routes->>Routes: Serialize to Response Models
Routes-->>App: HTTP Response
App-->>Client: HTTP Response
```
### Request Flow (Top to Bottom)
1. **Client** sends HTTP request to **app.py**
2. **app.py** forwards to **Security** middleware for authentication and CSRF validation
3. **Security** validates and returns authenticated request to **app.py**
4. **app.py** forwards validated request to **Routes**
5. **Routes** validate request data using Data Models, then delegate to either:
- **Features** (which may use **Services**), or
- **Services** directly
6. **Features/Services** call **Interfaces** for data access
7. **Interfaces** use **Connectors** to execute queries
8. **Connectors** query **Database** or call **External Systems**
### Response Flow (Bottom to Top)
1. **Database/External Systems** return raw data to **Connectors**
2. **Connectors** pass raw data to **Interfaces**
3. **Interfaces** transform raw data into domain objects
4. **Interfaces** return domain objects to **Features/Services**
5. **Features/Services** process business logic and return processed data to **Routes**
6. **Routes** serialize data to response models and return HTTP response to **app.py**
7. **app.py** returns HTTP response to **Client**
### Data Transformations
- **Routes**: HTTP Request ↔ Validated Data Models (Pydantic)
- **Features/Services**: Data Models ↔ Domain Objects (Business Logic Processing)
- **Interfaces**: Domain Objects ↔ Raw Data (SQL/API Format)
- **Connectors**: Raw Data ↔ Database Queries/API Calls
## Layer Descriptions
### Entry Point Layer
**app.py** - The FastAPI application entry point that orchestrates the entire system. It initializes logging, configures CORS and security middleware, registers all route routers, and manages the application lifecycle (startup/shutdown). This is where the application server starts and all components are wired together.
### API Layer
**Routes** - HTTP endpoints that define the REST API surface. Routes receive client requests, validate input using data models, delegate to features or services for business logic, and return structured responses. Each route module handles a specific domain (e.g., Real Estate, Chat, Workflows, Security).
**Security** - Middleware and services that handle authentication, authorization, CSRF protection, JWT token management, and token refresh. Ensures all requests are properly authenticated and authorized before reaching business logic. See [Security Component Documentation](./security-component.md) for detailed documentation.
**CORS** - Cross-Origin Resource Sharing middleware that controls which external domains can access the API, enabling secure cross-origin requests from web applications.
### Business Logic Layer
**Features** - Domain-specific business logic modules that implement core functionality for specific use cases (e.g., Real Estate management, Chat workflows, Data neutralization). Features are stateless and orchestrate services to fulfill business requirements. They can be called directly from routes or managed by the Features Lifecycle for background processing.
**Services** - Reusable, composable service components that provide cross-cutting functionality (AI processing, document extraction, content generation, chat operations, ticket management, etc.). Services encapsulate complex operations and can be used by multiple features. They typically use interfaces to access data and may call other services.
### Data Access Layer
**Interfaces** - Abstraction layer that provides a clean, domain-oriented API for accessing data. Interfaces hide the complexity of database connections and external system integrations, offering high-level methods for CRUD operations. They handle user context, access control, and data transformation between the application and persistence layers.
**Connectors** - Concrete implementations that handle low-level communication with external systems. Database connectors manage PostgreSQL connections, query execution, and transaction handling. External connectors integrate with third-party services (Jira, ClickUp, Google Voice, SharePoint) using their specific APIs and protocols.
### External Systems Layer
**Database** - PostgreSQL databases that persist application data. Multiple databases may exist for different domains (e.g., chat data, real estate data, management data). Connectors handle all database interactions.
**External Systems** - Third-party services and APIs that the application integrates with. These include ticketing systems (Jira, ClickUp), cloud services (Google Voice, SharePoint), and other external platforms. Connectors abstract away the specifics of each integration.
### Shared Resources Layer
**Shared Modules** - Common utilities and infrastructure used throughout the application. Includes configuration management, logging utilities, time/date helpers, JSON processing, attribute utilities, and audit logging. These modules provide cross-cutting concerns that don't belong to any specific domain.
**Data Models** - Pydantic models that define data structures for requests, responses, and database entities. They provide validation, serialization, and type safety across all layers. Models are organized by domain (e.g., Real Estate, Chat, Security, AI).
**Features Lifecycle** - Manages the startup and shutdown of features that require background processing, scheduled tasks, or event-driven operations. Coordinates initialization and cleanup of features that need persistent processes or event listeners.
## Request/Response Flow Summary
For a detailed visual representation, see the [Data Flow Diagram](#data-flow-diagram) above.
**Simplified Request Flow**: `Client Request``CORS``Security (Auth/CSRF)``Routes``Features/Services``Interfaces``Connectors``Database/External Systems`
**Simplified Response Flow**: `Database/External Systems``Connectors``Interfaces``Features/Services``Routes``Transform & Log``Client Response`
## Key Architectural Patterns
- **Layered Architecture**: Clear separation between API, business logic, and data access layers
- **Dependency Injection**: Services and interfaces are injected where needed
- **Interface Abstraction**: Interfaces abstract away database and connector details
- **Stateless Design**: Features operate statelessly without session management
- **Shared Utilities**: Common functionality centralized in shared modules

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,365 +0,0 @@
# Date and Time Handling
This document describes how dates and times are handled throughout the gateway project, including storage formats, transformations, and retrieval mechanisms.
## Overview
The gateway uses **Unix timestamps** (floats representing seconds since epoch) as the standard format for all date and time values. This ensures consistency across different database backends and eliminates timezone-related issues by always working in UTC.
## Core Components
### Time Utilities Module
The primary module for date/time handling is `modules/shared/timeUtils.py`, which provides:
#### `getUtcTimestamp() -> float`
Returns the current UTC timestamp as a float (seconds since Unix epoch with millisecond precision).
**Implementation:**
- Uses Python's `time.time()` which returns seconds since epoch as a float
- Provides millisecond precision
- Always returns UTC time
#### `getUtcNow() -> datetime`
Returns the current UTC time as a `datetime` object with timezone information.
#### `parseTimestamp(value: Any, default: Optional[float] = None) -> Optional[float]`
**Critical function for database retrieval** - Parses timestamp values from various formats and converts them to float.
This function handles the transformation/decoding of timestamps when reading from the database, especially important for PostgreSQL connectors that may return numeric fields as strings in some environments (e.g., Azure PostgreSQL).
**Supported input formats:**
- `float`: Returns as-is
- `int`: Converts to float
- `str`: Attempts to parse as numeric string (e.g., "1234567890.123")
- `None`: Returns default value (or None if no default provided)
**Usage:** Call `parseTimestamp()` with the database value and an optional default. For example: `parseTimestamp(db_value, default=getUtcTimestamp())`.
**Why this is needed:**
- PostgreSQL connectors (especially Azure PostgreSQL) may return numeric fields as strings
- Ensures consistent float type regardless of database return format
- Provides safe fallback with default values
#### `createExpirationTimestamp(expiresInSeconds: int) -> float`
Creates an expiration timestamp by adding seconds to the current UTC timestamp. Call with the number of seconds until expiration, for example: `createExpirationTimestamp(3600)` for 1 hour from now.
## Database Storage
### Storage Format
All timestamps are stored in the database as **floats** (Unix timestamps in seconds):
- **PostgreSQL**: Stored as `NUMERIC` or `DOUBLE PRECISION` type
- **JSON Database**: Stored as JSON number (float) in record files
### Saving Timestamps
#### PostgreSQL Connector (`connectorDbPostgre.py`)
When saving records, timestamp fields (`_createdAt`, `_modifiedAt`) are handled specially. The connector checks if the value is a string and attempts to convert it to float before storing.
**Process:**
1. Timestamp values are converted to float if they're strings
2. Stored directly as numeric values in PostgreSQL
3. No encryption or encoding - stored as plain numeric values
#### JSON Connector (`connectorDbJson.py`)
Timestamps are stored directly as JSON numbers. The connector calls `getUtcTimestamp()` to get the current time and sets `_createdAt` on creation and `_modifiedAt` on every save operation.
**Process:**
1. Timestamps are generated as floats using `getUtcTimestamp()`
2. Stored as JSON numbers in record files
3. No transformation needed - JSON natively supports float numbers
### Retrieving Timestamps
#### PostgreSQL Connector
When reading from PostgreSQL, timestamps may be returned in different formats:
- **Expected**: Float values
- **Actual (Azure PostgreSQL)**: Sometimes returned as strings
- **Solution**: Use `parseTimestamp()` to normalize
**Example from code:** In `interfaceDbChatObjects.py`, timestamps are parsed using `parseTimestamp(msg.get("publishedAt"), default=getUtcTimestamp())`.
#### JSON Connector
Timestamps are read directly from JSON and typically remain as floats, but `parseTimestamp()` is still used for safety to ensure consistent float type regardless of JSON parsing quirks. Call `parseTimestamp(record.get("timestamp"), default=getUtcTimestamp())` when reading timestamp fields.
## Data Model Definitions
Timestamps are defined in Pydantic models using the `float` type with `getUtcTimestamp` as the default factory. For example, in `ChatLog` model, the `timestamp` field uses `Field(default_factory=getUtcTimestamp, ...)`.
**Common timestamp fields:**
- `_createdAt`: When the record was created
- `_modifiedAt`: When the record was last modified
- `publishedAt`: When a message was published
- `timestamp`: Generic timestamp field
- `expiresAt`: When something expires
- `connectedAt`: When a connection was established
- `lastChecked`: When something was last verified
- `creationDate`: When something was created
## Transformation Flow
### Saving to Database
```
Application Code
getUtcTimestamp() → float (e.g., 1234567890.123)
Database Connector
PostgreSQL: Store as NUMERIC/DOUBLE PRECISION
JSON: Store as JSON number
```
### Reading from Database
```
Database
PostgreSQL: May return as float, int, or string
JSON: Returns as float (or int if no decimals)
parseTimestamp() → Normalizes to float
Application Code (always receives float)
```
## Key Points
1. **No Encryption**: Timestamps are **not encrypted**. They are stored as plain numeric values (floats) in the database. The "encrypted format" you may have seen refers to the numeric Unix timestamp format, which is not human-readable but is not encrypted.
2. **Type Transformation**: The main transformation happens when **reading** from the database:
- Database may return timestamps as strings (especially Azure PostgreSQL)
- `parseTimestamp()` converts strings/int/float → float
- This ensures consistent float type in application code
3. **UTC Only**: All timestamps are in UTC. No timezone conversions happen at the database level.
4. **Millisecond Precision**: Timestamps use float type, providing millisecond precision (e.g., `1234567890.123`).
5. **Default Values**: When timestamps are missing or invalid, `parseTimestamp()` can provide safe defaults using the `default` parameter.
## Usage Examples
### Creating a Record with Timestamps
When creating records, call `getUtcTimestamp()` to set `_createdAt` and `_modifiedAt` fields. These are typically auto-set by the database connectors.
### Reading and Using Timestamps
After retrieving a record from the database, use `parseTimestamp(record.get("publishedAt"), default=getUtcTimestamp())` to safely parse the timestamp value before using it for filtering or comparison.
### Filtering by Timestamp
When filtering messages or records by timestamp, iterate through the results and use `parseTimestamp(msg.get("publishedAt"), default=getUtcTimestamp())` to parse each timestamp, then compare against your threshold value.
### Sorting by Timestamp
When sorting logs or records by timestamp, use `parseTimestamp()` in the sort key function, for example: `logs.sort(key=lambda x: parseTimestamp(x.get("timestamp"), default=0))`.
## Common Patterns
### Automatic Timestamp Management
Database connectors automatically manage `_createdAt` and `_modifiedAt`:
- `_createdAt`: Set only on record creation (if not already present)
- `_modifiedAt`: Updated on every save operation
### Timestamp Filtering
When filtering records by timestamp, always use `parseTimestamp()` to handle all database return types. Call `parseTimestamp(record.get("timestamp"), default=0)` before comparison. Do not directly compare timestamp values as they may be strings from the database.
### Expiration Timestamps
For expiration logic, use `createExpirationTimestamp(3600)` to create an expiration timestamp, then compare it with the current time using `getUtcTimestamp()`. Parse any stored expiration timestamps using `parseTimestamp()` before comparison.
## Database-Specific Notes
### PostgreSQL (Azure)
- May return numeric fields as strings
- Always use `parseTimestamp()` when reading timestamp fields
- Stored as `NUMERIC` or `DOUBLE PRECISION` type
### JSON Database
- Timestamps stored as JSON numbers
- Usually returned as floats, but `parseTimestamp()` provides safety
- No special handling needed beyond normalization
## Troubleshooting
### Issue: Timestamp is a string instead of float
**Solution**: Use `parseTimestamp()` to convert: `parseTimestamp(string_timestamp, default=getUtcTimestamp())`.
### Issue: Timestamp is None
**Solution**: Provide a default value: `parseTimestamp(record.get("timestamp"), default=getUtcTimestamp())`.
### Issue: Timestamp comparison fails
**Cause**: Comparing string to float
**Solution**: Always parse first using `parseTimestamp(value, default=0)` before any comparison operations.
## Summary
The date/time handling system:
1. **Stores** timestamps as Unix timestamps (floats) in UTC
2. **Transforms** database return values (string/int/float) → float using `parseTimestamp()`
3. **Provides** utilities for timestamp generation, parsing, and expiration
4. **Ensures** consistency across different database backends
5. **Handles** edge cases (None values, string returns, invalid formats)
The transformation you mentioned is the **type normalization** that happens when reading from the database, not encryption. Timestamps are stored as plain numeric values and converted to consistent float types for application use.
---
## Frontend Requirements and Implementation
### API Response Format
The backend API returns timestamps as **Unix timestamps (floats)** in all JSON responses. Timestamps are always in UTC and represented as numbers (not strings).
**Example API Response:** The API returns timestamps as numeric values in JSON, for example: `_createdAt: 1704067200.123`, `_modifiedAt: 1704067300.456`, `publishedAt: 1704067250.789`, `expiresAt: 1704153600.0`.
**Important Notes:**
- Timestamps are **always numbers** (float) in JSON responses
- All timestamps are in **UTC** (no timezone information in the value)
- Timestamps have **millisecond precision** (decimal places)
- Timestamp fields may be `null` or `undefined` if not set
### Frontend Requirements
#### 1. Timestamp Decoding Module
The frontend **must** implement a core timestamp utility module that handles:
- **Decoding/parsing** timestamp values from API responses
- **Type normalization** (handles number, string, null, undefined)
- **Conversion** to JavaScript Date objects
- **Formatting** for display (relative time, absolute date/time)
- **Timezone handling** (convert UTC to user's local timezone)
#### 2. Required Functionality
The frontend timestamp module must provide:
1. **Parse/Decode Function**: Convert API timestamp (number/string/null) → JavaScript Date
2. **Format Functions**: Convert Date → human-readable strings
3. **Relative Time**: "2 hours ago", "in 5 minutes", etc.
4. **Absolute Time**: "2024-01-01 12:30:45 UTC" or localized format
5. **Comparison Utilities**: Compare timestamps, check expiration, etc.
6. **Safe Defaults**: Handle null/undefined/invalid values gracefully
#### 3. Display Requirements
Based on frontend documentation requirements, timestamps should be displayed as:
- **List Views**: Relative time ("2 hours ago") for recent items, absolute date for older items
- **Detail Views**: Absolute date/time with timezone information
- **Filters**: Date/time pickers that convert to/from Unix timestamps
- **Sorting**: Sort by timestamp value (numeric comparison)
### Core Frontend Timestamp Module
The frontend should implement a core timestamp utility module in `src/utils/timestampUtils.ts` (or `.js`) that provides the following functions:
#### Required Functions
- **`parseTimestamp(value, defaultValue)`**: Parse a timestamp value from the API and convert to JavaScript Date. Handles number, string, null, and undefined inputs. Validates timestamp range (1970-2100) and converts seconds to milliseconds for JavaScript Date constructor.
- **`getUtcTimestamp()`**: Get current UTC timestamp as Unix timestamp (float). Returns `Date.now() / 1000`.
- **`formatRelativeTime(timestamp, options)`**: Format timestamp as relative time string. Returns strings like "just now", "2 minutes ago", "3 hours ago", "2 days ago", or "in 5 minutes" for future timestamps. Options include `includeSeconds`, `futurePrefix`, and `pastSuffix`.
- **`formatAbsoluteTime(timestamp, options)`**: Format timestamp as absolute date/time string. Options include `includeTime`, `includeSeconds`, `includeTimezone`, and `format` ('iso', 'local', or 'utc').
- **`formatTimestamp(timestamp, options)`**: Smart formatting that uses relative time for recent items (default < 24 hours) and absolute time for older items. Options include `relativeThreshold`, `showRelative`, and `showAbsolute`.
- **`isExpired(expiresAt)`**: Check if a timestamp has expired (is in the past). Returns true if expired, false otherwise.
- **`isFuture(timestamp)`**: Check if a timestamp is in the future. Returns true if in future, false otherwise.
- **`compareTimestamps(timestamp1, timestamp2)`**: Compare two timestamps. Returns -1 if timestamp1 < timestamp2, 0 if equal, 1 if timestamp1 > timestamp2.
- **`dateToTimestamp(date)`**: Convert JavaScript Date to Unix timestamp (float). Defaults to current date if not provided.
- **`toISOString(timestamp)`**: Convert Unix timestamp to ISO 8601 string.
#### Usage Examples
**Basic Usage:** Import functions from the timestamp utils module. Use `parseTimestamp(apiData._createdAt)` to parse timestamps from API responses. Use `formatTimestamp(apiData._createdAt)` for smart display formatting (returns relative time for recent items, absolute time for older). Use `formatRelativeTime(apiData._createdAt)` for relative time strings like "2 hours ago". Use `formatAbsoluteTime(apiData._createdAt, { format: 'utc' })` for absolute time strings.
**In React Components:** Import `parseTimestamp`, `formatTimestamp`, and `isExpired` from the timestamp utils module. Call `parseTimestamp(workflow._createdAt)` to parse timestamps. Use `formatTimestamp(workflow._createdAt)` to display formatted time. Use `isExpired(expiresAt)` to check if a token has expired.
**Sorting:** Import `compareTimestamps` and use it in sort functions: `workflows.sort((a, b) => compareTimestamps(a._createdAt, b._createdAt))`.
**Filtering:** Import `isExpired` and use it to filter arrays: `tokens.filter(token => !isExpired(token.expiresAt))`.
### Frontend Integration Guidelines
#### 1. Always Use the Timestamp Module
**✅ DO:** Import and use `parseTimestamp()` from the timestamp utils module. Call `parseTimestamp(apiData._createdAt)` to safely parse timestamps.
**❌ DON'T:** Do not assume timestamps are always numbers and directly create Date objects like `new Date(apiData._createdAt * 1000)` as this may fail if the value is a string or null.
#### 2. Handle Null/Undefined Values
**✅ DO:** Always provide a default value when calling `parseTimestamp()`, for example: `parseTimestamp(apiData.expiresAt, new Date())`. Check if the returned date is valid before using it.
**❌ DON'T:** Do not assume timestamps always exist. Do not directly create Date objects without checking for null values first.
#### 3. Use Appropriate Formatting
- **List Views**: Use `formatTimestamp()` for smart relative/absolute formatting
- **Detail Views**: Use `formatAbsoluteTime()` with timezone information
- **Filters**: Convert Date picker values to Unix timestamps using `dateToTimestamp()`
#### 4. Timezone Considerations
- All backend timestamps are in **UTC**
- Frontend should convert to **user's local timezone** for display
- Use `formatAbsoluteTime()` with `format: 'local'` for user-friendly display
- Always show timezone information in detail views
### Testing the Timestamp Module
**Test Cases to Cover:**
1. Parse number timestamps (float and int)
2. Parse string timestamps
3. Handle null/undefined values
4. Handle invalid values (NaN, out of range)
5. Format relative time (past and future)
6. Format absolute time (UTC and local)
7. Compare timestamps
8. Check expiration
9. Convert Date to timestamp
**Example Test:** Import functions from the timestamp utils module and test that `parseTimestamp()` correctly handles number timestamps, string timestamps, and null values. Test that `formatRelativeTime()` correctly formats timestamps as relative time strings. Test that `isExpired()` correctly identifies expired timestamps.
### Summary: Frontend Timestamp Handling
1. **Always decode** API timestamps using `parseTimestamp()` - handles number/string/null
2. **Format appropriately** - relative for recent, absolute for older items
3. **Handle timezones** - convert UTC to user's local timezone for display
4. **Provide defaults** - handle null/undefined gracefully
5. **Use consistently** - use the core module throughout the project
6. **Test thoroughly** - cover all input formats and edge cases
The core timestamp module ensures consistent, safe handling of timestamps across the entire frontend application, matching the backend's `parseTimestamp()` functionality for type normalization and error handling.

View file

@ -1,981 +0,0 @@
# Features Component Documentation
Comprehensive documentation of the Features layer in the Gateway application, explaining the architecture, patterns, and implementation details of all feature modules and their relationship to connectors, services, and workflows.
## Table of Contents
1. [Overview](#overview)
2. [What is a Feature?](#what-is-a-feature)
3. [Features vs Services vs Workflows](#features-vs-services-vs-workflows)
4. [Feature Architecture](#feature-architecture)
5. [Feature Lifecycle Management](#feature-lifecycle-management)
6. [Connectors in the Architecture](#connectors-in-the-architecture)
7. [Individual Features](#individual-features)
8. [Feature Patterns and Best Practices](#feature-patterns-and-best-practices)
---
## Overview
The **Features Layer** is a domain-specific business logic layer that implements core functionality for specific use cases. Features serve as **temporary solutions** that bridge the gap between initial requirements and full service implementation or workflow integration. They provide rapid prototyping capabilities while maintaining clean architectural boundaries.
```mermaid
graph TB
subgraph "Application Layers"
Routes[Routes Layer<br/>API Endpoints]
Features[Features Layer<br/>Domain-Specific Logic]
Services[Services Layer<br/>Reusable Components]
Workflows[Workflows Layer<br/>Orchestration Engine]
Interfaces[Interfaces Layer<br/>Data Access]
Connectors[Connectors Layer<br/>External Systems]
end
Routes --> Features
Routes --> Services
Routes --> Workflows
Features --> Services
Features --> Interfaces
Workflows --> Services
Services --> Interfaces
Interfaces --> Connectors
style Features fill:#e8f5e9,stroke:#1b5e20,stroke-width:3px
style Connectors fill:#fff3e0,stroke:#e65100,stroke-width:2px
```
### Key Characteristics
- **Domain-Specific**: Each feature addresses a specific business domain or use case
- **Temporary by Design**: Features are intended to be migrated to services or workflows over time
- **Stateless**: Features operate without maintaining session state
- **Service-Dependent**: Features leverage services for cross-cutting functionality
- **Interface-Dependent**: Features use interfaces to access data through connectors
- **Lifecycle-Managed**: Background features are managed through the Features Lifecycle system
---
## What is a Feature?
A **Feature** is a domain-specific business logic module that implements functionality for a particular use case. Features are designed to:
1. **Rapid Prototyping**: Enable quick implementation of new functionality without full service architecture
2. **Domain Encapsulation**: Group related business logic for a specific domain (e.g., Real Estate, Chat, Data Synchronization)
3. **Temporary Solutions**: Serve as interim implementations before migration to services or workflows
4. **Orchestration**: Coordinate between services, interfaces, and external systems to fulfill business requirements
5. **Background Processing**: Support scheduled tasks, event-driven operations, and background managers
### Feature Lifecycle Philosophy
Features follow a natural evolution path:
```mermaid
graph LR
A[Initial Requirement] --> B[Feature Implementation]
B --> C{Stability & Usage}
C -->|Mature| D[Service Migration]
C -->|Complex Workflow| E[Workflow Integration]
C -->|Still Experimental| B
D --> F[Production Service]
E --> G[Workflow Component]
style B fill:#fff3e0,stroke:#e65100
style D fill:#e8f5e9,stroke:#1b5e20
style E fill:#e1f5ff,stroke:#01579b
```
**When to Use Features:**
- New functionality that needs rapid development
- Domain-specific logic that may not be reusable
- Experimental or proof-of-concept implementations
- Background tasks requiring scheduled execution
- Integrations that are still being refined
**When to Migrate to Services:**
- Functionality becomes reusable across multiple domains
- The feature is stable and well-tested
- Multiple features or routes need the same functionality
- The logic should be part of the core service layer
**When to Migrate to Workflows:**
- The feature involves complex multi-step user interactions
- Task planning and adaptive learning are required
- The feature needs workflow orchestration capabilities
- User interactions require state management and progress tracking
---
## Features vs Services vs Workflows
Understanding the distinction between Features, Services, and Workflows is crucial for architectural decisions.
```mermaid
graph TB
subgraph "Comparison Matrix"
A[Route Request] --> B{What Type?}
B -->|Domain-Specific<br/>Single Use Case| C[Feature]
B -->|Reusable<br/>Cross-Cutting| D[Service]
B -->|Complex Multi-Step<br/>User Interaction| E[Workflow]
C --> F[Uses Services]
C --> G[Uses Interfaces]
D --> H[Uses Other Services]
D --> G
E --> D
E --> I[Uses Methods]
G --> J[Uses Connectors]
end
style C fill:#fff3e0,stroke:#e65100
style D fill:#e8f5e9,stroke:#1b5e20
style E fill:#e1f5ff,stroke:#01579b
style J fill:#fce4ec,stroke:#880e4f
```
| Aspect | Feature | Service | Workflow |
|--------|---------|---------|----------|
| **Purpose** | Domain-specific business logic | Cross-cutting, reusable functionality | Complex multi-step orchestration |
| **Scope** | Single use case or domain | Multiple use cases | User interaction flows |
| **Reusability** | Low (domain-specific) | High (cross-domain) | Medium (workflow patterns) |
| **State Management** | Stateless | Stateless | Stateful (workflow state) |
| **Dependencies** | Uses services and interfaces | Uses other services and interfaces | Uses services and methods |
| **Lifecycle** | Temporary, may migrate | Permanent core component | Permanent orchestration engine |
| **Examples** | Real Estate queries, Chat Althaus scheduler | AI processing, Document extraction | Chat workflows, Task planning |
### Decision Flow
```mermaid
flowchart TD
Start[New Functionality Required] --> Q1{Is it reusable<br/>across domains?}
Q1 -->|Yes| Service[Implement as Service]
Q1 -->|No| Q2{Does it require<br/>complex multi-step<br/>user interaction?}
Q2 -->|Yes| Workflow[Implement as Workflow]
Q2 -->|No| Q3{Is it domain-specific<br/>or experimental?}
Q3 -->|Yes| Feature[Implement as Feature]
Q3 -->|No| Service
Feature --> Q4{Feature Matures}
Q4 -->|Stable & Reusable| Service
Q4 -->|Complex Interactions| Workflow
Q4 -->|Still Experimental| Feature
style Feature fill:#fff3e0,stroke:#e65100
style Service fill:#e8f5e9,stroke:#1b5e20
style Workflow fill:#e1f5ff,stroke:#01579b
```
---
## Feature Architecture
### High-Level Architecture
```mermaid
graph TB
subgraph "Entry Point"
App[app.py<br/>FastAPI Application]
Lifecycle[Features Lifecycle<br/>featuresLifecycle.py]
end
subgraph "API Layer"
Routes[Routes<br/>routeRealEstate.py<br/>routeChatPlayground.py<br/>routeDataNeutralization.py]
end
subgraph "Feature Layer"
RE[Real Estate Feature<br/>mainRealEstate.py]
CA[Chat Althaus Feature<br/>mainChatAlthaus.py]
SD[Sync Delta Feature<br/>mainSyncDelta.py]
CP[Chat Playground Feature<br/>mainChatPlayground.py]
NP[Neutralize Playground Feature<br/>mainNeutralizePlayground.py]
end
subgraph "Service Layer"
Services[Services Container<br/>AI, Chat, SharePoint, etc.]
end
subgraph "Interface Layer"
Interfaces[Interfaces<br/>Database, Ticket, etc.]
end
subgraph "Connector Layer"
DBConn[Database Connector<br/>connectorDbPostgre.py]
TicketConn[Ticket Connectors<br/>connectorTicketsJira.py<br/>connectorTicketsClickup.py]
VoiceConn[Voice Connector<br/>connectorVoiceGoogle.py]
JsonConn[JSON Connector<br/>connectorDbJson.py]
end
subgraph "External Systems"
DB[(PostgreSQL Database)]
Jira[Jira API]
ClickUp[ClickUp API]
SharePoint[SharePoint API]
GoogleVoice[Google Voice API]
end
App --> Lifecycle
App --> Routes
Lifecycle --> CA
Lifecycle --> SD
Routes --> RE
Routes --> CP
Routes --> NP
RE --> Services
CA --> Services
SD --> Services
CP --> Services
NP --> Services
Services --> Interfaces
Interfaces --> DBConn
Interfaces --> TicketConn
Interfaces --> VoiceConn
Interfaces --> JsonConn
DBConn --> DB
TicketConn --> Jira
TicketConn --> ClickUp
VoiceConn --> GoogleVoice
Services --> SharePoint
style Features fill:#fff3e0,stroke:#e65100
style Connectors fill:#fce4ec,stroke:#880e4f
```
### Feature Request Flow
```mermaid
sequenceDiagram
participant Client
participant Route as Route<br/>routeRealEstate.py
participant Feature as Feature<br/>mainRealEstate.py
participant Service as Service<br/>Services Container
participant Interface as Interface<br/>interfaceDbRealEstateObjects.py
participant Connector as Connector<br/>connectorDbPostgre.py
participant DB as Database<br/>PostgreSQL
Client->>Route: HTTP Request
Route->>Route: Validate Request Data
Route->>Feature: Call Feature Function
Feature->>Service: Use Service (e.g., AI Service)
Service-->>Feature: Service Result
Feature->>Interface: Request Data Access
Interface->>Connector: Execute Query
Connector->>DB: SQL Query
DB-->>Connector: Raw Data
Connector-->>Interface: Raw Data
Interface->>Interface: Transform to Domain Objects
Interface-->>Feature: Domain Objects
Feature->>Feature: Process Business Logic
Feature-->>Route: Processed Result
Route->>Route: Serialize Response
Route-->>Client: HTTP Response
```
---
## Feature Lifecycle Management
Features that require background processing, scheduled tasks, or event-driven operations are managed through the **Features Lifecycle** system.
### Lifecycle Architecture
```mermaid
graph TB
subgraph "Application Startup"
App[app.py<br/>FastAPI Application]
Lifespan[Lifespan Context Manager]
end
subgraph "Features Lifecycle"
Lifecycle[featuresLifecycle.py]
Start[start function]
Stop[stop function]
end
subgraph "Background Features"
SyncDelta[SyncDelta Manager<br/>startSyncManager]
ChatAlthaus[ChatAlthaus Manager<br/>startDataScheduler]
AutomationEvents[Automation Events<br/>syncAutomationEvents]
end
App --> Lifespan
Lifespan -->|On Startup| Lifecycle
Lifecycle --> Start
Start --> SyncDelta
Start --> ChatAlthaus
Start --> AutomationEvents
Lifespan -->|On Shutdown| Lifecycle
Lifecycle --> Stop
Stop --> SyncDelta
Stop --> ChatAlthaus
style Lifecycle fill:#e8f5e9,stroke:#1b5e20
style SyncDelta fill:#fff3e0,stroke:#e65100
style ChatAlthaus fill:#fff3e0,stroke:#e65100
```
### Lifecycle Sequence
```mermaid
sequenceDiagram
participant App as app.py
participant Lifespan as Lifespan Manager
participant Lifecycle as featuresLifecycle
participant EventUser as Event User
participant SyncDelta as SyncDelta Manager
participant ChatAlthaus as ChatAlthaus Manager
App->>Lifespan: Application Startup
Lifespan->>Lifecycle: start()
Lifecycle->>EventUser: getRootInterface().getUserByUsername("event")
EventUser-->>Lifecycle: Event User Object
Lifecycle->>ChatAlthaus: syncAutomationEvents()
ChatAlthaus-->>Lifecycle: Events Synced
Lifecycle->>SyncDelta: startSyncManager(eventUser)
SyncDelta->>SyncDelta: Initialize Background Thread
SyncDelta-->>Lifecycle: Manager Started
Lifecycle->>ChatAlthaus: startDataScheduler(eventUser)
ChatAlthaus->>ChatAlthaus: Initialize Scheduler
ChatAlthaus-->>Lifecycle: Scheduler Started
Lifecycle->>ChatAlthaus: performDataUpdate(eventUser)
ChatAlthaus-->>Lifecycle: Initial Update Complete
Lifecycle-->>Lifespan: Startup Complete
Lifespan-->>App: Application Ready
Note over App: Application Running...
App->>Lifespan: Application Shutdown
Lifespan->>Lifecycle: stop()
Lifecycle->>SyncDelta: Stop Manager
Lifecycle->>ChatAlthaus: Stop Scheduler
Lifecycle-->>Lifespan: Shutdown Complete
```
### Lifecycle-Managed Features
Features managed through the lifecycle system include:
1. **SyncDelta**: Background synchronization manager for ticket synchronization
2. **ChatAlthaus**: Scheduled data updates for Althaus preprocessing service
3. **Automation Events**: Event synchronization for chat automation
These features run continuously in the background and require proper initialization and cleanup during application startup and shutdown.
---
## Connectors in the Architecture
Connectors are the lowest-level abstraction for communicating with external systems. They provide concrete implementations for database connections, API integrations, and external service communication.
### Connector Architecture
```mermaid
graph TB
subgraph "Connector Types"
DBConn[Database Connectors<br/>connectorDbPostgre.py<br/>connectorDbJson.py]
TicketConn[Ticket Connectors<br/>connectorTicketsJira.py<br/>connectorTicketsClickup.py]
VoiceConn[Voice Connectors<br/>connectorVoiceGoogle.py]
end
subgraph "Connector Responsibilities"
Connection[Connection Management<br/>Establish & Maintain Connections]
Query[Query Execution<br/>Execute Queries & API Calls]
Transform[Data Transformation<br/>Raw Data ↔ Application Format]
Error[Error Handling<br/>Connection Errors & Retries]
end
subgraph "External Systems"
PostgreSQL[(PostgreSQL Database)]
JSONFile[JSON Files]
JiraAPI[Jira API]
ClickUpAPI[ClickUp API]
GoogleVoiceAPI[Google Voice API]
end
DBConn --> Connection
TicketConn --> Connection
VoiceConn --> Connection
Connection --> Query
Query --> Transform
Transform --> Error
DBConn --> PostgreSQL
DBConn --> JSONFile
TicketConn --> JiraAPI
TicketConn --> ClickUpAPI
VoiceConn --> GoogleVoiceAPI
style DBConn fill:#fce4ec,stroke:#880e4f
style TicketConn fill:#fce4ec,stroke:#880e4f
style VoiceConn fill:#fce4ec,stroke:#880e4f
```
### Connector Usage Flow
```mermaid
sequenceDiagram
participant Feature as Feature
participant Service as Service
participant Interface as Interface
participant Connector as Connector
participant External as External System
Feature->>Service: Use Service
Service->>Interface: Request Data Access
Interface->>Connector: Initialize Connection
Connector->>External: Establish Connection
External-->>Connector: Connection Established
Interface->>Connector: Execute Query/API Call
Connector->>Connector: Format Request
Connector->>External: Send Request
External-->>Connector: Raw Response
Connector->>Connector: Parse Response
Connector-->>Interface: Formatted Data
Interface->>Interface: Transform to Domain Objects
Interface-->>Service: Domain Objects
Service-->>Feature: Processed Result
```
### Available Connectors
#### Database Connectors
**connectorDbPostgre.py** - PostgreSQL Database Connector
- Manages PostgreSQL database connections
- Executes SQL queries with parameterization
- Handles JSONB column types
- Provides transaction support
- Used by: Real Estate interfaces, Chat interfaces, Application interfaces
**connectorDbJson.py** - JSON File Database Connector
- Provides file-based data storage using JSON
- Useful for development and testing
- Lightweight alternative to PostgreSQL
- Used by: Development environments, Testing scenarios
#### Ticket Connectors
**connectorTicketsJira.py** - Jira Ticket Connector
- Integrates with Jira REST API
- Manages Jira tickets, issues, and projects
- Handles field mapping and synchronization
- Used by: SyncDelta feature, Ticket interfaces
**connectorTicketsClickup.py** - ClickUp Ticket Connector
- Integrates with ClickUp API
- Manages ClickUp tasks and lists
- Handles task synchronization
- Used by: Ticket interfaces
#### Voice Connectors
**connectorVoiceGoogle.py** - Google Voice Connector
- Integrates with Google Voice API
- Handles voice transcription and processing
- Manages voice data and audio files
- Used by: Voice-related services and features
### Connector Integration Pattern
Connectors are never directly accessed by features. Instead, they follow this integration pattern:
```mermaid
graph LR
A[Feature] --> B[Service]
B --> C[Interface]
C --> D[Connector]
D --> E[External System]
style A fill:#fff3e0,stroke:#e65100
style B fill:#e8f5e9,stroke:#1b5e20
style C fill:#e1f5ff,stroke:#01579b
style D fill:#fce4ec,stroke:#880e4f
style E fill:#f5f5f5,stroke:#424242
```
**Why This Pattern?**
- **Abstraction**: Interfaces hide connector implementation details
- **Flexibility**: Connectors can be swapped without affecting features
- **Testability**: Interfaces can be mocked for testing
- **Consistency**: All data access follows the same pattern
- **User Context**: Interfaces handle user context and access control
---
## Individual Features
### Real Estate Feature
**Location**: `modules/features/realEstate/mainRealEstate.py`
**Purpose**: Provides AI-powered natural language processing for Real Estate database operations. Enables users to interact with Real Estate data using natural language commands that are translated into CRUD operations.
**Architecture**:
```mermaid
graph TB
subgraph "Real Estate Feature"
Route[routeRealEstate.py]
Feature[mainRealEstate.py]
Intent[Intent Analysis<br/>analyzeUserIntent]
CRUD[CRUD Operations<br/>executeIntentBasedOperation]
Query[Direct Queries<br/>executeDirectQuery]
end
subgraph "Dependencies"
AIService[AI Service<br/>Intent Recognition]
REInterface[Real Estate Interface<br/>interfaceDbRealEstateObjects.py]
DBConnector[Database Connector<br/>connectorDbPostgre.py]
end
subgraph "Data Models"
REModels[Real Estate Models<br/>Projekt, Parzelle, etc.]
end
Route --> Feature
Feature --> Intent
Feature --> CRUD
Feature --> Query
Intent --> AIService
CRUD --> REInterface
Query --> REInterface
REInterface --> DBConnector
REInterface --> REModels
style Feature fill:#fff3e0,stroke:#e65100
```
**Key Functions**:
- `processNaturalLanguageCommand()`: Main entry point for natural language processing
- `analyzeUserIntent()`: Uses AI to analyze user input and extract intent, entity, and parameters
- `executeIntentBasedOperation()`: Executes CRUD operations based on analyzed intent
- `executeDirectQuery()`: Executes direct SQL queries without AI processing
**Connector Usage**:
- Uses **Database Connector** (`connectorDbPostgre.py`) through the Real Estate Interface
- Accesses PostgreSQL database for Real Estate data
- Handles CRUD operations on entities like Projekt, Parzelle, Dokument
**Service Integration**:
- Uses **AI Service** for intent recognition and natural language understanding
- Leverages AI planning capabilities to analyze user commands
**Migration Path**:
- May evolve into a **Service** if Real Estate operations become reusable across domains
- Could integrate with **Workflows** for complex multi-step Real Estate processes
---
### Chat Althaus Feature
**Location**: `modules/features/chatAlthaus/mainChatAlthaus.py`
**Purpose**: Manages scheduled data updates for the Althaus preprocessing service. Triggers daily updates to synchronize database configuration with external preprocessing service.
**Architecture**:
```mermaid
graph TB
subgraph "Chat Althaus Feature"
Lifecycle[featuresLifecycle.py]
Manager[ManagerChatAlthaus]
Scheduler[Data Scheduler]
Updater[Data Updater<br/>updateDatabaseWithConfig]
end
subgraph "Dependencies"
Services[Services Container]
HTTPClient[HTTP Client<br/>aiohttp]
Config[Configuration<br/>APP_CONFIG]
end
subgraph "External System"
AlthausAPI[Althaus Preprocessing API<br/>Azure Function]
end
Lifecycle --> Manager
Manager --> Scheduler
Manager --> Updater
Updater --> Services
Updater --> HTTPClient
Updater --> Config
Updater --> AlthausAPI
style Manager fill:#fff3e0,stroke:#e65100
```
**Key Functions**:
- `startDataScheduler()`: Initializes and starts the scheduled data update manager
- `performDataUpdate()`: Executes immediate data update
- `updateDatabaseWithConfig()`: Sends configuration to Althaus preprocessing service
**Scheduling**:
- Runs daily at 01:00 UTC
- Uses background scheduler for automated execution
- Managed through Features Lifecycle system
**Connector Usage**:
- Uses **HTTP Client** (aiohttp) for API communication
- No database connector (uses external API)
**Service Integration**:
- Uses **Services Container** for configuration access
- Leverages shared configuration utilities
**Migration Path**:
- Could become a **Service** if data synchronization becomes a core capability
- May integrate with **Workflows** for complex data processing pipelines
---
### Sync Delta Feature
**Location**: `modules/features/syncDelta/mainSyncDelta.py`
**Purpose**: Synchronizes tickets between Jira and SharePoint. Manages bidirectional synchronization of ticket data, supporting both CSV and Excel file formats.
**Architecture**:
```mermaid
graph TB
subgraph "Sync Delta Feature"
Lifecycle[featuresLifecycle.py]
Manager[ManagerSyncDelta]
Sync[syncTicketsOverSharepoint]
Merge[Data Merging Logic]
Audit[Audit Logging]
end
subgraph "Dependencies"
TicketService[Ticket Service]
SharePointService[SharePoint Service]
JiraConnector[Jira Connector<br/>connectorTicketsJira.py]
end
subgraph "External Systems"
Jira[Jira API]
SharePoint[SharePoint API]
end
Lifecycle --> Manager
Manager --> Sync
Sync --> Merge
Sync --> Audit
Sync --> TicketService
Sync --> SharePointService
TicketService --> JiraConnector
JiraConnector --> Jira
SharePointService --> SharePoint
style Manager fill:#fff3e0,stroke:#e65100
```
**Key Functions**:
- `startSyncManager()`: Initializes background synchronization manager
- `syncTicketsOverSharepoint()`: Performs synchronization between Jira and SharePoint
- `initializeInterface()`: Sets up connectors and validates connections
- `_logAuditEvent()`: Logs synchronization events for auditing
**Synchronization Modes**:
- **CSV Mode**: Uses CSV files for data exchange
- **Excel Mode**: Uses Excel (.xlsx) files for data exchange
**Connector Usage**:
- Uses **Jira Connector** (`connectorTicketsJira.py`) through Ticket Service
- Uses **SharePoint Service** for file operations
- Manages field mapping between Jira and SharePoint formats
**Service Integration**:
- Uses **Ticket Service** for ticket interface creation
- Uses **SharePoint Service** for file upload/download
- Leverages **Services Container** for configuration and utilities
**Migration Path**:
- Likely candidate for **Service** migration as ticket synchronization becomes core functionality
- Could integrate with **Workflows** for complex synchronization scenarios
---
### Chat Playground Feature
**Location**: `modules/features/chatPlayground/mainChatPlayground.py`
**Purpose**: Provides entry point for chat workflow functionality. Acts as a thin wrapper around the WorkflowManager for chat-based interactions.
**Architecture**:
```mermaid
graph TB
subgraph "Chat Playground Feature"
Route[routeChatPlayground.py]
Feature[mainChatPlayground.py]
Start[chatStart]
Stop[chatStop]
end
subgraph "Workflow System"
WorkflowManager[WorkflowManager]
WorkflowProcessor[WorkflowProcessor]
Methods[Workflow Methods]
end
subgraph "Dependencies"
Services[Services Container]
end
Route --> Feature
Feature --> Start
Feature --> Stop
Start --> WorkflowManager
Stop --> WorkflowManager
WorkflowManager --> WorkflowProcessor
WorkflowProcessor --> Methods
WorkflowManager --> Services
style Feature fill:#fff3e0,stroke:#e65100
style WorkflowManager fill:#e1f5ff,stroke:#01579b
```
**Key Functions**:
- `chatStart()`: Starts a new chat workflow or continues an existing one
- `chatStop()`: Stops a running chat workflow
**Relationship to Workflows**:
- This feature is a **bridge** between routes and the workflow system
- Delegates all processing to WorkflowManager
- Demonstrates how features can integrate with workflows
**Connector Usage**:
- No direct connector usage (delegates to workflows)
- Workflows use connectors through services and methods
**Service Integration**:
- Uses **Services Container** for workflow management
- Leverages workflow services for chat operations
**Migration Path**:
- Already integrated with **Workflows** system
- May be simplified or removed as workflows become the primary interface
---
### Neutralize Playground Feature
**Location**: `modules/features/neutralizePlayground/mainNeutralizePlayground.py`
**Purpose**: Provides a playground interface for data neutralization functionality. Wraps the Neutralization Service for testing and experimentation.
**Architecture**:
```mermaid
graph TB
subgraph "Neutralize Playground Feature"
Route[routeDataNeutralization.py]
Feature[NeutralizationPlayground]
ProcessText[processText]
ProcessFiles[processFiles]
CleanAttributes[cleanAttributes]
Stats[getStats]
Config[getConfig/saveConfig]
end
subgraph "Dependencies"
NeutralizationService[Neutralization Service]
end
Route --> Feature
Feature --> ProcessText
Feature --> ProcessFiles
Feature --> CleanAttributes
Feature --> Stats
Feature --> Config
ProcessText --> NeutralizationService
ProcessFiles --> NeutralizationService
CleanAttributes --> NeutralizationService
Stats --> NeutralizationService
Config --> NeutralizationService
style Feature fill:#fff3e0,stroke:#e65100
style NeutralizationService fill:#e8f5e9,stroke:#1b5e20
```
**Key Functions**:
- `processText()`: Processes text for data neutralization
- `processFiles()`: Processes files for data neutralization
- `cleanAttributes()`: Cleans neutralization attributes
- `getStats()`: Retrieves neutralization statistics
- `getConfig()` / `saveConfig()`: Manages neutralization configuration
**Purpose as Playground**:
- Provides testing interface for neutralization functionality
- Allows experimentation with neutralization patterns
- Demonstrates service usage patterns
**Connector Usage**:
- No direct connector usage (uses Neutralization Service)
- Service handles all data access internally
**Service Integration**:
- Wraps **Neutralization Service** for easy access
- Provides playground-specific functionality
**Migration Path**:
- May be removed once neutralization is fully integrated
- Functionality may move directly to routes using the service
---
## Feature Patterns and Best Practices
### Pattern 1: Stateless Feature Design
Features should be stateless and operate without session management. Each request should be independent and self-contained.
```mermaid
graph LR
A[Request] --> B[Feature Function]
B --> C[Process Request]
C --> D[Return Result]
style B fill:#fff3e0,stroke:#e65100
```
**Benefits**:
- Simpler implementation
- Better scalability
- Easier testing
- No state management overhead
### Pattern 2: Service Delegation
Features should delegate cross-cutting functionality to services rather than implementing it directly.
```mermaid
graph TB
A[Feature] --> B{Needs Functionality}
B -->|AI Processing| C[AI Service]
B -->|Data Access| D[Interface]
B -->|File Operations| E[File Service]
B -->|Other| F[Other Services]
style A fill:#fff3e0,stroke:#e65100
style C fill:#e8f5e9,stroke:#1b5e20
style D fill:#e1f5ff,stroke:#01579b
```
**Benefits**:
- Code reuse
- Consistent behavior
- Easier maintenance
- Better separation of concerns
### Pattern 3: Interface Abstraction
Features should never directly access connectors. All data access should go through interfaces.
```mermaid
graph LR
A[Feature] --> B[Interface]
B --> C[Connector]
C --> D[External System]
style A fill:#fff3e0,stroke:#e65100
style B fill:#e1f5ff,stroke:#01579b
style C fill:#fce4ec,stroke:#880e4f
```
**Benefits**:
- Abstraction of implementation details
- Flexibility to change connectors
- Consistent data access patterns
- User context handling
### Pattern 4: Background Processing
Features requiring background processing should use the Features Lifecycle system.
```mermaid
sequenceDiagram
participant App as Application
participant Lifecycle as Features Lifecycle
participant Feature as Background Feature
participant Scheduler as Scheduler
App->>Lifecycle: Startup
Lifecycle->>Feature: Initialize Manager
Feature->>Scheduler: Start Background Task
Scheduler-->>Feature: Task Running
Note over Feature,Scheduler: Background Processing...
App->>Lifecycle: Shutdown
Lifecycle->>Feature: Stop Manager
Feature->>Scheduler: Stop Background Task
Scheduler-->>Feature: Task Stopped
```
**Benefits**:
- Proper lifecycle management
- Clean startup/shutdown
- Resource management
- Error handling
### Pattern 5: Migration Planning
Features should be designed with migration in mind. Consider future migration to services or workflows during design.
```mermaid
graph LR
A[Feature Design] --> B{Consider Migration}
B -->|Reusable Logic| C[Design as Service]
B -->|Complex Flow| D[Design for Workflow]
B -->|Temporary| E[Keep as Feature]
style A fill:#fff3e0,stroke:#e65100
style C fill:#e8f5e9,stroke:#1b5e20
style D fill:#e1f5ff,stroke:#01579b
```
**Best Practices**:
- Document migration path
- Keep dependencies minimal
- Use standard patterns
- Plan for refactoring
---
## Summary
The Features component provides a flexible, domain-specific business logic layer that enables rapid development while maintaining architectural boundaries. Features serve as temporary solutions that bridge the gap between initial requirements and full service or workflow implementation.
**Key Takeaways**:
1. **Features are Temporary**: Designed to be migrated to services or workflows as they mature
2. **Domain-Specific**: Each feature addresses a specific business domain or use case
3. **Service-Dependent**: Features leverage services for cross-cutting functionality
4. **Interface-Abstracted**: Features access data through interfaces, never directly through connectors
5. **Lifecycle-Managed**: Background features are managed through the Features Lifecycle system
6. **Connector Integration**: Connectors are accessed through interfaces, providing abstraction and flexibility
The architecture supports a natural evolution path from features to services or workflows, ensuring that the codebase remains maintainable and scalable as functionality matures.

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,509 +0,0 @@
# Security API Documentation
API documentation for security-related endpoints and how to use security components in routes.
## Table of Contents
1. [Overview](#overview)
2. [Authentication Endpoints](#authentication-endpoints)
3. [Authentication Flows](#authentication-flows)
4. [Using Security in Routes](#using-security-in-routes)
5. [API Examples](#api-examples)
## Overview
The Security component provides authentication endpoints and utilities that routes can use to protect their endpoints and access user context. This document focuses on the API surface and how to use security components from route handlers.
For detailed information about the Security component architecture and internal workings, see [Security Component Documentation](./security-component.md).
## Authentication Endpoints
### Local Authentication
**Base Path**: `/api/local`
#### POST `/api/local/login`
Authenticate with username and password.
**Request**:
- Content-Type: `application/x-www-form-urlencoded`
- Headers: `X-CSRF-Token` (required)
- Body: `username`, `password` (form data)
**Response**:
- Status: `200 OK`
- Cookies: `auth_token` (httpOnly), `refresh_token` (httpOnly)
- Body:
```json
{
"type": "local_auth_success",
"message": "Login successful - tokens set in httpOnly cookies",
"authenticationAuthority": "local",
"expires_at": "2024-01-01T12:00:00"
}
```
**Rate Limit**: 30 requests per minute
#### POST `/api/local/register`
Register a new user account.
**Request**:
- Content-Type: `application/json`
- Body: User object + password
**Response**: User object
**Rate Limit**: 10 requests per minute
#### GET `/api/local/me`
Get current authenticated user information.
**Request**:
- Headers: `Authorization: Bearer <token>` OR Cookie: `auth_token`
**Response**: User object
**Rate Limit**: 30 requests per minute
#### POST `/api/local/refresh`
Refresh access token using refresh token.
**Request**:
- Cookie: `refresh_token` (httpOnly)
**Response**:
- Cookies: New `auth_token` and `refresh_token`
- Body: Token refresh response
**Rate Limit**: 60 requests per minute
#### POST `/api/local/logout`
Logout current user and invalidate tokens.
**Request**:
- Headers: `Authorization: Bearer <token>` OR Cookie: `auth_token`
**Response**: Logout confirmation
**Rate Limit**: 10 requests per minute
### Microsoft OAuth Authentication
**Base Path**: `/api/msft`
#### GET `/api/msft/login`
Initiate Microsoft OAuth login flow.
**Response**: Redirects to Microsoft OAuth login page
#### GET `/api/msft/auth/callback`
OAuth callback endpoint (handled by Microsoft).
**Query Parameters**:
- `code`: Authorization code from Microsoft
- `state`: State parameter for CSRF protection
**Response**: HTML page that sets cookies and redirects
#### GET `/api/msft/me`
Get current authenticated user information.
**Request**:
- Headers: `Authorization: Bearer <token>` OR Cookie: `auth_token`
**Response**: User object
#### POST `/api/msft/logout`
Logout current user.
**Request**:
- Headers: `Authorization: Bearer <token>` OR Cookie: `auth_token`
**Response**: Logout confirmation
### Google OAuth Authentication
**Base Path**: `/api/google`
#### GET `/api/google/login`
Initiate Google OAuth login flow.
**Query Parameters**:
- `state`: Optional state parameter (default: "login")
- `connectionId`: Optional connection ID for connection flow
**Response**: Redirects to Google OAuth login page
#### GET `/api/google/auth/callback`
OAuth callback endpoint (handled by Google).
**Query Parameters**:
- `code`: Authorization code from Google
- `state`: State parameter for CSRF protection
**Response**: HTML page that sets cookies and redirects
#### GET `/api/google/me`
Get current authenticated user information.
**Request**:
- Headers: `Authorization: Bearer <token>` OR Cookie: `auth_token`
**Response**: User object
#### POST `/api/google/logout`
Logout current user.
**Request**:
- Headers: `Authorization: Bearer <token>` OR Cookie: `auth_token`
**Response**: Logout confirmation
## Authentication Flows
### Login Flow (Local Authentication)
```mermaid
sequenceDiagram
participant Client
participant Route as Login Route<br/>POST /api/local/login
participant Auth as auth.py
participant JWT as jwtService.py
participant Interface as Interface Layer
participant DB as Database
Client->>Route: POST /api/local/login<br/>(username, password, X-CSRF-Token)
Route->>Route: Validate CSRF Token
Route->>Interface: authenticateLocalUser(username, password)
Interface->>DB: Query User & Verify Password
DB-->>Interface: User Record
alt Invalid Credentials
Interface-->>Route: None
Route-->>Client: HTTPException 401
end
Route->>JWT: createAccessToken(userData)
JWT->>JWT: Generate JTI (UUID)
JWT->>JWT: Set Expiration
JWT->>JWT: Sign JWT
JWT-->>Route: Access Token + Expires At
Route->>JWT: createRefreshToken(userData)
JWT-->>Route: Refresh Token + Expires At
Route->>Interface: Save Token to DB<br/>(for LOCAL authority)
Interface->>DB: Insert Token Record
Route->>JWT: setAccessTokenCookie(response, token)
JWT->>JWT: Set httpOnly Cookie<br/>(secure, samesite=strict)
Route->>JWT: setRefreshTokenCookie(response, token)
JWT->>JWT: Set httpOnly Cookie
Route-->>Client: HTTP Response<br/>(with Cookies)
```
### OAuth Flow (Microsoft/Google)
```mermaid
sequenceDiagram
participant Client
participant Route as OAuth Route<br/>GET /api/{provider}/login
participant Provider as OAuth Provider<br/>(MSFT/Google)
participant JWT as jwtService.py
participant Interface as Interface Layer
participant DB as Database
Client->>Route: GET /api/{provider}/login
Route->>Route: Generate OAuth State
Route->>Provider: Redirect to OAuth URL<br/>(with state, client_id, redirect_uri)
Provider-->>Client: OAuth Login Page
Client->>Provider: User Authenticates
Provider->>Route: GET /api/{provider}/callback<br/>(code, state)
Route->>Route: Validate State
Route->>Provider: Exchange Code for Tokens<br/>(POST /token)
Provider-->>Route: Access Token + Refresh Token
Route->>Provider: Get User Info<br/>(using Access Token)
Provider-->>Route: User Profile Data
Route->>Interface: Find/Create User<br/>(by external ID)
Interface->>DB: Query/Create User
DB-->>Interface: User Record
Interface-->>Route: User Object
Route->>Interface: Save/Create Connection
Interface->>DB: Save Connection Record
Route->>Interface: Save Token
Interface->>DB: Save Token Record
Route->>JWT: createAccessToken(userData)
JWT-->>Route: Gateway JWT Token
Route->>JWT: setAccessTokenCookie(response, token)
Route->>JWT: setRefreshTokenCookie(response, token)
Route-->>Client: HTTP Response<br/>(with Gateway Cookies)
```
## Using Security in Routes
### Basic Authentication Pattern
All protected routes use the `getCurrentUser` dependency to access the authenticated user:
```python
from fastapi import APIRouter, Depends
from modules.security.auth import getCurrentUser
from modules.datamodels.datamodelUam import User
router = APIRouter(prefix="/api/example", tags=["Example"])
@router.get("/protected")
async def protected_endpoint(
currentUser: User = Depends(getCurrentUser)
) -> dict:
"""
Protected endpoint that requires authentication.
The currentUser parameter is automatically populated by getCurrentUser.
"""
return {
"message": f"Hello, {currentUser.username}!",
"userId": currentUser.id,
"mandateId": currentUser.mandateId
}
```
### Rate Limiting
Use the `limiter` from the security module to add rate limiting:
```python
from modules.security.auth import getCurrentUser, limiter
from fastapi import Request
@router.post("/action")
@limiter.limit("30/minute")
async def rate_limited_endpoint(
request: Request,
currentUser: User = Depends(getCurrentUser)
) -> dict:
"""Endpoint with rate limiting (30 requests per minute)"""
return {"status": "success"}
```
### Cookie vs Header Authentication
The security component supports both authentication methods:
1. **Cookie-based** (preferred for web apps):
- Tokens are automatically sent via httpOnly cookies
- More secure (not accessible via JavaScript)
- Automatically included in requests from same origin
2. **Header-based** (for API clients):
- Use `Authorization: Bearer <token>` header
- Required for programmatic API access
- Tokens can be obtained from login endpoints
The `CookieAuth` class checks cookies first, then falls back to headers.
### Creating Tokens in Routes
When implementing custom authentication endpoints, use the JWT service:
```python
from modules.security.jwtService import (
createAccessToken,
createRefreshToken,
setAccessTokenCookie,
setRefreshTokenCookie
)
from modules.datamodels.datamodelUam import AuthAuthority
@router.post("/custom-login")
async def custom_login(
response: Response,
username: str,
password: str
):
# Verify credentials...
user = verify_user(username, password)
# Create token data
token_data = {
"sub": user.username,
"mandateId": str(user.mandateId),
"userId": str(user.id),
"authenticationAuthority": AuthAuthority.LOCAL
}
# Create tokens
access_token, expires_at = createAccessToken(token_data)
refresh_token, _ = createRefreshToken(token_data)
# Set cookies
setAccessTokenCookie(response, access_token)
setRefreshTokenCookie(response, refresh_token)
return {"status": "success", "expires_at": expires_at.isoformat()}
```
### Clearing Tokens (Logout)
Use the JWT service cookie clearing functions:
```python
from modules.security.jwtService import (
clearAccessTokenCookie,
clearRefreshTokenCookie
)
@router.post("/logout")
async def logout(
response: Response,
currentUser: User = Depends(getCurrentUser)
):
# Clear cookies
clearAccessTokenCookie(response)
clearRefreshTokenCookie(response)
# Optionally revoke token in database
# interface.revokeToken(tokenId)
return {"status": "logged_out"}
```
## API Examples
### Example: Protected Endpoint
```python
from fastapi import APIRouter, Depends, HTTPException
from modules.security.auth import getCurrentUser, limiter
from modules.datamodels.datamodelUam import User
from fastapi import Request
router = APIRouter(prefix="/api/data", tags=["Data"])
@router.get("/items")
@limiter.limit("60/minute")
async def get_items(
request: Request,
currentUser: User = Depends(getCurrentUser)
) -> list:
"""
Get items for the current user.
Requires authentication.
"""
# User is guaranteed to be authenticated and enabled
# Access user properties: currentUser.id, currentUser.mandateId, etc.
items = fetch_user_items(currentUser.id)
return items
```
### Example: Role-Based Access
```python
from modules.datamodels.datamodelUam import UserPrivilege
@router.delete("/admin/items/{item_id}")
async def delete_item(
item_id: str,
currentUser: User = Depends(getCurrentUser)
):
"""
Delete item (admin only).
"""
# Check user privilege
if currentUser.privilege not in [UserPrivilege.ADMIN, UserPrivilege.SYSADMIN]:
raise HTTPException(
status_code=403,
detail="Admin access required"
)
delete_item_by_id(item_id)
return {"status": "deleted"}
```
### Example: Mandate-Scoped Access
```python
@router.get("/mandate/data")
async def get_mandate_data(
currentUser: User = Depends(getCurrentUser)
):
"""
Get data scoped to user's mandate.
"""
# User's mandateId is automatically validated during authentication
# Token context must match user's current mandate
data = fetch_mandate_data(currentUser.mandateId)
return data
```
### Example: CSRF Protection
For state-changing operations, ensure CSRF token is included:
```python
@router.post("/update")
async def update_data(
request: Request,
data: dict,
currentUser: User = Depends(getCurrentUser)
):
"""
Update data (requires CSRF token).
CSRF middleware automatically validates X-CSRF-Token header.
"""
# CSRF validation happens automatically via middleware
# Just ensure client sends X-CSRF-Token header
update_user_data(currentUser.id, data)
return {"status": "updated"}
```
### Example: Error Handling
```python
from fastapi import HTTPException, status
@router.get("/sensitive")
async def get_sensitive_data(
currentUser: User = Depends(getCurrentUser)
):
"""
Get sensitive data with proper error handling.
"""
try:
# getCurrentUser already validates:
# - Token is valid and not expired
# - User exists and is enabled
# - Context matches (mandateId, userId)
data = fetch_sensitive_data(currentUser.id)
return data
except ValueError as e:
# Handle business logic errors
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=str(e)
)
```
## Related Documentation
- [Security Component Documentation](./security-component.md) - Component architecture and internal workings
- [Architecture Overview](./architecture-overview.md) - Overall system architecture

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,786 +0,0 @@
# Chat Playground Page Requirements
This document contains the complete frontend requirements for the chat playground page and workflow management components. All UI components are dynamically generated from backend metadata—no hardcoding required.
## Table of Contents
1. [Overview](#overview)
2. [Page Structure and Layout](#page-structure-and-layout)
3. [User Interactions and Functionality](#user-interactions-and-functionality)
4. [Backend Routes and API Integration](#backend-routes-and-api-integration)
5. [Field and Attribute Reference](#field-and-attribute-reference)
6. [Dynamic Rendering Guidelines](#dynamic-rendering-guidelines)
---
## Overview
The chat playground page enables users to create, manage, and track AI-powered workflows that process user requests through task planning and action execution. The frontend consists of a single page (`/chat-playground` or `/workflows/playground`) with different views/states:
- **Input View** - Start new workflows or continue existing ones with prompt input, mode selection, and file attachments
- **Workflow View** - Live tracking of workflow execution with messages, logs, and statistics
- **Workflow History View** - View completed workflows with full message history
All views use backend-driven UI generation, meaning field definitions, labels, validation rules, and UI structure come entirely from backend metadata through the `/api/attributes/ChatWorkflow` and `/api/attributes/UserInputRequest` endpoints. Views are managed through component state and routing within the same page, not as separate routes.
**Note:** Workflows are user-scoped. Users can only see and manage their own workflows. The backend enforces this security.
---
## Page Structure and Layout
### Chat Playground Page (`/chat-playground` or `/workflows/playground`)
The chat playground page uses different views/states to handle different user interactions. Views are managed through component state and routing within the same page component.
### Input View
**State:** `view === 'input'` or `selectedWorkflowId === null` (starting new workflow)
**What the user sees:**
- **Main Content Area:**
- Chat input form with the following components:
- **Workflow Dropdown** - Select previous workflow to continue (optional, shows "New Workflow" by default)
- **Prompt Dropdown** - Select saved prompt template (optional)
- **Prompt Text Input** - Multi-line text area for user input (required)
- **Workflow Mode Selector** - Radio buttons or tabs for Actionplan, Dynamic, or Template (required)
- **Neutralization Toggle** - Checkbox/toggle to enable/disable data neutralization (optional)
- **File Attachment Area** - Drop zone with drag-and-drop support, plus "Attach File" button and "Browse Files" button
- **Action Buttons:**
- "Start Workflow" button (when no workflow selected)
- "Continue Workflow" or "Send" button (when workflow selected)
- **File Attachment Display:**
- List of attached files with preview (name, size, type)
- Remove button for each attached file
- Visual feedback for drag-and-drop (highlight, border, overlay when dragging)
- **Workflow Context Display** (when workflow selected):
- Previous messages from selected workflow displayed in chat view
- Workflow status indicator
- Workflow mode pre-selected from selected workflow
### Workflow View
**State:** `view === 'workflow'` and `selectedWorkflowId !== null` (active workflow tracking)
**What the user sees:**
- **Main Content Area:**
- **Chat Interface:**
- Message history displayed chronologically
- User messages and assistant responses
- File attachments displayed as part of each message
- Each file attachment shows:
- File name, size, and type/icon
- Action buttons: "Show", "Download", "Delete"
- File preview (if applicable) when "Show" is clicked
- Auto-scroll to latest message (optional, user can disable)
- **Log Panel** (optional, can be toggled):
- Execution logs displayed chronologically
- Log level indicators (info, warning, error)
- Timestamps for each log entry
- **Statistics Panel** (optional, can be toggled):
- Performance metrics
- Task completion status
- Execution time
- **Workflow Status Indicator:**
- Current workflow status (running, completed, stopped, failed)
- Visual status badge with color coding
- Neutralization indicator (if enabled)
- **Action Buttons:**
- "Stop" button (when workflow is running)
- "Delete Message" button (on individual messages)
- **File Action Buttons** (on each file attachment in messages):
- "Show" button - Opens file preview/viewer
- "Download" button - Downloads file to user's device
- "Delete" button - Removes file from message (with confirmation)
- "Back to Input" button (return to input view)
- **Live Updates:**
- Real-time polling for new messages, logs, and statistics
- Visual indicators for new content
- Automatic UI updates without page refresh
---
## User Interactions and Functionality
### Starting a New Workflow
**Workflow Selection:**
- User sees workflow dropdown with "New Workflow" as default option
- Dropdown shows list of previous workflows (name, status, last activity)
- Selecting "New Workflow" clears any selected workflow context
- Selecting a previous workflow loads its context (messages, mode)
**Prompt Selection:**
- User can optionally select a saved prompt from dropdown
- Selecting a prompt pre-fills the prompt text field
- User can still edit the pre-filled text
- Prompt selection is optional
**Workflow Mode Selection:**
- User must select one of three modes:
- **Actionplan** - Traditional task planning (shows description on selection)
- **Dynamic** - Iterative dynamic-style processing (shows description on selection)
- **Template** - Template-based processing (shows description on selection)
- Mode selection is required before starting workflow
- Visual indicator shows selected mode
**Neutralization Toggle:**
- User can toggle neutralization on/off
- Frontend checks neutralization config status
- If config exists and enabled, neutralization is enabled for workflow
- If config disabled or not found, neutralization is disabled
- User can configure neutralization settings on separate settings page
- Toggle shows current state (enabled/disabled indicator)
**File Attachment:**
- **Drag and Drop:**
- User drags files over drop zone
- Visual feedback shown (highlight, border, overlay)
- User drops files onto drop zone
- Files processed and uploaded automatically
- File preview shown immediately
- **Button Upload:**
- User clicks "Attach File" or "Upload File" button
- File picker dialog opens
- User selects files from device
- Files uploaded and preview shown
- **Browse Existing Files:**
- User clicks "Browse Files" or "Select File" button
- File browser/selector opens with paginated file list
- User selects existing files
- Selected files added to attachment list
- **File Management:**
- Attached files shown in list with name, size, type
- Remove button for each file
- Multiple files can be attached
- Files validated before upload (size limits, type restrictions)
**Form Validation:**
- Required fields: prompt text, workflow mode
- Optional fields: prompt selection, neutralization, files
- Validation errors shown inline
- Form cannot be submitted until required fields are filled
**Workflow Submission:**
- User clicks "Start Workflow" button
- Form validates (required fields, types, workflowMode)
- If validation fails, show errors
- If validation passes:
- Build UserInputRequest with prompt, listFileId (if files attached), userLanguage
- Show loading state
- Submit to `/api/chat/playground/start` with workflowMode query param
- On success: Navigate to workflow view, start polling
- On error: Show error message, revert optimistic updates
### Continuing an Existing Workflow
**Workflow Selection:**
- User selects previous workflow from dropdown
- Frontend loads workflow data via `GET /api/workflows/workflowId`
- Previous messages displayed in chat view
- Workflow mode pre-selected from selected workflow
- Selected workflow name/ID shown
**Additional Input:**
- User can optionally select a prompt (pre-fills text)
- User enters or edits prompt text
- User can toggle neutralization
- User can attach files (same methods as starting new workflow)
**Workflow Continuation:**
- User clicks "Continue" or "Send" button
- Form validates (required fields)
- If validation passes:
- Build UserInputRequest with prompt, listFileId (if files attached)
- Show optimistic update (add user message to UI)
- Submit to `/api/chat/playground/start` with workflowId and workflowMode query params
- On success: Continue polling, update workflow view
- On error: Revert optimistic update, show error
### Live Tracking Workflow Progress
**Polling Mechanism:**
- Start polling when workflow view is active
- Poll interval: every 2 seconds (configurable)
- Poll endpoint: `GET /api/chat/playground/{workflowId}/chatData`
- Use `afterTimestamp` query param for selective data transfer
**Data Updates:**
- Compare new data with existing data
- If new data available:
- Append new messages to chat view
- Append new logs to log panel
- Update statistics display
- Update workflow status indicator
- Scroll to latest content (if auto-scroll enabled)
- If no new data, continue polling silently
**Polling Control:**
- Stop polling when workflow status is "completed", "stopped", or "failed"
- Stop polling when user navigates away
- Show final status when workflow completes
- Handle errors gracefully (404 stops polling, shows error)
**Visual Feedback:**
- Loading indicators during polling
- New content indicators
- Status change animations
- Progress indicators for long-running workflows
### Stopping a Running Workflow
**Stop Action:**
- User clicks "Stop" button (only visible when workflow is running)
- Confirmation dialog appears: "Stop this workflow?"
- User can cancel or confirm
**Stop Submission:**
- If user confirms:
- Show optimistic update (status to "stopping")
- Submit to `POST /api/chat/playground/{workflowId}/stop`
- On success: Stop polling, update UI with stopped status
- On error: Revert optimistic update, show error
### Viewing Files in Messages
**Show File:**
- User clicks "Show" button on file attachment in message
- Frontend fetches file data via `GET /api/files/{fileId}/download` or preview endpoint
- File preview/viewer opens (modal, sidebar, or inline)
- Preview supports different file types:
- Images → Display image viewer
- PDFs → Display PDF viewer
- Text files → Display text content
- Other types → Show file info or download prompt
- User can close preview to return to message view
**Download File:**
- User clicks "Download" button on file attachment in message
- Frontend triggers download via `GET /api/files/{fileId}/download`
- Browser automatically downloads file with proper filename
- File name properly encoded for Unicode characters
- Handle 403 (permission denied) and 404 (file not found) errors
### Deleting Context from a Workflow
**Delete Message:**
- User clicks "Delete" button on message
- Confirmation dialog: "Delete this message? This will remove it from the workflow context."
- If user confirms:
- Show optimistic update (remove message from UI)
- Submit to `DELETE /api/workflows/{workflowId}/messages/{messageId}`
- On success: Keep optimistic update, refresh workflow data
- On error: Revert optimistic update, show error
**Delete File from Message:**
- User clicks "Delete" button on file attachment in message
- Confirmation dialog: "Delete this file? This will remove it from the message context."
- If user confirms:
- Show optimistic update (remove file from UI)
- Submit to `DELETE /api/workflows/{workflowId}/messages/{messageId}/files/{fileId}`
- On success: Keep optimistic update, refresh message data
- On error: Revert optimistic update, show error
---
## Backend Routes and API Integration
### Complete Route Reference
All backend routes used by chat playground pages:
| Route | Method | Purpose | When Used | Access Control |
|-------|--------|---------|-----------|----------------|
| `/api/chat/playground/start` | POST | Start new workflow or continue existing | User clicks "Start Workflow" or "Continue" | Current user only |
| `/api/chat/playground/{workflowId}/stop` | POST | Stop running workflow | User clicks "Stop" button | Current user only |
| `/api/chat/playground/{workflowId}/chatData` | GET | Get unified chat data for polling | Live tracking (polling every 2 seconds) | Current user only |
| `/api/workflows/` | GET | Get all workflows for current user | Load workflow dropdown, initial page load | Current user only |
| `/api/workflows/{workflowId}` | GET | Get workflow by ID | User selects workflow from dropdown | Current user only |
| `/api/workflows/{workflowId}/messages/{messageId}` | DELETE | Delete message from workflow | User confirms message deletion | Current user only |
| `/api/workflows/{workflowId}/messages/{messageId}/files/{fileId}` | DELETE | Delete file from message | User confirms file deletion | Current user only |
| `/api/prompts` | GET | Get all prompts for current user | Load prompt dropdown | Current user only |
| `/api/prompts/{promptId}` | GET | Get prompt by ID | User selects prompt from dropdown | Current user only |
| `/api/files/upload` | POST | Upload new file | User drags/drops or clicks upload | Current user only |
| `/api/files/list` | GET | Get all files for current user | User clicks "Browse Files" | Current user only |
| `/api/files/{fileId}/download` | GET | Download file | User clicks "Download" button on file | Current user only |
| `/api/neutralization/config` | GET | Get neutralization config | User toggles neutralization | Current user only |
| `/api/attributes/ChatWorkflow` | GET | Get field definitions | Page load (once per page) | All authenticated users |
| `/api/attributes/UserInputRequest` | GET | Get field definitions | Page load (once per page) | All authenticated users |
### API Request Patterns
**Start Workflow Request:**
```
POST /api/chat/playground/start?workflowMode=Dynamic
Content-Type: application/json
Body: {
"prompt": "User prompt text here...",
"listFileId": ["fileId1", "fileId2"],
"userLanguage": "en"
}
```
- `workflowMode` query parameter is required: "Actionplan", "Dynamic", or "Template"
- `workflowId` query parameter is optional (for continuing existing workflow)
- `listFileId` array contains file IDs to attach (optional)
- `prompt` field contains user's prompt text (required)
- `userLanguage` should match user's preferred language
- Handle 403 (permission denied) and 400 (validation errors)
**Continue Workflow Request:**
```
POST /api/chat/playground/start?workflowId=workflow-id&workflowMode=Dynamic
Content-Type: application/json
Body: {
"prompt": "Additional prompt text...",
"listFileId": ["fileId1"],
"userLanguage": "en"
}
```
- `workflowId` query parameter is required (ID of workflow to continue)
- `workflowMode` query parameter is required (from selected workflow)
- Same body structure as start workflow
- Handle 403, 404 (workflow not found), and 400 errors
**Stop Workflow Request:**
```
POST /api/chat/playground/{workflowId}/stop
```
- No body required
- Returns updated ChatWorkflow with status "stopped"
- Handle 403 (permission denied) and 404 (workflow not found)
**Get Chat Data Request (Polling):**
```
GET /api/chat/playground/{workflowId}/chatData?afterTimestamp=1234567890.123
```
- `afterTimestamp` query parameter is optional (Unix timestamp for selective data transfer)
- Returns unified chat data: `{messages: [], logs: [], stats: []}`
- Data is chronologically ordered by `_createdAt` timestamp
- Handle 404 (workflow not found) - stop polling
**Get Workflows Request:**
```
GET /api/workflows/
```
- Returns paginated workflows list
- Can include pagination parameter: `?pagination={"page":1,"pageSize":10,"sort":[]}`
- Used to populate workflow dropdown
- Returns only current user's workflows
**Get Workflow Request:**
```
GET /api/workflows/{workflowId}
```
- Returns full workflow data including messages, logs, stats
- Used when user selects workflow from dropdown
- Handle 404 (workflow not found)
**Upload File Request:**
```
POST /api/files/upload
Content-Type: multipart/form-data
Body: {
file: <file data>,
workflowId: "optional-workflow-id" (optional)
}
```
- File sent as multipart/form-data
- `workflowId` is optional form field
- Handle 403 (permission denied), 413 (file too large), and 400 (validation errors)
- Response includes duplicate information
**Get Prompts Request:**
```
GET /api/prompts
```
- Returns paginated prompts list
- Used to populate prompt dropdown
- Returns only current user's prompts
**Get Prompt Request:**
```
GET /api/prompts/{promptId}
```
- Returns prompt details (name, content)
- Used when user selects prompt from dropdown
- Handle 404 (prompt not found)
**Get Neutralization Config Request:**
```
GET /api/neutralization/config
```
- Returns neutralization configuration (enabled status, settings)
- Used when user toggles neutralization
- Returns default config if none exists
**Delete Message Request:**
```
DELETE /api/workflows/{workflowId}/messages/{messageId}
```
- Deletes message from workflow
- Updates workflow's messageIds list
- Handle 403 (permission denied) and 404 (message not found)
**Download File Request:**
```
GET /api/files/{fileId}/download
```
- Returns file content with Content-Disposition header
- Browser automatically triggers download
- Filename properly encoded for Unicode characters
- Handle 403 (permission denied) and 404 (file not found)
**Delete File Request:**
```
DELETE /api/workflows/{workflowId}/messages/{messageId}/files/{fileId}
```
- Deletes file reference from message
- Handle 403 (permission denied) and 404 (file not found)
### Response Handling
**Start/Continue Workflow Response:**
```json
{
"id": "workflow-id",
"status": "running",
"workflowMode": "Dynamic",
"messages": [...],
"logs": [...],
"stats": [...],
...
}
```
- Returns ChatWorkflow object with status "running"
- Includes all workflow data
**Chat Data Response (Polling):**
```json
{
"messages": [
{
"id": "message-id",
"role": "user",
"content": "...",
"_createdAt": 1234567890.123,
...
}
],
"logs": [
{
"id": "log-id",
"level": "info",
"message": "...",
"_createdAt": 1234567890.124,
...
}
],
"stats": [
{
"id": "stat-id",
"metric": "...",
"value": 123,
"_createdAt": 1234567890.125,
...
}
]
}
```
- All data types in chronological order by `_createdAt`
- Empty arrays if no new data
**Error Responses:**
- 403 Forbidden → Show permission error message
- 404 Not Found → Show "not found" error message
- 400 Bad Request → Display validation errors from response
- 413 Request Entity Too Large → Show file size error
- 500 Internal Server Error → Show generic error message
---
## Field and Attribute Reference
### Complete Field List
The following is a comprehensive list of all parameters, attributes, and fields that will be displayed for workflows and user input. All of these are provided by the backend through the `/api/attributes/ChatWorkflow` and `/api/attributes/UserInputRequest` endpoints and should never be hardcoded in the frontend.
#### ChatWorkflow Fields
**Identification Fields:**
- `id` - Unique workflow identifier (text, readonly, not required, visible)
- `mandateId` - ID of the mandate this workflow belongs to (text, readonly, not required, visible)
- `name` - Workflow name (text, editable, not required, visible)
**Workflow Properties:**
- `status` - Workflow status (select, readonly, not required, visible)
- Options: "running", "completed", "stopped", "failed"
- Each option has localized labels (en/fr)
- `workflowMode` - Execution mode (select, readonly, not required, visible)
- Options: "Actionplan", "Dynamic", "Template"
- Each option has localized labels (en/fr)
- `currentRound` - Current user interaction round (number, readonly, not required, visible)
- `currentTask` - Current task in task plan (number, readonly, not required, visible)
- `currentAction` - Current action within task (number, readonly, not required, visible)
- `totalTasks` - Number of tasks in task plan (number, readonly, not required, visible)
- `totalActions` - Number of actions in current task (number, readonly, not required, visible)
- `maxSteps` - Maximum steps for Dynamic mode (number, readonly, not required, visible)
**Timestamp Fields:**
- `startedAt` - When workflow was created (timestamp, readonly, not required, visible)
- `lastActivity` - Last activity timestamp (timestamp, readonly, not required, visible)
**Related Data:**
- `messages` - List of ChatMessage objects (array, readonly, not required, visible)
- `logs` - List of ChatLog objects (array, readonly, not required, visible)
- `stats` - List of ChatStat objects (array, readonly, not required, visible)
- `tasks` - List of task objects (array, readonly, not required, visible)
#### UserInputRequest Fields
**Input Fields:**
- `prompt` - User prompt text (textarea, editable, required, visible)
- `listFileId` - Array of file IDs to attach (array, editable, not required, visible)
- `userLanguage` - User's preferred language (select, editable, not required, visible)
- Options: "en", "fr", etc.
- Each option has localized labels
#### Prompt Fields
**Prompt Properties:**
- `id` - Unique prompt identifier (text, readonly, not required, visible)
- `mandateId` - ID of the mandate this prompt belongs to (text, readonly, not required, visible)
- `name` - Prompt name (text, readonly, not required, visible)
- `content` - Prompt content (textarea, readonly, not required, visible)
### Attribute Definition Structure
Each field returned from `/api/attributes/ChatWorkflow` and `/api/attributes/UserInputRequest` contains:
- `name` - Field name (e.g., "status", "workflowMode", "prompt", "listFileId")
- `type` - Field data type (e.g., "text", "select", "textarea", "array", "timestamp", "number")
- `label` - Localized field label (object with language keys: {"en": "English Label", "fr": "French Label"})
- `description` - Field description text
- `required` - Boolean indicating if field is required
- `readonly` - Boolean indicating if field is read-only
- `editable` - Boolean indicating if field can be edited (inverse of readonly)
- `visible` - Boolean indicating if field should be displayed in UI
- `options` - Array of options for select fields (each option has `value` and localized `label`)
---
## Dynamic Rendering Guidelines
The frontend must render all UI components dynamically based on backend metadata. No field definitions, labels, validation rules, or UI structure should be hardcoded.
### Form Field Generation
When rendering input forms:
1. Fetch attribute definitions from `/api/attributes/UserInputRequest` and `/api/attributes/ChatWorkflow`
2. Filter attributes where `visible: true` AND `editable: true` to determine which fields to show
3. For each editable field, generate appropriate form input based on `type`:
- `text` fields → Text input
- `textarea` fields → Multi-line text area
- `select` fields → Dropdown/select input with options from `options` array (use localized labels)
- `array` fields → Array input with add/remove controls
- `number` fields → Number input
4. Use `label` property for field labels (localized)
5. Use `required` property to show required indicators (asterisk, etc.)
6. Use `description` property to show help text or tooltips
7. Validate form before submission:
- Check all `required: true` fields have values
- Validate types (e.g., array fields must be arrays)
- Validate select fields (value must be in options array)
8. On submit, build UserInputRequest object with all form data
### Workflow Mode Selector Generation
When rendering workflow mode selector:
1. Fetch attribute definitions from `/api/attributes/ChatWorkflow`
2. Find `workflowMode` field
3. Extract `options` array from field definition
4. Generate radio buttons or tabs for each option
5. Use localized labels from options: `option.label[userLanguage]`
6. Show description/help text when option is selected
7. Mark one option as required (user must select before starting)
### Dropdown Generation
**Workflow Dropdown:**
1. Fetch workflows via `GET /api/workflows/`
2. Display workflows in dropdown with name, status, last activity
3. Add "New Workflow" as default/first option
4. When workflow selected, load full workflow data
5. Display previous messages when workflow selected
**Prompt Dropdown:**
1. Fetch prompts via `GET /api/prompts`
2. Display prompts in dropdown with name
3. When prompt selected, fetch prompt details and pre-fill text field
4. Allow user to edit pre-filled text
### File Attachment UI Generation
**Drop Zone:**
1. Create drop zone area with visual boundaries
2. Handle drag events (dragenter, dragover, dragleave, drop)
3. Show visual feedback when files dragged over (highlight, border, overlay)
4. Process dropped files and upload automatically
5. Show file preview immediately after drop
**File Upload Button:**
1. Create file input element (hidden)
2. Trigger file picker on button click
3. Handle multiple file selection
4. Upload files and show preview
**File Browser:**
1. Fetch files via `GET /api/files/list`
2. Display files in browser/selector with pagination
3. Allow multiple file selection
4. Add selected files to attachment list
**File List Display:**
1. Show attached files with name, size, type
2. Display remove button for each file
3. Update list when files added or removed
### Message Display Generation
When rendering messages in workflow view:
1. Fetch messages from workflow data or chatData endpoint
2. Display messages chronologically
3. Format based on message role:
- User messages → Right-aligned or distinct styling
- Assistant messages → Left-aligned or distinct styling
4. Display file attachments as part of each message:
- Show file name, size, and type/icon for each attachment
- Display file attachments in organized list or grid within message
- For each file attachment, render action buttons:
- **"Show" button** - Opens file preview/viewer
- **"Download" button** - Triggers file download
- **"Delete" button** - Removes file from message (with confirmation)
- File preview can be displayed inline, in modal, or sidebar
- Support different file type previews (images, PDFs, text, etc.)
5. Show timestamps (relative or absolute)
6. Add delete button for each message (if user has permission)
### Log Display Generation
When rendering logs in log panel:
1. Fetch logs from workflow data or chatData endpoint
2. Display logs chronologically
3. Format based on log level:
- Info → Default styling
- Warning → Yellow/orange styling
- Error → Red styling
4. Show timestamps for each log entry
5. Support filtering by log level (optional)
### Statistics Display Generation
When rendering statistics in stats panel:
1. Fetch stats from workflow data or chatData endpoint
2. Display statistics in organized format
3. Format based on metric type:
- Numbers → Display with appropriate units
- Percentages → Display as percentage
- Timestamps → Format as duration or absolute time
4. Update statistics in real-time during polling
### Display Formatting
When displaying field values:
1. Use `type` property to determine formatting:
- `text` → Display as-is (may need HTML escaping)
- `textarea` → Preserve line breaks
- `select` → Look up value in `options` array and display localized label
- `timestamp` → Format as relative time or absolute date/time
- `number` → Format with appropriate decimal places
- `array` → Display as list or comma-separated
2. Handle `null` or `undefined` values gracefully (show "-" or "Not set")
3. Use `readonly` property to determine if field should show edit indicators
4. Special formatting for workflow fields:
- Status → Color-code badges (Running = blue, Completed = green, Stopped = gray, Failed = red)
- Workflow Mode → Display as badge with icon
- Timestamps → Show relative time in list view, absolute date in detail view
### Localization
All labels and options support multiple languages:
1. Use user's preferred language (from user settings or browser locale)
2. Access localized labels from `label` object: `label[userLanguage]` or `label.en` as fallback
3. For select options, use `option.label[userLanguage]` or `option.label.en` as fallback
4. If label for current language is missing, fall back to English
### Polling Implementation
**Polling Setup:**
1. Start polling when workflow view is active
2. Use `setInterval` or similar mechanism (2 second interval)
3. Store last timestamp to use in `afterTimestamp` parameter
4. Stop polling when workflow completes or user navigates away
**Polling Logic:**
1. Call `GET /api/chat/playground/{workflowId}/chatData?afterTimestamp={lastTimestamp}`
2. Compare returned data with existing data
3. Append new messages, logs, stats to UI
4. Update last timestamp
5. Check workflow status - stop polling if completed/stopped/failed
6. Handle errors gracefully (404 stops polling)
**Performance Considerations:**
1. Debounce rapid updates
2. Batch UI updates
3. Use virtual scrolling for long message lists
4. Limit polling frequency
5. Stop polling when tab is not visible (Page Visibility API)
### Key Principles
- Never hardcode field names, labels, types, or validation rules
- Always fetch attribute definitions from backend before rendering UI
- Use attribute metadata to determine what to display and how to display it
- Support all field types dynamically - if backend adds new types, frontend should handle them
- Respect `visible`, `editable`, `readonly`, and `required` flags from backend
- Use localized labels from backend metadata
- Generate forms, dropdowns, and displays entirely from attribute definitions
- When backend adds new fields, frontend should automatically display them without code changes
- Handle all error cases gracefully (403, 404, 400, 413, 500)
- Provide user feedback for all actions (loading states, success messages, error messages)
- **All workflows are user-scoped** (backend enforces this)
- **Polling should be efficient** (use selective data transfer with afterTimestamp)
- **Optimistic updates** for better UX (show changes immediately, revert on error)
---
## Summary
This document provides complete frontend requirements for the chat playground page and workflow management components. All requirements follow the principle of **backend-driven UI generation**—no hardcoding of field definitions, labels, or validation rules. The frontend should dynamically generate all UI components from backend metadata provided through the `/api/attributes/ChatWorkflow` and `/api/attributes/UserInputRequest` endpoints.
**Key Architecture Pattern:** The chat playground interface is a single page (`/chat-playground`) with different views managed through component state. All interactions happen within the same page component without separate routes.
**Security Note:** Workflows are user-scoped. Users can only see and manage their own workflows. The backend enforces this security, and the frontend should never attempt to access other users' workflows.
**Real-Time Updates:** The workflow view uses polling-based live tracking to show real-time updates. Polling should be efficient using selective data transfer with timestamps.
For generic patterns that apply across all entity types (not just workflows), see the [Dynamic Forms and Pagination documentation](./dynamic-forms-and-pagination.md).

View file

@ -1,542 +0,0 @@
# Chat Playground and Workflow Live Tracking Frontend Documentation
This document describes customer journeys for managing chat playground workflows and live tracking workflow execution through the frontend, focusing on how users interact with workflow management and how the backend routes support these experiences. All UI components are dynamically generated from backend metadata—no hardcoding required.
## Table of Contents
1. [Overview](#overview)
2. [Customer Journey 1: Starting a New Workflow](#customer-journey-1-starting-a-new-workflow)
3. [Customer Journey 2: Continuing an Existing Workflow](#customer-journey-2-continuing-an-existing-workflow)
4. [Customer Journey 3: Live Tracking Workflow Progress](#customer-journey-3-live-tracking-workflow-progress)
5. [Customer Journey 4: Stopping a Running Workflow](#customer-journey-4-stopping-a-running-workflow)
6. [Customer Journey 5: Deleting Context from a Workflow](#customer-journey-5-deleting-context-from-a-workflow)
---
## Overview
The chat playground routes (`/api/chat/playground`) and workflow routes (`/api/workflows`) enable users to create, manage, and track AI-powered workflows that process user requests through task planning and action execution. These routes support **workflow lifecycle management** including creation, live tracking, modification, and deletion.
**Key Principles:**
- **User-Centric**: Documentation organized around what users want to accomplish
- **Backend-Driven**: All forms, tables, and UI components generated from backend metadata
- **No Hardcoding**: Field definitions, labels, validation rules, and options come from the backend
- **Permission-Aware**: Backend enforces permissions; frontend handles gracefully
- **User-Scoped**: Users can only see and manage their own workflows
- **Real-Time Updates**: Polling-based live tracking for workflow progress
---
## Customer Journey 1: Starting a New Workflow
### User Goal
"I want to start a new AI workflow to process my request."
### User Story
As a user, I want to start a new workflow by optionally selecting a saved prompt template, providing or editing my input prompt, choosing a workflow mode (Actionplan for traditional task planning, Dynamic for iterative processing, or Template for template-based processing), optionally enabling data neutralization for privacy compliance, and optionally attaching files, so the system can begin processing my request in the appropriate mode with sensitive data protected if needed.
### User Story Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Backend
User->>Frontend: Navigate to chat playground
Frontend->>Backend: GET /api/attributes/ChatWorkflow
Backend-->>Frontend: Attribute definitions (fields, labels, types)
Frontend->>Backend: GET /api/attributes/UserInputRequest
Backend-->>Frontend: Input request field definitions
Frontend->>Frontend: Generate input form from attributes
Frontend->>Backend: GET /api/prompts
Backend-->>Frontend: Paginated prompts list
Frontend-->>User: Display chat input form with mode selector<br/>(Actionplan, Dynamic, Template)<br/>+ prompt dropdown selector
alt User optionally selects a prompt
User->>Frontend: Click prompt dropdown
Frontend->>Frontend: Display available prompts list<br/>(from cached prompts data)
User->>Frontend: Select prompt from dropdown
Frontend->>Backend: GET /api/prompts/promptId
Backend-->>Frontend: Selected prompt details<br/>(name, content)
Frontend->>Frontend: Pre-fill prompt text field with prompt content
Frontend->>Frontend: Show selected prompt name
Frontend-->>User: Display prompt text pre-filled<br/>(user can still edit)
end
User->>Frontend: Enter or edit prompt text
alt User selects workflow mode
alt User selects "Actionplan" mode
User->>Frontend: Click "Actionplan" mode option
Frontend->>Frontend: Show mode description/help text<br/>(traditional task planning)
Frontend->>Frontend: Set workflowMode to "Actionplan"
Frontend-->>User: Display selected mode indicator
else User selects "Dynamic" mode
User->>Frontend: Click "Dynamic" mode option
Frontend->>Frontend: Show mode description/help text<br/>(iterative dynamic-style processing)
Frontend->>Frontend: Set workflowMode to "Dynamic"
Frontend-->>User: Display selected mode indicator
else User selects "Template" mode
User->>Frontend: Click "Template" mode option
Frontend->>Frontend: Show mode description/help text<br/>(template-based processing)
Frontend->>Frontend: Set workflowMode to "Template"
Frontend-->>User: Display selected mode indicator
end
end
alt User optionally enables neutralization
User->>Frontend: Click "Enable Neutralization" toggle
Frontend->>Backend: GET /api/neutralization/config
Backend-->>Frontend: Neutralization config (enabled status)
alt Config exists and enabled
Frontend->>Frontend: Mark neutralization as enabled for workflow
Frontend-->>User: Show neutralization enabled indicator<br/>(uses existing config)
else Config disabled or not found
Frontend->>Frontend: Mark neutralization as disabled
Frontend-->>User: Show neutralization disabled<br/>(user can configure on settings page)
end
end
alt User optionally attaches files
alt User drags and drops files
User->>Frontend: Drag file(s) over drop zone
Frontend->>Frontend: Show visual feedback<br/>(highlight drop zone, border, overlay)
Frontend-->>User: Display drop zone active state
User->>Frontend: Drop file(s) onto drop zone
Frontend->>Frontend: Process dropped files
Frontend->>Frontend: Show file preview with name and size
Frontend->>Frontend: Optimistic update: Add file to attachment list
Frontend->>Backend: POST /api/files/upload<br/>+ multipart/form-data (file)
alt Permission denied (403)
Backend-->>Frontend: 403 Forbidden
Frontend->>Frontend: Revert optimistic update: Remove file from list
Frontend-->>User: Show permission error
else File too large (413)
Backend-->>Frontend: 413 Request Entity Too Large
Frontend->>Frontend: Revert optimistic update: Remove file from list
Frontend-->>User: Show file size error
else Success (201)
Backend-->>Frontend: FileItem object + duplicate info
Frontend->>Frontend: Keep optimistic update
Frontend->>Frontend: Store fileId for later use
Frontend-->>User: Show file attached successfully
end
else User uploads new file via button
User->>Frontend: Click "Attach File" or "Upload File" button
Frontend->>Frontend: Open file picker dialog
User->>Frontend: Select file(s) from device
Frontend->>Frontend: Show file preview with name and size
Frontend->>Frontend: Optimistic update: Add file to attachment list
Frontend->>Backend: POST /api/files/upload<br/>+ multipart/form-data (file)
alt Permission denied (403)
Backend-->>Frontend: 403 Forbidden
Frontend->>Frontend: Revert optimistic update: Remove file from list
Frontend-->>User: Show permission error
else File too large (413)
Backend-->>Frontend: 413 Request Entity Too Large
Frontend->>Frontend: Revert optimistic update: Remove file from list
Frontend-->>User: Show file size error
else Success (201)
Backend-->>Frontend: FileItem object + duplicate info
Frontend->>Frontend: Keep optimistic update
Frontend->>Frontend: Store fileId for later use
Frontend-->>User: Show file attached successfully
end
else User selects existing file
User->>Frontend: Click "Browse Files" or "Select File" button
Frontend->>Backend: GET /api/files/list
Backend-->>Frontend: Paginated files list
Frontend->>Frontend: Display file browser/selector
Frontend-->>User: Show available files
User->>Frontend: Select file(s) from list
Frontend->>Frontend: Add fileId(s) to attachment list
Frontend-->>User: Show selected files in attachment list
end
end
User->>Frontend: Click "Start Workflow" button
Frontend->>Frontend: Validate form (required fields, types, workflowMode)
alt Validation fails (missing workflowMode or prompt)
Frontend-->>User: Show validation errors<br/>(e.g., "Workflow mode is required")
else Validation passes
Frontend->>Frontend: Build UserInputRequest with listFileId array (if files attached)
alt Neutralization enabled
Frontend->>Frontend: Neutralization will be applied automatically<br/>by backend during workflow processing
end
Frontend->>Frontend: Optimistic update: Show loading state, create workflow placeholder
Frontend->>Backend: POST /api/chat/playground/start<br/>+ workflowMode query param (Actionplan/Dynamic/Template)<br/>+ UserInputRequest body<br/>(includes listFileId if files attached)
alt Permission denied (403)
Backend-->>Frontend: 403 Forbidden
Frontend->>Frontend: Revert optimistic update
Frontend-->>User: Show permission error
else Validation error (400)
Backend-->>Frontend: 400 Bad Request + error details
Frontend->>Frontend: Revert optimistic update
Frontend-->>User: Show backend validation errors
else Success (200)
Backend-->>Frontend: Created ChatWorkflow (status: "running")<br/>with files attached (if any)<br/>(neutralized if neutralization enabled)
Frontend->>Frontend: Keep optimistic update
Frontend->>Frontend: Navigate to workflow view
Frontend->>Frontend: Start polling for updates
alt Neutralization enabled
Frontend->>Frontend: Show neutralization indicator in workflow view
Frontend->>Frontend: Option to resolve text back to original when viewing
end
Frontend-->>User: Display workflow with live tracking<br/>(files visible if attached, neutralized if enabled)
end
end
```
---
## Customer Journey 2: Continuing an Existing Workflow
### User Goal
"I want to continue a workflow I started earlier by selecting it from a list and adding more input."
### User Story
As a user, I want to select a previous workflow from a dropdown on the chat interface page and continue it by providing additional input, so the system can process my new request in the context of the previous conversation.
### User Story Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Backend
User->>Frontend: Navigate to chat playground
Frontend->>Backend: GET /api/attributes/ChatWorkflow
Backend-->>Frontend: Attribute definitions (fields, labels, types)
Frontend->>Backend: GET /api/attributes/UserInputRequest
Backend-->>Frontend: Input request field definitions
Frontend->>Backend: GET /api/workflows/
Backend-->>Frontend: Paginated workflows list
Frontend->>Backend: GET /api/prompts
Backend-->>Frontend: Paginated prompts list
Frontend->>Frontend: Generate input form from attributes
Frontend-->>User: Display chat input form with<br/>workflow dropdown selector<br/>+ mode selector + prompt dropdown
alt User selects previous workflow from dropdown
User->>Frontend: Click workflow dropdown
Frontend->>Frontend: Display available workflows list<br/>(from cached workflows data)
User->>Frontend: Select workflow from dropdown
Frontend->>Backend: GET /api/workflows/workflowId
Backend-->>Frontend: Selected workflow data<br/>(status, messages, workflowMode, etc.)
Frontend->>Frontend: Load workflow history
Frontend->>Frontend: Display previous messages in chat view
Frontend->>Frontend: Set workflowMode from selected workflow
Frontend->>Frontend: Show selected workflow name/ID
Frontend-->>User: Display workflow context<br/>(previous messages visible,<br/>workflow mode pre-selected)
end
alt User optionally selects a prompt
User->>Frontend: Click prompt dropdown
Frontend->>Frontend: Display available prompts list<br/>(from cached prompts data)
User->>Frontend: Select prompt from dropdown
Frontend->>Backend: GET /api/prompts/promptId
Backend-->>Frontend: Selected prompt details<br/>(name, content)
Frontend->>Frontend: Pre-fill prompt text field with prompt content
Frontend->>Frontend: Show selected prompt name
Frontend-->>User: Display prompt text pre-filled<br/>(user can still edit)
end
User->>Frontend: Enter or edit prompt text
alt User optionally enables/disables neutralization
User->>Frontend: Click "Enable Neutralization" toggle
Frontend->>Backend: GET /api/neutralization/config
Backend-->>Frontend: Neutralization config (enabled status)
alt Config exists and enabled
Frontend->>Frontend: Mark neutralization as enabled for workflow
Frontend-->>User: Show neutralization enabled indicator<br/>(uses existing config)
else Config disabled or not found
Frontend->>Frontend: Mark neutralization as disabled
Frontend-->>User: Show neutralization disabled<br/>(user can configure on settings page)
end
end
alt User optionally attaches files
alt User drags and drops files
User->>Frontend: Drag file(s) over drop zone
Frontend->>Frontend: Show visual feedback<br/>(highlight drop zone, border, overlay)
Frontend-->>User: Display drop zone active state
User->>Frontend: Drop file(s) onto drop zone
Frontend->>Frontend: Process dropped files
Frontend->>Frontend: Show file preview with name and size
Frontend->>Frontend: Optimistic update: Add file to attachment list
Frontend->>Backend: POST /api/files/upload<br/>+ multipart/form-data (file)<br/>+ workflowId (optional)
alt Permission denied (403)
Backend-->>Frontend: 403 Forbidden
Frontend->>Frontend: Revert optimistic update: Remove file from list
Frontend-->>User: Show permission error
else File too large (413)
Backend-->>Frontend: 413 Request Entity Too Large
Frontend->>Frontend: Revert optimistic update: Remove file from list
Frontend-->>User: Show file size error
else Success (201)
Backend-->>Frontend: FileItem object + duplicate info
Frontend->>Frontend: Keep optimistic update
Frontend->>Frontend: Store fileId for later use
Frontend-->>User: Show file attached successfully
end
else User uploads new file via button
User->>Frontend: Click "Attach File" or "Upload File" button
Frontend->>Frontend: Open file picker dialog
User->>Frontend: Select file(s) from device
Frontend->>Frontend: Show file preview with name and size
Frontend->>Frontend: Optimistic update: Add file to attachment list
Frontend->>Backend: POST /api/files/upload<br/>+ multipart/form-data (file)<br/>+ workflowId (optional)
alt Permission denied (403)
Backend-->>Frontend: 403 Forbidden
Frontend->>Frontend: Revert optimistic update: Remove file from list
Frontend-->>User: Show permission error
else File too large (413)
Backend-->>Frontend: 413 Request Entity Too Large
Frontend->>Frontend: Revert optimistic update: Remove file from list
Frontend-->>User: Show file size error
else Success (201)
Backend-->>Frontend: FileItem object + duplicate info
Frontend->>Frontend: Keep optimistic update
Frontend->>Frontend: Store fileId for later use
Frontend-->>User: Show file attached successfully
end
else User selects existing file
User->>Frontend: Click "Browse Files" or "Select File" button
Frontend->>Backend: GET /api/files/list
Backend-->>Frontend: Paginated files list
Frontend->>Frontend: Display file browser/selector
Frontend-->>User: Show available files
User->>Frontend: Select file(s) from list
Frontend->>Frontend: Add fileId(s) to attachment list
Frontend-->>User: Show selected files in attachment list
end
end
User->>Frontend: Click "Continue" or "Send" button
Frontend->>Frontend: Validate form (required fields, workflowMode)
alt Validation fails (missing workflowMode or prompt)
Frontend-->>User: Show validation errors<br/>(e.g., "Workflow mode is required")
else Validation passes
Frontend->>Frontend: Build UserInputRequest with listFileId array (if files attached)
alt Neutralization enabled
Frontend->>Frontend: Neutralization will be applied automatically<br/>by backend during workflow processing
end
Frontend->>Frontend: Optimistic update: Add user message to UI
Frontend->>Backend: POST /api/chat/playground/start<br/>+ workflowId query param (from selected workflow)<br/>+ workflowMode query param (from selected workflow)<br/>+ UserInputRequest body<br/>(includes listFileId if files attached)
alt Permission denied (403)
Backend-->>Frontend: 403 Forbidden
Frontend->>Frontend: Revert optimistic update
Frontend-->>User: Show permission error
else Workflow not found (404)
Backend-->>Frontend: 404 Not Found
Frontend->>Frontend: Revert optimistic update
Frontend-->>User: Show not found error
else Validation error (400)
Backend-->>Frontend: 400 Bad Request + error details
Frontend->>Frontend: Revert optimistic update
Frontend-->>User: Show backend validation errors
else Success (200)
Backend-->>Frontend: Updated ChatWorkflow (status: "running")<br/>with new files attached (if any)<br/>(neutralized if neutralization enabled)
Frontend->>Frontend: Keep optimistic update
Frontend->>Frontend: Navigate to workflow view or update current view
Frontend->>Frontend: Start/continue polling for updates
alt Neutralization enabled
Frontend->>Frontend: Show neutralization indicator in workflow view
Frontend->>Frontend: Option to resolve text back to original when viewing
end
Frontend-->>User: Display updated workflow with new input<br/>(files visible if attached, neutralized if enabled)
end
end
```
---
## Customer Journey 3: Live Tracking Workflow Progress
### User Goal
"I want to see real-time updates as my workflow processes my request."
### User Story
As a user, I want to see live updates including new messages, execution logs, and statistics as my workflow processes, so I can monitor progress and understand what the system is doing.
### User Story Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Backend
User->>Frontend: View active workflow
Frontend->>Frontend: Start polling interval (e.g., every 2 seconds)
loop Polling cycle
Frontend->>Backend: GET /api/chat/playground/workflowId/chatData<br/>+ afterTimestamp query param (optional)
alt Workflow not found (404)
Backend-->>Frontend: 404 Not Found
Frontend->>Frontend: Stop polling
Frontend-->>User: Show error, navigate away
else Success (200)
Backend-->>Frontend: Unified chat data<br/>{messages: [], logs: [], stats: []}<br/>(chronologically ordered by _createdAt)
Frontend->>Frontend: Compare with existing data
alt New data available
Frontend->>Frontend: Append new messages to chat view
Frontend->>Frontend: Append new logs to log panel
Frontend->>Frontend: Update statistics display
Frontend->>Frontend: Update workflow status indicator
Frontend->>Frontend: Scroll to latest content (if auto-scroll enabled)
Frontend-->>User: Display new messages, logs, stats
else No new data
Frontend->>Frontend: Continue polling silently
end
alt Workflow status is "completed" or "stopped" or "failed"
Frontend->>Frontend: Stop polling
Frontend->>Frontend: Show final status
Frontend-->>User: Display completed workflow
end
end
end
alt User manually stops polling
User->>Frontend: Navigate away or close tab
Frontend->>Frontend: Stop polling interval
end
```
---
## Customer Journey 4: Stopping a Running Workflow
### User Goal
"I want to stop a workflow that is currently running."
### User Story
As a user, I want to stop a running workflow by clicking a stop button, so I can halt processing if I no longer need the results or if something is taking too long.
### User Story Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Backend
User->>Frontend: View running workflow
Frontend->>Frontend: Display "Stop" button
User->>Frontend: Click "Stop" button
Frontend->>Frontend: Show confirmation dialog<br/>"Stop this workflow?"
alt User cancels
User->>Frontend: Click "Cancel"
Frontend->>Frontend: Close dialog
Frontend-->>User: Dialog closed, workflow continues
else User confirms
User->>Frontend: Click "Confirm"
Frontend->>Frontend: Optimistic update: Update status to "stopping"
Frontend->>Backend: POST /api/chat/playground/workflowId/stop
alt Permission denied (403)
Backend-->>Frontend: 403 Forbidden
Frontend->>Frontend: Revert optimistic update
Frontend-->>User: Show permission error
else Workflow not found (404)
Backend-->>Frontend: 404 Not Found
Frontend->>Frontend: Revert optimistic update
Frontend-->>User: Show not found error
else Success (200)
Backend-->>Frontend: Updated ChatWorkflow (status: "stopped")
Frontend->>Frontend: Keep optimistic update
Frontend->>Frontend: Stop polling for updates
Frontend->>Backend: GET /api/workflows/workflowId (refetch)
Backend-->>Frontend: Final workflow state
Frontend->>Frontend: Update UI with stopped status
Frontend-->>User: Show stopped workflow with final state
end
end
```
---
## Customer Journey 5: Deleting Context from a Workflow
### User Goal
"I want to remove messages or files from a workflow to clean up the context."
### User Story
As a user, I want to delete individual messages or files attached to messages in a workflow, so I can remove unwanted context and keep the workflow focused on what's relevant.
### User Story Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Backend
alt User deletes message from workflow
User->>Frontend: View workflow with messages
User->>Frontend: Click "Delete" button on message
Frontend->>Frontend: Show confirmation dialog<br/>"Delete this message?<br/>This will remove it from the workflow context."
alt User cancels
User->>Frontend: Click "Cancel"
Frontend->>Frontend: Close dialog
Frontend-->>User: Dialog closed, message remains
else User confirms
User->>Frontend: Click "Confirm" or "Delete"
Frontend->>Frontend: Optimistic update: Remove message from UI
Frontend->>Backend: DELETE /api/workflows/workflowId/messages/messageId
alt Permission denied (403)
Backend-->>Frontend: 403 Forbidden
Frontend->>Frontend: Revert optimistic update: Restore message
Frontend-->>User: Show permission error
else Message not found (404)
Backend-->>Frontend: 404 Not Found
Frontend->>Frontend: Revert optimistic update: Restore message
Frontend-->>User: Show not found error
else Success (200)
Backend-->>Frontend: Success response<br/>{workflowId, messageId, message: "Message deleted successfully"}
Frontend->>Frontend: Keep optimistic update
Frontend->>Backend: GET /api/workflows/workflowId (refetch)
Backend-->>Frontend: Updated workflow (messageIds updated)
Frontend->>Frontend: Update UI with fresh workflow data
Frontend-->>User: Show message removed from workflow
end
end
end
alt User deletes file from message
User->>Frontend: View message with file attachments
User->>Frontend: Click "Delete" button on file attachment
Frontend->>Frontend: Show confirmation dialog<br/>"Delete this file?<br/>This will remove it from the message context."
alt User cancels
User->>Frontend: Click "Cancel"
Frontend->>Frontend: Close dialog
Frontend-->>User: Dialog closed, file remains
else User confirms
User->>Frontend: Click "Confirm" or "Delete"
Frontend->>Frontend: Optimistic update: Remove file from UI
Frontend->>Backend: DELETE /api/workflows/workflowId/messages/messageId/files/fileId
alt Permission denied (403)
Backend-->>Frontend: 403 Forbidden
Frontend->>Frontend: Revert optimistic update: Restore file
Frontend-->>User: Show permission error
else File not found (404)
Backend-->>Frontend: 404 Not Found
Frontend->>Frontend: Revert optimistic update: Restore file
Frontend-->>User: Show not found error
else Success (200)
Backend-->>Frontend: Success response<br/>{workflowId, messageId, fileId, message: "File reference deleted successfully"}
Frontend->>Frontend: Keep optimistic update
Frontend->>Backend: GET /api/workflows/workflowId/messages/messageId (refetch)
Backend-->>Frontend: Updated message (files list updated)
Frontend->>Frontend: Update UI with fresh message data
Frontend-->>User: Show file removed from message
end
end
end
```

View file

@ -1,293 +0,0 @@
# Connection Routes Frontend Documentation
This document describes customer journeys for managing connections through the frontend, focusing on how users interact with connection management and how the backend routes support these experiences. All UI components are dynamically generated from backend metadata—no hardcoding required.
## Table of Contents
1. [Overview](#overview)
2. [Customer Journey 1: Discovering and Browsing Connections](#customer-journey-1-discovering-and-browsing-connections)
3. [Customer Journey 2: Creating New Connections](#customer-journey-2-creating-new-connections)
4. [Customer Journey 3: Editing Connection Properties](#customer-journey-3-editing-connection-properties)
5. [Customer Journey 4: Refreshing Connection Tokens](#customer-journey-4-refreshing-connection-tokens)
6. [Customer Journey 5: Deleting Connections](#customer-journey-5-deleting-connections)
---
## Overview
The connection routes (`/api/connections`) enable users to manage their OAuth connections (Google, Microsoft) within their account. These routes focus on **connection administration** including creation, editing, token refresh, and deletion.
**Key Principles:**
- **User-Centric**: Documentation organized around what users want to accomplish
- **Backend-Driven**: All forms, tables, and UI components generated from backend metadata
- **No Hardcoding**: Field definitions, labels, validation rules, and options come from the backend
- **Permission-Aware**: Backend enforces permissions; frontend handles gracefully
- **User-Scoped**: Users can only see and manage their own connections
---
## Customer Journey 1: Discovering and Browsing Connections
### User Goal
"I want to see all my connections and find the one I'm looking for."
### User Story
As a user, I want to browse my connections, search for specific connections, filter by any field, sort them by different criteria, and quickly identify connections by their authority, status, and token status.
### User Story Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Backend
User->>Frontend: Navigate to /connections
Frontend->>Backend: GET /api/attributes/UserConnection
Backend-->>Frontend: Attribute definitions (fields, labels, types)
Frontend->>Backend: GET /api/connections/
Backend-->>Frontend: Connections list (with token status)
Frontend->>Frontend: Generate table columns from attributes
Frontend->>Frontend: Generate filter controls from attributes
Frontend->>Frontend: Render connections table + search + filters
Frontend->>Frontend: Render action buttons in table (Edit, Delete, Refresh Token)
Frontend-->>User: Display connection list with search/filter UI + action buttons
alt User performs general search
User->>Frontend: Type in search box (e.g., "google")
Frontend->>Frontend: Update search query
Frontend->>Backend: GET /api/connections/ (client-side filter)
Frontend-->>User: Display matching connections
end
alt User applies field filter
User->>Frontend: Select filter field (e.g., "Authority")
Frontend->>Frontend: Show filter options from attribute metadata
User->>Frontend: Select filter value (e.g., "google")
Frontend->>Frontend: Update filter parameters
Frontend->>Backend: GET /api/connections/ (client-side filter)
Frontend-->>User: Display filtered connections
end
alt User combines search + filter + sort
User->>Frontend: Apply search + filter + sort
Frontend->>Frontend: Combine all parameters
Frontend->>Backend: GET /api/connections/ (client-side filter/sort)
Frontend-->>User: Display results
end
User->>Frontend: Click column header (e.g., "Status")
Frontend->>Frontend: Update sort parameters
Frontend->>Backend: GET /api/connections/ (client-side sort)
Backend-->>Frontend: Connections list
Frontend-->>User: Display sorted connections
```
---
## Customer Journey 2: Creating New Connections
### User Goal
"I want to create new OAuth connections for my account."
### User Story
As a user, I want to create a new connection by clicking either "Connect Google" or "Connect Microsoft" button, which will immediately initiate the OAuth flow.
### User Story Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Backend
alt User clicks "Connect Google" button
User->>Frontend: Click "Connect Google" button
Frontend->>Frontend: Optimistic update: Show loading state, add connection to UI immediately
Frontend->>Backend: POST /api/connections/ + {type: "google"}
else User clicks "Connect Microsoft" button
User->>Frontend: Click "Connect Microsoft" button
Frontend->>Frontend: Optimistic update: Show loading state, add connection to UI immediately
Frontend->>Backend: POST /api/connections/ + {type: "msft"}
end
alt Permission denied (403)
Backend-->>Frontend: 403 Forbidden
Frontend->>Frontend: Revert optimistic update: Remove connection from UI
Frontend-->>User: Show permission error
else Validation error (400)
Backend-->>Frontend: 400 Bad Request + error details
Frontend->>Frontend: Revert optimistic update: Remove connection from UI
Frontend-->>User: Show backend validation errors
else Success (200)
Backend-->>Frontend: Created connection object (status: PENDING)
Frontend->>Frontend: Keep optimistic update
Frontend->>Backend: POST /api/connections/connectionId/connect
Backend-->>Frontend: {authUrl: "/api/google/login?state=..."} or {authUrl: "/api/msft/login?state=..."}
Frontend->>Frontend: Navigate to authUrl (OAuth flow)
Frontend-->>User: Redirect to OAuth provider
end
```
---
## Customer Journey 3: Editing Connection Properties
### User Goal
"I want to change connection settings like its status or external email."
### User Story
As a user, I want to edit a connection's properties through a popup/modal form that only shows fields I'm allowed to edit, with validation and clear error messages.
### User Story Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Backend
User->>Frontend: Click "Edit" button in table row
Frontend->>Backend: GET /api/connections/connectionId
Backend-->>Frontend: Current connection data
Frontend->>Backend: GET /api/attributes/UserConnection
Backend-->>Frontend: Field definitions (editable fields)
Frontend->>Frontend: Filter editable fields
Frontend->>Frontend: Generate form from attributes
Frontend->>Frontend: Pre-populate form with connection data
Frontend->>Frontend: Open popup/modal with edit form
Frontend-->>User: Display edit form in popup/modal
User->>Frontend: Modify form fields
User->>Frontend: Click "Save"
Frontend->>Frontend: Validate form (required fields, types)
alt Validation fails
Frontend-->>User: Show validation errors in modal
else Validation passes
Frontend->>Frontend: Optimistic update: Apply changes to UI immediately
Frontend->>Backend: PUT /api/connections/connectionId + form data
alt Permission denied (403)
Backend-->>Frontend: 403 Forbidden
Frontend->>Frontend: Revert optimistic update
Frontend-->>User: Show permission error in modal
else Validation error (400)
Backend-->>Frontend: 400 Bad Request + error details
Frontend->>Frontend: Revert optimistic update
Frontend-->>User: Show backend validation errors in modal
else Success (200)
Backend-->>Frontend: Updated connection
Frontend->>Frontend: Keep optimistic update (or refresh from response)
Frontend->>Backend: GET /api/connections/ (refetch)
Backend-->>Frontend: Updated connections list
Frontend->>Frontend: Update table with fresh data
Frontend->>Frontend: Close popup/modal
Frontend-->>User: Show updated connection in table
end
end
alt User clicks Cancel
User->>Frontend: Click "Cancel" button
Frontend->>Frontend: Close popup/modal without saving
Frontend-->>User: Modal closed, no changes
end
```
---
## Customer Journey 4: Refreshing Connection Tokens
### User Goal
"I want to refresh the OAuth token for a connection that is expired or about to expire."
### User Story
As a user, I want to refresh the OAuth token for a connection by clicking a refresh button, so the connection remains active.
### User Story Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Backend
User->>Frontend: Click "Refresh Token" button in table
Frontend->>Frontend: Show loading state
Frontend->>Frontend: Optimistic update: Update token status to "refreshing"
alt Connection authority is Microsoft
Frontend->>Backend: POST /api/msft/refresh + {connectionId: connectionId}
else Connection authority is Google
Frontend->>Backend: POST /api/google/refresh + {connectionId: connectionId}
end
alt Permission denied (403)
Backend-->>Frontend: 403 Forbidden
Frontend->>Frontend: Revert optimistic update
Frontend-->>User: Show permission error
else Connection not found (404)
Backend-->>Frontend: 404 Not Found
Frontend->>Frontend: Revert optimistic update
Frontend-->>User: Show not found error
else Success (200)
Backend-->>Frontend: {message: "Token refreshed successfully", expires_at: timestamp, expires_in_seconds: number}
Frontend->>Frontend: Keep optimistic update
Frontend->>Backend: GET /api/connections/ (refetch)
Backend-->>Frontend: Updated connections list with new token status
Frontend->>Frontend: Update table with fresh data
Frontend-->>User: Show success message, updated token status
end
```
---
## Customer Journey 5: Deleting Connections
### User Goal
"I want to delete connections that are no longer needed."
### User Story
As a user, I want to delete connections with a clear confirmation to prevent accidental deletion.
### User Story Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Backend
User->>Frontend: Click "Delete" button
Frontend->>Backend: GET /api/connections/
Backend-->>Frontend: Connections list
Frontend->>Frontend: Find connection by ID (for name/authority)
Frontend->>Frontend: Show confirmation dialog<br/>"Delete 'Google Connection'?"
User->>Frontend: Cancel deletion
Frontend-->>User: Dialog closed, no action
User->>Frontend: Click "Delete" button again
Frontend->>Backend: GET /api/connections/
Backend-->>Frontend: Connections list
Frontend->>Frontend: Show confirmation dialog
User->>Frontend: Confirm deletion
Frontend->>Frontend: Optimistic update: Remove connection from UI immediately
Frontend->>Backend: DELETE /api/connections/connectionId
alt Permission denied (403)
Backend-->>Frontend: 403 Forbidden
Frontend->>Frontend: Revert optimistic update: Restore connection in UI
Frontend-->>User: Show permission error
else Not found (404)
Backend-->>Frontend: 404 Not Found
Frontend->>Frontend: Revert optimistic update: Restore connection in UI
Frontend-->>User: Show not found error
else Success (200)
Backend-->>Frontend: Success response
Frontend->>Frontend: Keep optimistic update (connection already removed)
Frontend->>Frontend: Show success message
Frontend-->>User: Display connection list (without deleted connection)
end
```

View file

@ -1,491 +0,0 @@
# Connection Page Requirements
This document contains the complete frontend requirements for all connection management pages and components. All UI components are dynamically generated from backend metadata—no hardcoding required.
## Table of Contents
1. [Overview](#overview)
2. [Page Structure and Layout](#page-structure-and-layout)
3. [User Interactions and Functionality](#user-interactions-and-functionality)
4. [Backend Routes and API Integration](#backend-routes-and-api-integration)
5. [Field and Attribute Reference](#field-and-attribute-reference)
6. [Dynamic Rendering Guidelines](#dynamic-rendering-guidelines)
---
## Overview
The connection management page enables users to manage their OAuth connections (Google, Microsoft) within their account. The frontend consists of a single page (`/connections`) with different views/states:
- **List View** - Browse, search, filter, and sort connections (all information displayed in table)
- **Edit View** - Edit connection properties in popup/modal
All views use backend-driven UI generation, meaning field definitions, labels, validation rules, and UI structure come entirely from backend metadata through the `/api/attributes/UserConnection` endpoint. Views are managed through component state and routing within the same page, not as separate routes.
**Note:** Connections are user-scoped. Users can only see and manage their own connections. The backend enforces this security.
---
## Page Structure and Layout
### Connection Management Page (`/connections`)
The connection management page uses different views/states to handle different user interactions. Views are managed through component state and routing within the same page component.
### List View
**State:** `view === 'list'` or `selectedConnectionId === null`
**What the user sees:**
- **Main Content Area:**
- Table or card grid displaying all connections for the current user
- Each connection row/card shows: authority, external username, external email, status, token status, connected at, last checked
- **Action buttons column** in table (rendered on first load):
- "Edit" button - opens popup/modal edit form
- "Delete" button - shows confirmation dialog and deletes connection
- "Refresh Token" button - refreshes OAuth token for the connection
- All necessary connection information displayed in table (no detail view needed)
- **Search and Filter Controls:**
- General search input box (searches across all text fields)
- Field-specific filter controls (one filter per visible field)
- Active filter indicators (chips/badges showing applied filters)
- "Clear all filters" button when filters are active
- **Note:** Filtering and sorting are done client-side (connections endpoint returns all user connections)
- **Sorting Controls:**
- Clickable column headers with sort indicators (up/down arrows)
- Visual indication of current sort field and direction
- Support for multi-level sorting
- **Note:** Sorting is done client-side
- **Action Buttons:**
- "Connect Google" button - creates Google connection and initiates OAuth flow
- "Connect Microsoft" button - creates Microsoft connection and initiates OAuth flow
### Edit View (Popup/Modal)
**State:** `view === 'edit'` and `selectedConnectionId !== null` (popup/modal overlay)
**What the user sees:**
- **Edit Form in Popup/Modal:**
- Dynamic form with editable connection fields only
- Field labels with required indicators (asterisk for required fields)
- Help text/tooltips from field descriptions
- Input validation errors displayed inline
- Form pre-populated with current connection values
- Save and Cancel buttons in modal footer
- On save: Updates connection, closes modal, refreshes table
- On cancel: Closes modal without saving
- **Confirmation Dialogs:**
- Delete confirmation dialog
---
## User Interactions and Functionality
### Browsing and Discovery
**Search Functionality:**
- User types in general search box
- Frontend debounces input (300-500ms delay)
- Search applies across all text fields in connection objects
- **Client-side filtering** (connections endpoint returns all user connections)
- Results update automatically
**Field Filtering:**
- User selects field to filter by
- Frontend shows appropriate filter UI based on field type:
- Text fields → Text input with operator selection (contains, equals, startsWith, endsWith)
- Select fields → Dropdown with options from backend metadata
- Timestamp fields → Date picker with comparison operators or date range picker
- User applies filter → Filter appears as active chip/badge
- User can remove individual filters
- Multiple filters work together (AND logic)
- **Client-side filtering** (no backend pagination)
**Sorting:**
- User clicks column header
- Sort direction toggles (asc → desc → remove)
- Multiple columns can be sorted (multi-level sorting)
- Sort indicators show on column headers
- All filters and search preserved when sorting
- **Client-side sorting** (no backend pagination)
**View Switching:**
- All connection information displayed in table (no detail view navigation needed)
### Creating Connections
**Create Interaction:**
- User clicks "Connect Google" button → Immediately creates Google connection and initiates OAuth flow
- OR user clicks "Connect Microsoft" button → Immediately creates Microsoft connection and initiates OAuth flow
- No dialog or selection step needed
**Connection Creation:**
- Connection created with PENDING status
- OAuth flow automatically initiated via `/api/connections/{connectionId}/connect`
- User redirected to OAuth provider
- After OAuth completion, connection status updated to ACTIVE
**Connection Submission:**
- For Google: Connection type sent as `{type: "google"}`
- For Microsoft: Connection type sent as `{type: "msft"}`
- Success → Connection created, OAuth flow initiated, user redirected
- Error handling:
- 403 (permission denied) → Show permission error
- 400 (validation errors) → Display backend validation errors
- Other errors → Show generic error message
### Editing Connections
**Edit Interaction:**
- User clicks "Edit" button in table row → Opens popup/modal edit form
- Form pre-populated with current connection values
- User modifies fields (typically externalEmail, status)
- Client-side validation shows errors immediately
- User clicks Save → Form validates and submits
- User clicks Cancel → Closes modal without saving
**Form Validation:**
- Required field validation (shows error if empty)
- Type validation (e.g., email fields must be valid email format)
- Select field validation (value must be in options array)
- Validation errors displayed inline below fields
**Form Submission:**
- Only changed fields sent (or all form data)
- Success → Close popup/modal, refresh table, show success message
- Error handling:
- 403 (permission denied) → Show permission error in modal
- 400 (validation errors) → Display backend validation errors in modal
- Other errors → Show generic error message in modal
### Refreshing Connection Tokens
**Refresh Token Action:**
- User clicks "Refresh Token" button in table
- Frontend shows loading state
- Frontend determines connection authority (Google or Microsoft)
- Frontend calls appropriate refresh endpoint:
- Microsoft: `POST /api/msft/refresh` with `{connectionId: connectionId}`
- Google: `POST /api/google/refresh` with `{connectionId: connectionId}`
- Success → Token refreshed, connection status updated, table refreshed
- Error handling:
- 403 (permission denied) → Show permission error
- 404 (connection not found) → Show not found error
- Other errors → Show generic error message
**Implementation Notes:**
- Refresh button should be disabled or show loading state during refresh
- Token status should update immediately after successful refresh
- Connection status may change from "expired" to "active" after refresh
### Deleting Connections
**Delete Action:**
- User clicks delete button in table
- Confirmation dialog appears with connection authority/type
- Warning about permanent deletion
- User confirms → Connection deleted
- User cancels → Dialog closes, no action
**Delete Success Handling:**
- Success message displayed
- Remove connection from list or refresh table
---
## Backend Routes and API Integration
### Complete Route Reference
All backend routes used by connection pages:
| Route | Method | Purpose | When Used | Access Control |
|-------|--------|---------|-----------|----------------|
| `/api/connections/` | GET | Get all connections for current user | Initial page load | Current user only (returns only user's connections) |
| `/api/connections/` | POST | Create new connection | User selects connection type | Current user only |
| `/api/connections/{connectionId}` | PUT | Update connection | Edit form submission | Current user only |
| `/api/connections/{connectionId}` | DELETE | Delete connection | User confirms deletion | Current user only |
| `/api/connections/{connectionId}/connect` | POST | Initiate OAuth flow | After connection creation | Current user only |
| `/api/msft/refresh` | POST | Refresh Microsoft token | User clicks refresh token for MSFT connection | Current user only |
| `/api/google/refresh` | POST | Refresh Google token | User clicks refresh token for Google connection | Current user only |
| `/api/attributes/UserConnection` | GET | Get field definitions | Page load (once per page) - used to generate all UI components | All authenticated users |
### API Request Patterns
**Get Connections Request:**
```
GET /api/connections/
```
- Returns all connections for the current user (no pagination)
- Response includes token status information
- Filtering and sorting done client-side
**Create Connection Request:**
```
POST /api/connections/
Content-Type: application/json
Body: {
"type": "google" | "msft"
}
```
- Creates connection with PENDING status
- Returns created connection object
- Handle 403 (permission denied) and 400 (validation errors)
**Connect Service Request:**
```
POST /api/connections/{connectionId}/connect
```
- Returns `{authUrl: "/api/google/login?state=..."}` or `{authUrl: "/api/msft/login?state=..."}`
- Frontend should navigate to the authUrl to initiate OAuth flow
- Called automatically after connection creation
**Update Request:**
```
PUT /api/connections/{connectionId}
Content-Type: application/json
Body: {fieldName: value, ...}
```
- Send only changed fields or all form data
- Handle 403 (permission denied) and 400 (validation errors)
**Refresh Token Request:**
```
POST /api/msft/refresh
Content-Type: application/json
Body: {"connectionId": "connection-id"}
```
OR
```
POST /api/google/refresh
Content-Type: application/json
Body: {"connectionId": "connection-id"}
```
- Returns `{message: "Token refreshed successfully", expires_at: timestamp, expires_in_seconds: number}`
- Handle 403 (permission denied) and 404 (connection not found)
**Delete Requests:**
```
DELETE /api/connections/{connectionId}
```
- Delete operation requires user confirmation
- Handle 403 (permission denied) and 404 (not found) gracefully
### Response Handling
**Get Connections Response:**
```json
[
{
"id": "...",
"userId": "...",
"authority": "google",
"externalId": "...",
"externalUsername": "...",
"externalEmail": "...",
"status": "active",
"connectedAt": 1234567890,
"lastChecked": 1234567890,
"expiresAt": 1234567890,
"tokenStatus": "active",
"tokenExpiresAt": 1234567890
},
...
]
```
- Returns array of connections (no pagination)
- Each connection includes token status information
**Error Responses:**
- 403 Forbidden → Show permission error message
- 404 Not Found → Show "not found" error message
- 400 Bad Request → Display validation errors from response
- 500 Internal Server Error → Show generic error message
---
## Field and Attribute Reference
### Complete Field List
The following is a comprehensive list of all parameters, attributes, and fields that will be displayed for connections. All of these are provided by the backend through the `/api/attributes/UserConnection` endpoint and should never be hardcoded in the frontend.
#### Core Connection Fields
**Identification Fields:**
- `id` - Unique connection identifier (text, readonly, not required, visible)
- `userId` - ID of the user this connection belongs to (text, readonly, not required, visible)
**Connection Properties:**
- `authority` - Authentication authority (select, readonly, not required, visible)
- Options: "local", "google", "msft"
- Each option has localized labels (en/fr)
- `externalId` - User ID in the external system (text, readonly, not required, visible)
- `externalUsername` - Username in the external system (text, editable, required, visible)
- `externalEmail` - Email in the external system (email, editable, not required, visible)
- `status` - Connection status (select, editable, not required, visible)
- Options: "active", "inactive", "expired", "pending"
- Each option has localized labels (en/fr)
**Timestamp Fields:**
- `connectedAt` - When the connection was established (timestamp, readonly, not required, visible)
- `lastChecked` - When the connection was last verified (timestamp, readonly, not required, visible)
- `expiresAt` - When the connection expires (timestamp, readonly, not required, visible)
**Token Status Fields:**
- `tokenStatus` - Current token status (select, readonly, not required, visible)
- Options: "active", "expired", "none"
- Each option has localized labels (en/fr)
- `tokenExpiresAt` - When the current token expires (timestamp, readonly, not required, visible)
### Attribute Definition Structure
Each field returned from `/api/attributes/UserConnection` contains:
- `name` - Field name (e.g., "authority", "status", "externalEmail", "id")
- `type` - Field data type (e.g., "text", "select", "email", "timestamp", "checkbox")
- `label` - Localized field label (object with language keys: {"en": "English Label", "fr": "French Label"})
- `description` - Field description text
- `required` - Boolean indicating if field is required
- `readonly` - Boolean indicating if field is read-only
- `editable` - Boolean indicating if field can be edited (inverse of readonly)
- `visible` - Boolean indicating if field should be displayed in UI
- `options` - Array of options for select fields (each option has `value` and localized `label`)
---
## Dynamic Rendering Guidelines
The frontend must render all UI components dynamically based on backend metadata. No field definitions, labels, validation rules, or UI structure should be hardcoded.
### Table Column Generation
When rendering the connection list table:
1. Fetch attribute definitions from `/api/attributes/UserConnection`
2. Filter attributes where `visible: true` to determine which columns to display
3. Use `label` property for column headers (select appropriate language based on user preference)
4. Use `type` property to determine how to format cell values:
- `text` fields → Display as plain text
- `email` fields → Display as clickable mailto link
- `select` fields → Display value using label from options array (match value to option.value, then display option.label)
- `timestamp` fields → Format as relative time ("2 hours ago") or absolute date/time based on user preference
- `checkbox` fields → Display as checkmark icon or "Yes"/"No" text
5. Use `readonly` property to determine if column should be sortable (readonly fields may still be sortable, but editable fields definitely are)
6. Generate click handlers for column headers to update sort parameters (client-side sorting)
7. **Add Actions Column:**
- Render action buttons in each table row on first load
- Include "Edit" button - opens popup/modal edit form
- Include "Delete" button - shows confirmation dialog
- Include "Refresh Token" button - refreshes OAuth token (only for Google/MSFT connections)
- Buttons should be visible and accessible in each row
### Filter Control Generation
When rendering filter controls:
1. Fetch attribute definitions from `/api/attributes/UserConnection`
2. Filter attributes where `visible: true` to determine which filters to show
3. For each visible field, generate appropriate filter UI based on `type`:
- `text` fields → Text input filter (supports "contains", "equals", "startsWith", "endsWith" operators)
- `email` fields → Email input filter
- `select` fields → Dropdown filter with options from `options` array (use localized labels)
- `timestamp` fields → Date range picker or single date picker with comparison operators
- `checkbox` fields → Boolean toggle filter (true/false/any)
4. Use `label` property for filter labels (localized)
5. When user applies filter, update client-side filter state
6. Display active filters as chips/badges showing field label and value
7. Allow removing individual filters
8. **Note:** All filtering is done client-side (connections endpoint returns all user connections)
### Search Implementation
For general search functionality:
1. Display a single search input box (not field-specific)
2. When user types, update client-side search state
3. Debounce search input (wait 300-500ms after user stops typing before filtering)
4. Search applies across all text fields in the connection object
5. **Note:** All searching is done client-side (connections endpoint returns all user connections)
### Form Field Generation
When rendering edit forms:
1. Fetch attribute definitions from `/api/attributes/UserConnection`
2. Filter attributes where `visible: true` AND `editable: true` to determine which fields to show
3. For each editable field, generate appropriate form input based on `type`:
- `text` fields → Text input
- `email` fields → Email input
- `select` fields → Dropdown/select input with options from `options` array (use localized labels)
- `timestamp` fields → Date/time picker
- `checkbox` fields → Checkbox input
4. Use `label` property for field labels (localized)
5. Use `required` property to show required indicators (asterisk, etc.)
6. Use `description` property to show help text or tooltips
7. Validate form before submission:
- Check all `required: true` fields have values
- Validate types (e.g., email fields must be valid email format)
- Validate select fields (value must be in options array)
8. On submit, send only changed fields or all form data to update endpoint
### Display Formatting
When displaying field values:
1. Use `type` property to determine formatting:
- `text` → Display as-is (may need HTML escaping)
- `email` → Display as clickable mailto link
- `select` → Look up value in `options` array and display localized label
- `timestamp` → Format as relative time or absolute date/time
- `checkbox` → Display as checkmark icon or "Yes"/"No" text
2. Handle `null` or `undefined` values gracefully (show "-" or "Not set")
3. Use `readonly` property to determine if field should show edit indicators
4. Special formatting for connection fields:
- Authority → Display as badge with icon (Google, Microsoft)
- Status → Color-code badges (Active = green, Inactive = gray, Expired = red, Pending = yellow)
- Token Status → Color-code badges (Active = green, Expired = red, None = gray)
- Timestamps → Show relative time in list view, absolute date in detail view
### Localization
All labels and options support multiple languages:
1. Use user's preferred language (from user settings or browser locale)
2. Access localized labels from `label` object: `label[userLanguage]` or `label.en` as fallback
3. For select options, use `option.label[userLanguage]` or `option.label.en` as fallback
4. If label for current language is missing, fall back to English
### Key Principles
- Never hardcode field names, labels, types, or validation rules
- Always fetch attribute definitions from backend before rendering UI
- Use attribute metadata to determine what to display and how to display it
- Support all field types dynamically - if backend adds new types, frontend should handle them
- Respect `visible`, `editable`, `readonly`, and `required` flags from backend
- Use localized labels from backend metadata
- Generate filters, forms, and tables entirely from attribute definitions
- When backend adds new fields, frontend should automatically display them without code changes
- Handle all error cases gracefully (403, 404, 400, 500)
- Provide user feedback for all actions (loading states, success messages, error messages)
- **All filtering and sorting is done client-side** (connections endpoint returns all user connections)
- **Users can only see and manage their own connections** (backend enforces this)
---
## Summary
This document provides complete frontend requirements for all connection management pages and components. All requirements follow the principle of **backend-driven UI generation**—no hardcoding of field definitions, labels, or validation rules. The frontend should dynamically generate all UI components from backend metadata provided through the `/api/attributes/UserConnection` endpoint.
**Key Architecture Pattern:** The connection management interface is a single page (`/connections`) with different views managed through component state. All interactions happen within the same page component without separate routes.
**Security Note:** Connections are user-scoped. Users can only see and manage their own connections. The backend enforces this security, and the frontend should never attempt to access other users' connections.
For generic patterns that apply across all entity types (not just connections), see the [Dynamic Forms and Pagination documentation](./dynamic-forms-and-pagination.md).

View file

@ -1,689 +0,0 @@
# Dynamic Forms and Pagination - Generic Frontend Patterns
This document describes the generic, reusable patterns for dynamic form generation and pagination that apply across all entity types in the frontend. These patterns enable completely backend-driven UI generation with no hardcoding.
## Table of Contents
1. [Overview](#overview)
2. [Backend Metadata System](#backend-metadata-system)
3. [Dynamic Form Generation](#dynamic-form-generation)
4. [Pagination System](#pagination-system)
5. [Search and Filtering](#search-and-filtering)
6. [Sorting](#sorting)
7. [Localization](#localization)
8. [Implementation Patterns](#implementation-patterns)
---
## Overview
The frontend uses a **completely backend-driven approach** for generating forms, tables, filters, and pagination controls. All field definitions, labels, validation rules, and UI structure come from the backend through the attribute definition system.
### Key Principles
- **No Hardcoding**: Field names, labels, types, validation rules, and options are never hardcoded
- **Backend-Driven**: All UI components generated from backend metadata
- **Entity-Agnostic**: Same patterns work for workflows, users, mandates, files, prompts, automations, etc.
- **Automatic Updates**: When backend adds new fields, frontend automatically displays them without code changes
- **Localization**: All labels and options support multiple languages from backend
### Applicable Entity Types
These patterns apply to any entity type that has:
- An attributes endpoint: `GET /api/attributes/{EntityType}`
- A list endpoint supporting pagination: `GET /api/{entities}/?pagination=...`
- CRUD operations: Create, Read, Update, Delete
Examples: `ChatWorkflow`, `User`, `Mandate`, `FileItem`, `Prompt`, `AutomationDefinition`, `ChatMessage`, `ChatLog`, etc.
---
## Backend Metadata System
### Attribute Definition Endpoint
Every entity type exposes an attributes endpoint that provides complete metadata:
```
GET /api/attributes/{EntityType}
```
**Examples:**
- `GET /api/attributes/ChatWorkflow`
- `GET /api/attributes/User`
- `GET /api/attributes/Mandate`
- `GET /api/attributes/FileItem`
- `GET /api/attributes/Prompt`
### Attribute Definition Structure
Each attribute returned from the endpoint contains:
- **`name`** - Field name (e.g., "status", "name", "email", "createdAt")
- **`type`** - Field data type (e.g., "text", "select", "integer", "timestamp", "checkbox", "email", "url")
- **`label`** - Localized field label (object with language keys: `{"en": "English Label", "fr": "French Label"}`)
- **`description`** - Field description text (for help text/tooltips)
- **`required`** - Boolean indicating if field is required for validation
- **`readonly`** - Boolean indicating if field is read-only (cannot be edited)
- **`editable`** - Boolean indicating if field can be edited (inverse of readonly)
- **`visible`** - Boolean indicating if field should be displayed in UI
- **`options`** - Array of options for select fields (each option has `value` and localized `label`)
### Response Format
The attributes endpoint returns:
```json
{
"entityType": "ChatWorkflow",
"attributes": [
{
"name": "status",
"type": "select",
"label": {"en": "Status", "fr": "Statut"},
"description": "Current status of the workflow",
"required": false,
"readonly": false,
"editable": true,
"visible": true,
"options": [
{"value": "running", "label": {"en": "Running", "fr": "En cours"}},
{"value": "completed", "label": {"en": "Completed", "fr": "Terminé"}}
]
},
{
"name": "name",
"type": "text",
"label": {"en": "Name", "fr": "Nom"},
"description": "Name of the workflow",
"required": true,
"readonly": false,
"editable": true,
"visible": true
}
// ... more attributes
]
}
```
---
## Dynamic Form Generation
Dynamic forms are generated entirely from backend attribute definitions. The same pattern works for create forms, edit forms, and inline editing.
### Form Generation Process
1. **Fetch Attribute Definitions**
- Call `GET /api/attributes/{EntityType}` when form component mounts
- Store attribute definitions in component state
2. **Filter Attributes**
- For edit forms: Filter where `visible: true` AND `editable: true`
- For create forms: Filter where `visible: true` AND `editable: true` (may exclude readonly fields)
- For display-only: Filter where `visible: true`
3. **Generate Form Fields**
- Iterate through filtered attributes
- Generate appropriate input component based on `type`
- Use `label` for field labels (localized)
- Use `description` for help text/tooltips
- Use `required` to show required indicators
4. **Handle Form Submission**
- Validate form using attribute metadata
- Send form data to appropriate endpoint (POST for create, PUT for update)
- Handle success/error responses
### Field Type to Input Component Mapping
Based on the `type` property, generate appropriate input components:
- **`text`** → Text input (single line)
- **`textarea`** → Multi-line text area
- **`select`** → Dropdown/select input with options from `options` array
- **`integer`** → Number input (integer only)
- **`float`** or **`number`** → Number input (decimal allowed)
- **`timestamp`** → Date/time picker
- **`date`** → Date picker (date only)
- **`time`** → Time picker (time only)
- **`checkbox`** → Checkbox input (boolean)
- **`email`** → Email input (with email validation)
- **`url`** → URL input (with URL validation)
- **`password`** → Password input (masked)
- **`file`** → File upload input
### Form Field Rendering Rules
For each form field:
1. **Field Label**
- Use `label[userLanguage]` or `label.en` as fallback
- Show required indicator (asterisk, etc.) if `required: true`
2. **Input Component**
- Generate based on `type` property
- For `select` fields: Populate options from `options` array, use localized labels
- For `integer`/`number` fields: Set appropriate min/max constraints if available
- For `timestamp`/`date`/`time` fields: Use appropriate date/time picker component
3. **Help Text**
- Display `description` as help text or tooltip
- Show below or next to input field
4. **Validation**
- Mark field as required if `required: true`
- Validate type (e.g., integer fields must be numbers)
- Validate select fields (value must be in options array)
- Validate email/url fields with appropriate regex patterns
5. **Disabled State**
- Disable input if `readonly: true` or `editable: false`
- Show read-only indicator if applicable
### Form Validation
Before form submission:
1. **Required Field Validation**
- Check all fields where `required: true` have non-empty values
- Show error messages for missing required fields
2. **Type Validation**
- Validate integer fields contain valid integers
- Validate number fields contain valid numbers
- Validate email fields contain valid email addresses
- Validate URL fields contain valid URLs
- Validate timestamp/date fields contain valid dates
3. **Option Validation**
- For select fields, ensure value exists in `options` array
- Show error if invalid option selected
4. **Custom Validation**
- Apply any additional validation rules from backend metadata if available
### Form Submission
On form submit:
1. **Collect Form Data**
- Gather values from all form fields
- Use attribute `name` as keys in form data object
2. **Prepare Request**
- For create: `POST /api/{entities}` with form data
- For update: `PUT /api/{entities}/{id}` with form data
- Include only changed fields (for updates) or all form data (for creates)
3. **Handle Response**
- On success: Show success message, navigate or refresh as appropriate
- On error: Display validation errors from backend, highlight invalid fields
---
## Pagination System
Pagination is a unified system that works across all list endpoints. It supports pagination, sorting, filtering, and general search in a consistent way.
### Pagination Endpoint Pattern
All list endpoints support pagination through a query parameter:
```
GET /api/{entities}/?pagination={JSON_ENCODED_PAGINATION_PARAMS}
```
**Examples:**
- `GET /api/workflows/?pagination={"page":1,"pageSize":20,"sort":[],"filters":null}`
- `GET /api/users/?pagination={"page":1,"pageSize":20,"sort":[{"field":"name","direction":"asc"}],"filters":{"status":"active"}}`
- `GET /api/files/list?pagination={"page":2,"pageSize":50,"sort":[],"filters":{"search":"report"}}`
### Pagination Request Parameters
The `pagination` query parameter is a JSON-encoded object with the following structure:
**`PaginationParams` Structure:**
- **`page`** - Current page number (1-based, minimum 1)
- **`pageSize`** - Number of items per page (minimum 1, maximum 1000)
- **`sort`** - Array of sort field configurations
- Each sort field contains:
- `field` - Field name to sort by (must match an attribute name)
- `direction` - Sort direction: "asc" or "desc"
- **`filters`** - Filter criteria dictionary (see [Search and Filtering](#search-and-filtering))
**Example:**
```json
{
"page": 1,
"pageSize": 20,
"sort": [
{"field": "lastActivity", "direction": "desc"},
{"field": "name", "direction": "asc"}
],
"filters": {
"search": "invoice",
"status": "running"
}
}
```
### Pagination Response Structure
All paginated endpoints return data in this format:
```json
{
"items": [
// Array of entity objects
],
"pagination": {
"currentPage": 1,
"pageSize": 20,
"totalItems": 45,
"totalPages": 3,
"sort": [
{"field": "lastActivity", "direction": "desc"}
],
"filters": {
"search": "invoice",
"status": "running"
}
}
}
```
**`PaginationMetadata` Structure:**
- **`currentPage`** - Current page number (1-based)
- **`pageSize`** - Number of items per page
- **`totalItems`** - Total number of items across all pages (after filters applied)
- **`totalPages`** - Total number of pages (calculated from totalItems / pageSize)
- **`sort`** - Current sort configuration applied (array of SortField objects)
- **`filters`** - Current filters applied (mirrors request filters)
### Pagination UI Components
Generate pagination controls using the `pagination` metadata from response:
1. **Page Information Display**
- Show "Page X of Y" (using `currentPage` and `totalPages`)
- Show "Showing X-Y of Z items" (calculate from `currentPage`, `pageSize`, `totalItems`)
2. **Page Navigation Controls**
- Previous page button (disabled if `currentPage === 1`)
- Next page button (disabled if `currentPage === totalPages`)
- Page number buttons (show current page and adjacent pages)
- First page button (if not on first page)
- Last page button (if not on last page)
3. **Page Size Selector**
- Dropdown to change `pageSize` (common options: 10, 20, 50, 100)
- When changed, reset to page 1 and refetch
4. **Page Change Handler**
- When user clicks page number or navigation button:
- Update `page` in pagination parameters
- Preserve all filters and sort settings
- Refetch data with updated pagination
### Non-Paginated Requests
If user wants all items without pagination:
- Omit `pagination` parameter entirely: `GET /api/{entities}/`
- Backend returns all items (still wrapped in `PaginatedResponse` with `pagination: null`)
---
## Search and Filtering
The pagination system supports both general search and field-specific filtering. Both are combined in the `filters` object.
### General Search
General search searches across all text fields in the entity.
**Implementation:**
1. Display a single search input box (not field-specific)
2. When user types, update `filters.search` in pagination parameters
3. Debounce search input (wait 300-500ms after user stops typing before sending request)
4. Reset to page 1 when search query changes
5. Combine search with field-specific filters (both are in the `filters` object)
**Filter Structure:**
```json
{
"filters": {
"search": "invoice"
}
}
```
### Field-Specific Filtering
Field-specific filters allow filtering by individual fields with various operators.
**Filter Structure:**
Simple equals filter:
```json
{
"filters": {
"status": "running"
}
}
```
Filter with operator:
```json
{
"filters": {
"name": {
"operator": "contains",
"value": "workflow"
}
}
}
```
**Supported Operators:**
- **`equals`** or **`eq`** - Exact match
- **`contains`** - Substring match (case-insensitive for strings)
- **`startsWith`** - String starts with (case-insensitive)
- **`endsWith`** - String ends with (case-insensitive)
- **`gt`** - Greater than (for numbers/dates)
- **`gte`** - Greater than or equal
- **`lt`** - Less than
- **`lte`** - Less than or equal
- **`in`** - Value in list (array of values)
- **`notIn`** - Value not in list (array of values)
**Multiple Filters:**
All filters are combined with AND logic:
```json
{
"filters": {
"search": "invoice",
"status": "running",
"currentRound": {
"operator": "gt",
"value": 0
}
}
}
```
### Filter Control Generation
Generate filter controls dynamically from attribute definitions:
1. **Fetch Attribute Definitions**
- Call `GET /api/attributes/{EntityType}` when filter component mounts
- Filter attributes where `visible: true` to determine which filters to show
2. **Generate Filter UI by Type**
- **`text`** fields → Text input filter (supports "contains", "equals", "startsWith", "endsWith" operators)
- **`select`** fields → Dropdown filter with options from `options` array (use localized labels)
- **`integer`** or **`number`** fields → Number range filter (min/max inputs) or single number input with comparison operators (gt, gte, lt, lte)
- **`timestamp`** or **`date`** fields → Date range picker or single date picker with comparison operators
- **`checkbox`** fields → Boolean toggle filter (true/false/any)
3. **Filter Labels**
- Use `label` property for filter labels (localized)
- Display filter label next to filter control
4. **Apply Filters**
- When user applies filter, update `filters[fieldName]` in pagination parameters
- Support multiple filters simultaneously
- Reset to page 1 when filters change
- Refetch data with updated filters
5. **Active Filter Indicators**
- Display active filters as chips/badges showing field label and value
- Allow removing individual filters by removing them from `filters` object
- Show "Clear all filters" button when filters are active
### Combined Search and Filters
Search and field filters work together:
- Both are stored in the `filters` object
- All filters are combined with AND logic
- When any filter changes, combine all and refetch
- Preserve all active filters when sorting or changing pages
---
## Sorting
Sorting allows users to order list items by one or more fields.
### Sort Configuration
Sorting is configured in the `sort` array of pagination parameters:
```json
{
"sort": [
{"field": "lastActivity", "direction": "desc"},
{"field": "name", "direction": "asc"}
]
}
```
- Multiple sort fields create multi-level sorting (sorts by first field, then by second field for ties)
- Sort fields are applied in order (first field is primary sort, second is secondary sort, etc.)
### Sort UI Implementation
1. **Column Header Sorting**
- Make column headers clickable for sortable columns
- Show sort indicator (arrow up/down) next to column header when sorted
- Clicking a column header:
- If not currently sorted by that column: Add sort field with "asc" direction
- If sorted ascending: Change to "desc"
- If sorted descending: Remove sort field (or change to "asc" if keeping)
- Update `sort` array in pagination parameters
- Preserve all filters and search
- Refetch data with updated sort
2. **Sort Indicator Display**
- Show up arrow (↑) for ascending sort
- Show down arrow (↓) for descending sort
- Show both arrows when column is sortable but not currently sorted
- Hide sort indicators for non-sortable columns
3. **Multi-Level Sort**
- When user clicks a second column header, add it to the `sort` array
- Display multiple sort indicators if multiple columns are sorted
- Allow removing individual sort fields
### Sortable Columns
Determine which columns are sortable:
- All visible columns can potentially be sortable
- Backend handles sorting logic, so frontend can attempt to sort any field
- If backend doesn't support sorting a field, it will ignore that sort field
- Readonly fields may still be sortable (e.g., timestamps, IDs)
---
## Localization
All labels and options support multiple languages from the backend.
### Language Detection
1. **User Language Preference**
- Get user's preferred language from user settings
- Fall back to browser locale if user setting not available
- Default to "en" (English) if no language detected
2. **Label Access Pattern**
- Access localized labels from `label` object: `label[userLanguage]`
- Fall back to `label.en` if label for current language is missing
- For select options: `option.label[userLanguage]` or `option.label.en` as fallback
### Localized Components
Apply localization to:
1. **Form Fields**
- Field labels: `attribute.label[userLanguage]`
- Help text/descriptions: `attribute.description` (may be localized if backend provides)
- Select options: `option.label[userLanguage]`
- Validation error messages: Use localized messages
2. **Table Columns**
- Column headers: `attribute.label[userLanguage]`
- Cell values for select fields: `option.label[userLanguage]`
3. **Filter Controls**
- Filter labels: `attribute.label[userLanguage]`
- Filter options: `option.label[userLanguage]`
4. **Pagination Controls**
- "Page X of Y" text: Use localized strings
- "Showing X-Y of Z items" text: Use localized strings
- Button labels (Previous, Next, etc.): Use localized strings
---
## Implementation Patterns
### Pattern 1: Generic List Page Component
A reusable list page component that works for any entity type:
**Component Structure:**
1. Accept `entityType` as prop (e.g., "ChatWorkflow", "User", "Mandate")
2. Fetch attributes: `GET /api/attributes/{entityType}`
3. Fetch list data: `GET /api/{entities}/?pagination=...`
4. Generate table columns from attributes
5. Generate filter controls from attributes
6. Handle pagination, search, filtering, and sorting
7. Handle row clicks (navigate to detail page)
**State Management:**
- Store attribute definitions
- Store pagination parameters (page, pageSize, sort, filters)
- Store pagination metadata from response
- Store list items
- Store loading/error states
**User Interactions:**
- Search input → Update `filters.search`
- Filter controls → Update `filters[fieldName]`
- Column header clicks → Update `sort` array
- Page navigation → Update `page`
- Page size change → Update `pageSize`, reset to page 1
### Pattern 2: Generic Form Component
A reusable form component that works for any entity type:
**Component Structure:**
1. Accept `entityType` and `mode` as props ("create" or "edit")
2. Accept `entityId` as prop (for edit mode)
3. Fetch attributes: `GET /api/attributes/{entityType}`
4. Fetch entity data (for edit mode): `GET /api/{entities}/{id}`
5. Generate form fields from attributes
6. Handle form submission
7. Handle validation
**Form Field Generation:**
- Filter attributes: `visible: true` AND `editable: true`
- Generate input components based on `type`
- Apply labels, descriptions, required indicators
- Handle validation
**Form Submission:**
- Validate form using attribute metadata
- For create: `POST /api/{entities}` with form data
- For update: `PUT /api/{entities}/{id}` with form data
- Handle success/error responses
### Pattern 3: Generic Table Component
A reusable table component that works for any entity type:
**Component Structure:**
1. Accept `attributes` and `items` as props
2. Generate columns from attributes (filter `visible: true`)
3. Render table rows with formatted cell values
4. Handle column header clicks for sorting
5. Handle row clicks for navigation
**Cell Value Formatting:**
- Use `type` property to determine formatting
- Format select fields using options array
- Format timestamps as relative/absolute time
- Format numbers with separators
- Handle null/undefined values
### Pattern 4: Generic Filter Component
A reusable filter component that works for any entity type:
**Component Structure:**
1. Accept `attributes` and `filters` as props
2. Generate filter controls from attributes (filter `visible: true`)
3. Handle filter changes
4. Display active filters as chips/badges
5. Allow removing individual filters
**Filter Control Generation:**
- Generate appropriate filter UI based on `type`
- Use localized labels
- Support multiple operators for text/number fields
- Update filters object and trigger refetch
### Key Implementation Guidelines
1. **Never Hardcode**
- Never hardcode field names, labels, types, or validation rules
- Always fetch attribute definitions from backend
- Use attribute metadata for all UI generation
2. **Entity-Agnostic**
- Same components work for all entity types
- Pass `entityType` as parameter to determine endpoints
- Use generic prop names (attributes, items, etc.)
3. **State Management**
- Keep pagination state separate from entity data
- Preserve filters and sort when changing pages
- Reset to page 1 when filters/search change
4. **Error Handling**
- Handle API errors gracefully
- Display validation errors from backend
- Show loading states during API calls
5. **Performance**
- Debounce search input (300-500ms)
- Cache attribute definitions (don't refetch on every render)
- Use pagination to limit data fetched
6. **Accessibility**
- Use semantic HTML for forms and tables
- Provide ARIA labels for form fields
- Ensure keyboard navigation works
- Support screen readers
---
## Summary
This generic system enables:
- **Complete Backend-Driven UI**: All forms, tables, filters generated from backend metadata
- **Zero Hardcoding**: No field definitions, labels, or validation rules in frontend code
- **Automatic Updates**: New backend fields automatically appear in frontend
- **Consistent UX**: Same patterns across all entity types
- **Localization**: Multi-language support from backend metadata
- **Reusable Components**: Generic components work for all entity types
By following these patterns, the frontend becomes a thin presentation layer that dynamically renders UI based on backend metadata, ensuring consistency, maintainability, and automatic adaptation to backend changes.

View file

@ -1,335 +0,0 @@
# File Routes Frontend Documentation
This document describes customer journeys for managing files through the frontend, focusing on how users interact with file management and how the backend routes support these experiences. All UI components are dynamically generated from backend metadata—no hardcoding required.
## Table of Contents
1. [Overview](#overview)
2. [Customer Journey 1: Discovering and Browsing Files](#customer-journey-1-discovering-and-browsing-files)
3. [Customer Journey 2: Uploading Files](#customer-journey-2-uploading-files)
4. [Customer Journey 3: Editing File Properties](#customer-journey-3-editing-file-properties)
5. [Customer Journey 4: Downloading Files](#customer-journey-4-downloading-files)
6. [Customer Journey 5: Adding File to Prompt](#customer-journey-5-adding-file-to-prompt)
7. [Customer Journey 6: Deleting Files](#customer-journey-6-deleting-files)
---
## Overview
The file routes (`/api/files`) enable users to manage files within their mandate. These routes focus on **file administration** including upload, editing, download, preview, and deletion.
**Key Principles:**
- **User-Centric**: Documentation organized around what users want to accomplish
- **Backend-Driven**: All forms, tables, and UI components generated from backend metadata
- **No Hardcoding**: Field definitions, labels, validation rules, and options come from the backend
- **Permission-Aware**: Backend enforces permissions; frontend handles gracefully
- **Mandate-Scoped**: Files are managed within the context of mandates
---
## Customer Journey 1: Discovering and Browsing Files
### User Goal
"I want to see all files in my mandate and find the one I'm looking for."
### User Story
As a user, I want to browse files, search for specific files, filter by any field, sort them by different criteria, and quickly identify files by their name, size, type, and creation date.
### User Story Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Backend
User->>Frontend: Navigate to /files
Frontend->>Backend: GET /api/attributes/FileItem
Backend-->>Frontend: Attribute definitions (fields, labels, types)
Frontend->>Backend: GET /api/files/list?pagination=...
Backend-->>Frontend: Paginated files list
Frontend->>Frontend: Generate table columns from attributes
Frontend->>Frontend: Generate filter controls from attributes
Frontend->>Frontend: Render files table + search + filters
Frontend->>Frontend: Render action buttons in table (Edit, Delete, Download, Add to Prompt)
Frontend-->>User: Display file list with search/filter UI + action buttons
alt User performs general search
User->>Frontend: Type in search box (e.g., "invoice")
Frontend->>Frontend: Update search query
Frontend->>Backend: GET /api/files/list?pagination=...filters:{"search":"invoice"}
Backend-->>Frontend: Filtered files list
Frontend-->>User: Display matching files
end
alt User applies field filter
User->>Frontend: Select filter field (e.g., "MIME Type")
Frontend->>Frontend: Show filter options from attribute metadata
User->>Frontend: Select filter value (e.g., "application/pdf")
Frontend->>Frontend: Update filter parameters
Frontend->>Backend: GET /api/files/list?pagination=...filters:{"mimeType":"application/pdf"}
Backend-->>Frontend: Filtered files list
Frontend-->>User: Display filtered files
end
alt User combines search + filter + sort
User->>Frontend: Apply search + filter + sort
Frontend->>Frontend: Combine all parameters
Frontend->>Backend: GET /api/files/list?pagination=...filters:{"search":"invoice","mimeType":"application/pdf"}...sort:desc
Backend-->>Frontend: Filtered, sorted files list
Frontend-->>User: Display results
end
User->>Frontend: Click column header (e.g., "File Size")
Frontend->>Frontend: Update sort parameters
Frontend->>Backend: GET /api/files/list?pagination=...sort:desc
Backend-->>Frontend: Sorted files list
Frontend-->>User: Display sorted files
```
---
## Customer Journey 2: Uploading Files
### User Goal
"I want to upload new files to my mandate."
### User Story
As a user, I want to upload files by selecting them from my device. The system should validate file size, handle duplicates, and show clear feedback about the upload status.
### User Story Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Backend
alt User clicks "Upload File" button
User->>Frontend: Click "Upload File" button
Frontend->>Frontend: Show file upload dialog/input
Frontend-->>User: Display file picker
User->>Frontend: Select file(s) from device
else User drags and drops files
User->>Frontend: Drag file(s) over upload area
Frontend->>Frontend: Highlight drop zone
User->>Frontend: Drop file(s) on upload area
Frontend->>Frontend: Accept dropped files
end
Frontend->>Frontend: Optimistic update: Show loading state, add file to UI immediately
Frontend->>Backend: POST /api/files/upload + file data
alt Permission denied (403)
Backend-->>Frontend: 403 Forbidden
Frontend->>Frontend: Revert optimistic update: Remove file from UI
Frontend-->>User: Show permission error
else Success (201)
Backend-->>Frontend: Created file object + duplicate info
Frontend->>Frontend: Keep optimistic update
Frontend->>Backend: GET /api/files/list?pagination=... (refetch)
Backend-->>Frontend: Updated files list
Frontend->>Frontend: Update table with fresh data
Frontend-->>User: Show success message (with duplicate info if applicable)
end
```
---
## Customer Journey 3: Editing File Properties
### User Goal
"I want to change the file name through an edit form."
### User Story
As a user, I want to edit a file's name through a popup/modal form, with validation and clear error messages.
### User Story Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Backend
User->>Frontend: Click "Edit" button in table row
Frontend->>Backend: GET /api/files/fileId
Backend-->>Frontend: Current file data
Frontend->>Backend: GET /api/attributes/FileItem
Backend-->>Frontend: Field definitions (editable fields)
Frontend->>Frontend: Filter editable fields
Frontend->>Frontend: Generate form from attributes
Frontend->>Frontend: Pre-populate form with file data
Frontend->>Frontend: Open popup/modal with edit form
Frontend-->>User: Display edit form in popup/modal
User->>Frontend: Modify file name
User->>Frontend: Click "Save"
Frontend->>Frontend: Validate form (required fields, types)
alt Validation fails
Frontend-->>User: Show validation errors in modal
else Validation passes
Frontend->>Frontend: Optimistic update: Apply changes to UI immediately
Frontend->>Backend: PUT /api/files/fileId + form data
alt Permission denied (403)
Backend-->>Frontend: 403 Forbidden
Frontend->>Frontend: Revert optimistic update
Frontend-->>User: Show permission error in modal
else Validation error (400)
Backend-->>Frontend: 400 Bad Request + error details
Frontend->>Frontend: Revert optimistic update
Frontend-->>User: Show backend validation errors in modal
else Success (200)
Backend-->>Frontend: Updated file
Frontend->>Frontend: Keep optimistic update (or refresh from response)
Frontend->>Backend: GET /api/files/list?pagination=... (refetch)
Backend-->>Frontend: Updated files list
Frontend->>Frontend: Update table with fresh data
Frontend->>Frontend: Close popup/modal
Frontend-->>User: Show updated file name in table
end
end
alt User clicks Cancel
User->>Frontend: Click "Cancel" button
Frontend->>Frontend: Close popup/modal without saving
Frontend-->>User: Modal closed, no changes
end
```
---
## Customer Journey 4: Downloading Files
### User Goal
"I want to download files to my device."
### User Story
As a user, I want to download files by clicking a download button, so I can save them locally on my device.
### User Story Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Backend
User->>Frontend: Click "Download" button in table
Frontend->>Frontend: Show loading state
Frontend->>Backend: GET /api/files/fileId/download
alt Permission denied (403)
Backend-->>Frontend: 403 Forbidden
Frontend-->>User: Show permission error
else File not found (404)
Backend-->>Frontend: 404 Not Found
Frontend-->>User: Show not found error
else Success (200)
Backend-->>Frontend: File content with Content-Disposition header
Frontend->>Frontend: Trigger browser download
Frontend-->>User: File downloads to device
end
```
---
## Customer Journey 5: Adding File to Prompt
### User Goal
"I want to use a file with a prompt in the chat playground."
### User Story
As a user, I want to add a file to the chat playground so I can use it with a prompt to start a workflow.
### User Story Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Backend
User->>Frontend: Click "Add to Prompt" button in table
Frontend->>Backend: GET /api/files/fileId
Backend-->>Frontend: File object (id, fileName)
Frontend->>Frontend: Navigate to /chat-playground
Frontend->>Frontend: Pre-select file in file picker/attachments
Frontend->>Frontend: Show file name as context
Frontend-->>User: Display chat playground with file attached
User->>Frontend: Enter prompt text
User->>Frontend: Optionally add more files
User->>Frontend: Click "Start" or "Send" button
Frontend->>Frontend: Validate user input (prompt required)
alt Validation fails
Frontend-->>User: Show validation errors
else Validation passes
Frontend->>Backend: POST /api/chat/playground/start?workflowMode=Dynamic<br/>Body: {prompt: userPrompt, listFileId: [fileId, ...], userLanguage: "en"}
alt Permission denied (403)
Backend-->>Frontend: 403 Forbidden
Frontend-->>User: Show permission error
else Validation error (400)
Backend-->>Frontend: 400 Bad Request + error details
Frontend-->>User: Show backend validation errors
else Success (200)
Backend-->>Frontend: Created workflow object
Frontend->>Frontend: Update chat playground UI with workflow
Frontend-->>User: Show workflow started, display messages/logs
end
end
```
---
## Customer Journey 6: Deleting Files
### User Goal
"I want to delete files that are no longer needed."
### User Story
As a user, I want to delete files with a clear confirmation to prevent accidental deletion.
### User Story Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Backend
User->>Frontend: Click "Delete" button
Frontend->>Backend: GET /api/files/fileId
Backend-->>Frontend: File data (for name)
Frontend->>Frontend: Show confirmation dialog<br/>"Delete 'File Name'?"
User->>Frontend: Cancel deletion
Frontend-->>User: Dialog closed, no action
User->>Frontend: Click "Delete" button again
Frontend->>Backend: GET /api/files/fileId
Backend-->>Frontend: File data
Frontend->>Frontend: Show confirmation dialog
User->>Frontend: Confirm deletion
Frontend->>Frontend: Optimistic update: Remove file from UI immediately
Frontend->>Backend: DELETE /api/files/fileId
alt Permission denied (403)
Backend-->>Frontend: 403 Forbidden
Frontend->>Frontend: Revert optimistic update: Restore file in UI
Frontend-->>User: Show permission error
else Not found (404)
Backend-->>Frontend: 404 Not Found
Frontend->>Frontend: Revert optimistic update: Restore file in UI
Frontend-->>User: Show not found error
else Success (200)
Backend-->>Frontend: Success response
Frontend->>Frontend: Keep optimistic update (file already removed)
Frontend->>Frontend: Show success message
Frontend->>Frontend: Navigate to /files (if on detail page)
Frontend-->>User: Display file list (without deleted file)
end
```

View file

@ -1,574 +0,0 @@
# File Page Requirements
This document contains the complete frontend requirements for all file management pages and components. All UI components are dynamically generated from backend metadata—no hardcoding required.
## Table of Contents
1. [Overview](#overview)
2. [Page Structure and Layout](#page-structure-and-layout)
3. [User Interactions and Functionality](#user-interactions-and-functionality)
4. [Backend Routes and API Integration](#backend-routes-and-api-integration)
5. [Field and Attribute Reference](#field-and-attribute-reference)
6. [Dynamic Rendering Guidelines](#dynamic-rendering-guidelines)
---
## Overview
The file management page enables users to manage files within their mandate. The frontend consists of a single page (`/files`) with different views/states:
- **List View** - Browse, search, filter, and sort files (all information displayed in table)
- **Edit View** - Edit file properties in popup/modal
- **Upload View** - Upload new files
All views use backend-driven UI generation, meaning field definitions, labels, validation rules, and UI structure come entirely from backend metadata through the `/api/attributes/FileItem` endpoint. Views are managed through component state and routing within the same page, not as separate routes.
---
## Page Structure and Layout
### File Management Page (`/files`)
The file management page uses different views/states to handle different user interactions. Views are managed through component state and routing within the same page component.
### List View
**State:** `view === 'list'` or `selectedFileId === null`
**What the user sees:**
- **Main Content Area:**
- Table or card grid displaying all files in the mandate
- Each file row/card shows: file name, MIME type, file size, creation date, mandate ID
- **Action buttons column** in table (rendered on first load):
- "Edit" button - opens popup/modal edit form for file name
- "Delete" button - shows confirmation dialog and deletes file
- "Download" button - downloads file to user's device
- "Add to Prompt" button - navigates to `/chat-playground` with file attached
- All necessary file information displayed in table (no detail view needed)
- **Search and Filter Controls:**
- General search input box (searches across all text fields)
- Field-specific filter controls (one filter per visible field)
- Active filter indicators (chips/badges showing applied filters)
- "Clear all filters" button when filters are active
- **Sorting Controls:**
- Clickable column headers with sort indicators (up/down arrows)
- Visual indication of current sort field and direction
- Support for multi-level sorting
- **Pagination Controls:**
- Page information display ("Page X of Y", "Showing 1-20 of 45 files")
- Previous/Next page buttons
- Page number buttons
- Page size selector (10, 20, 50, 100 items per page)
- **Action Buttons:**
- "Upload File" button - opens file upload dialog
### Edit View (Popup/Modal)
**State:** `view === 'edit'` and `selectedFileId !== null` (popup/modal overlay)
**What the user sees:**
- **Edit Form in Popup/Modal:**
- Dynamic form with editable file fields only (typically fileName)
- Field labels with required indicators (asterisk for required fields)
- Help text/tooltips from field descriptions
- Input validation errors displayed inline
- Form pre-populated with current file values
- Save and Cancel buttons in modal footer
- On save: Updates file name, closes modal, refreshes table
- On cancel: Closes modal without saving
### Upload View
**State:** `view === 'upload'` or upload dialog open
**What the user sees:**
- **Upload Dialog/Form:**
- File input/picker for selecting files
- Drag-and-drop area with visual feedback
- Selected files list with preview
- Upload progress indicator
- Duplicate file handling information
- **Action Buttons:**
- Upload button (starts upload)
- Cancel button (closes upload dialog)
- **Confirmation Dialogs:**
- Delete confirmation dialog (on file detail page)
---
## User Interactions and Functionality
### Browsing and Discovery
**Search Functionality:**
- User types in general search box
- Frontend debounces input (300-500ms delay)
- Search applies across all text fields in file objects
- Results update automatically
- Page resets to page 1 when search changes
**Field Filtering:**
- User selects field to filter by
- Frontend shows appropriate filter UI based on field type:
- Text fields → Text input with operator selection (contains, equals, startsWith, endsWith)
- Integer fields → Number input with comparison operators (gt, gte, lt, lte) or range inputs
- Timestamp fields → Date picker with comparison operators or date range picker
- Select fields → Dropdown with options from backend metadata
- User applies filter → Filter appears as active chip/badge
- User can remove individual filters
- Multiple filters work together (AND logic)
- Page resets to page 1 when filters change
**Sorting:**
- User clicks column header
- Sort direction toggles (asc → desc → remove)
- Multiple columns can be sorted (multi-level sorting)
- Sort indicators show on column headers
- All filters and search preserved when sorting
**Pagination:**
- User clicks page number or navigation button
- Page updates and data refetches
- All filters, search, and sort preserved
- User changes page size → Page resets to 1, data refetches
**View Switching:**
- All file information displayed in table (no detail view navigation needed)
### Uploading Files
**Upload Interaction:**
- User clicks "Upload File" button → Opens upload dialog/form
- OR user drags and drops file(s) onto upload area
- Drag and drop area highlights when files are dragged over
- User selects file(s) from device picker OR drops file(s) on upload area
- File upload starts immediately (no size validation)
- User clicks Cancel → Closes upload dialog, no action
**Drag and Drop Support:**
- Upload area supports drag and drop functionality
- Visual feedback when files are dragged over (highlight drop zone)
- Multiple files can be dropped at once
- Files are accepted and uploaded immediately upon drop
**Upload Submission:**
- File sent as multipart/form-data
- Optional `workflowId` parameter can be included
- No file size validation (all file sizes accepted)
- Success → File appears in list, show success message with duplicate info if applicable
- Error handling:
- 403 (permission denied) → Show permission error
- 400 (validation errors) → Display backend validation errors
- Other errors → Show generic error message
**Duplicate Handling:**
- Backend returns duplicate information in response
- Frontend displays appropriate message:
- Exact duplicate → "File already exists with identical content. Reusing existing file."
- Name conflict → "File already exists with different content. Uploaded as '[new name]'."
- New file → "File uploaded successfully"
### Editing Files
**Edit Interaction:**
- User clicks "Edit" button in table row → Opens popup/modal edit form
- Form pre-populated with current file values
- User modifies file name in form
- Client-side validation shows errors immediately
- User clicks Save → Form validates and submits
- User clicks Cancel → Closes modal without saving
**Form Validation:**
- Required field validation (shows error if empty)
- Type validation (e.g., text fields must be valid text)
- Validation errors displayed inline below fields
**Form Submission:**
- Only changed fields sent (or all form data)
- Success → Close popup/modal, refresh table, show success message
- Error handling:
- 403 (permission denied) → Show permission error in modal
- 400 (validation errors) → Display backend validation errors in modal
- Other errors → Show generic error message in modal
### Downloading Files
**Download Action:**
- User clicks "Download" button in table
- Frontend shows loading state
- Frontend calls `GET /api/files/{fileId}/download`
- Browser triggers download with proper filename
- Success → File downloads to user's device
- Error handling:
- 403 (permission denied) → Show permission error
- 404 (not found) → Show not found error
- Other errors → Show generic error message
**Implementation Notes:**
- Download should use proper Content-Disposition header handling
- Filename should be properly encoded for Unicode characters
### Adding File to Prompt
**Add to Prompt Action:**
- User clicks "Add to Prompt" button in table
- Frontend fetches file data to get file ID
- Frontend navigates to `/chat-playground` page
- Frontend pre-selects the file in the file picker/attachments area
- Frontend displays file name as context
- User can enter prompt text and optionally add more files
- User clicks "Start" or "Send" button
- Frontend calls `POST /api/chat/playground/start` with file ID in `listFileId` array
**Add to Prompt Submission:**
- File ID included in `listFileId` array in request body
- Prompt text required (user must enter prompt)
- Success → Workflow starts with file attached, chat playground updates
- Error handling:
- 403 (permission denied) → Show permission error
- 400 (validation errors) → Display backend validation errors
- Other errors → Show generic error message
### Deleting Files
**Delete Action:**
- User clicks delete button (on detail page or list)
- Confirmation dialog appears with file name
- Warning about permanent deletion
- User confirms → File deleted
- User cancels → Dialog closes, no action
**Delete Success Handling:**
- Success message displayed
- Remove file from list or refresh table
---
## Backend Routes and API Integration
### Complete Route Reference
All backend routes used by file pages:
| Route | Method | Purpose | When Used | Access Control |
|-------|--------|---------|-----------|----------------|
| `/api/files/list` | GET | Get all files (with pagination) | Initial page load, pagination changes, sort changes, filter changes, search changes | All authenticated users (filtered by mandate) |
| `/api/files/{fileId}` | GET | Get file details | Detail page load, edit page load | All authenticated users |
| `/api/files/{fileId}` | PUT | Update file | Edit form submission | All authenticated users |
| `/api/files/{fileId}` | DELETE | Delete file | User confirms deletion | All authenticated users |
| `/api/files/upload` | POST | Upload file | User selects and uploads file | All authenticated users |
| `/api/files/{fileId}/download` | GET | Download file | User clicks download button | All authenticated users |
| `/api/files/stats` | GET | Get file statistics | Optional: display statistics on page | All authenticated users |
| `/api/chat/playground/start` | POST | Start workflow with file | User clicks "Add to Prompt" and starts workflow | All authenticated users |
| `/api/attributes/FileItem` | GET | Get field definitions | Page load (once per page) - used to generate all UI components | All authenticated users |
### API Request Patterns
**Pagination Request:**
```
GET /api/files/list?pagination={"page":1,"pageSize":20,"sort":[],"filters":null}
```
- `pagination` parameter is JSON-encoded string
- If user wants all files: omit `pagination` parameter entirely
- Filters structure: `{"search":"query","fieldName":"value",...}`
- Optional `mandateId` query parameter to filter by mandate
**Upload Request:**
```
POST /api/files/upload
Content-Type: multipart/form-data
Body: {
file: <file data>,
workflowId: "optional-workflow-id" (optional)
}
```
- File sent as multipart/form-data
- `workflowId` is optional form field
- No file size limits (all sizes accepted)
- Handle 403 (permission denied) and 400 (validation errors)
- Response includes duplicate information:
```json
{
"message": "File uploaded successfully",
"file": {...},
"duplicateType": "new_file" | "exact_duplicate" | "name_conflict",
"originalFileName": "...",
"storedFileName": "...",
"isDuplicate": false
}
```
**Update Request:**
```
PUT /api/files/{fileId}
Content-Type: application/json
Body: {fieldName: value, ...}
```
- Send only changed fields or all form data
- Handle 403 (permission denied) and 400 (validation errors)
**Download Request:**
```
GET /api/files/{fileId}/download
```
- Returns file content with Content-Disposition header
- Browser automatically triggers download
- Filename properly encoded for Unicode characters
**Add to Prompt Request:**
```
POST /api/chat/playground/start?workflowMode=Dynamic
Content-Type: application/json
Body: {
"prompt": "User prompt text here...",
"listFileId": ["fileId1", "fileId2"],
"userLanguage": "en"
}
```
- `workflowMode` query parameter is required: "Actionplan", "Dynamic", or "Template" (default: "Dynamic")
- `listFileId` array contains file IDs to attach (includes the file from "Add to Prompt" button)
- `prompt` field contains user's prompt text
- `userLanguage` should match user's preferred language
- Handle 403 (permission denied) and 400 (validation errors)
**Delete Requests:**
```
DELETE /api/files/{fileId}
```
- Delete operation requires user confirmation
- Handle 403 (permission denied) and 404 (not found) gracefully
### Response Handling
**Paginated Response:**
```json
{
"items": [...],
"pagination": {
"currentPage": 1,
"pageSize": 20,
"totalItems": 45,
"totalPages": 3,
"sort": [...],
"filters": {...}
}
}
```
**Error Responses:**
- 403 Forbidden → Show permission error message
- 404 Not Found → Show "not found" error message
- 400 Bad Request → Display validation errors from response
- 500 Internal Server Error → Show generic error message
---
## Field and Attribute Reference
### Complete Field List
The following is a comprehensive list of all parameters, attributes, and fields that will be displayed for files. All of these are provided by the backend through the `/api/attributes/FileItem` endpoint and should never be hardcoded in the frontend.
#### Core File Fields
**Identification Fields:**
- `id` - Unique file identifier (text, readonly, not required, visible)
- `mandateId` - ID of the mandate this file belongs to (text, readonly, not required, visible)
**File Properties:**
- `fileName` - Name of the file (text, editable, required, visible)
- `mimeType` - MIME type of the file (text, readonly, not required, visible)
- `fileHash` - Hash of the file (text, readonly, not required, visible)
- `fileSize` - Size of the file in bytes (integer, readonly, not required, visible)
- `creationDate` - Date when the file was created (timestamp, readonly, not required, visible)
### Pagination Parameters
**Request Parameters (`PaginationParams`):**
- `page` - Current page number (1-based, minimum 1)
- `pageSize` - Number of items per page (minimum 1, maximum 1000)
- `sort` - Array of sort field configurations
- Each sort field contains:
- `field` - Field name to sort by (must match a file field name)
- `direction` - Sort direction: "asc" or "desc"
- `filters` - Filter criteria dictionary
- `search` - General search term (searches across all text fields, case-insensitive)
- Field-specific filters: `{fieldName: value}` or `{fieldName: {operator: "operator", value: value}}`
- Supported operators: "equals", "contains", "startsWith", "endsWith", "gt", "gte", "lt", "lte", "in", "notIn"
**Response Metadata (`PaginationMetadata`):**
- `currentPage` - Current page number (1-based)
- `pageSize` - Number of items per page
- `totalItems` - Total number of items across all pages (after filters applied)
- `totalPages` - Total number of pages (calculated from totalItems / pageSize)
- `sort` - Current sort configuration applied (array of SortField objects)
- `filters` - Current filters applied (mirrors request filters)
### Attribute Definition Structure
Each field returned from `/api/attributes/FileItem` contains:
- `name` - Field name (e.g., "fileName", "mimeType", "fileSize", "id")
- `type` - Field data type (e.g., "text", "integer", "timestamp", "checkbox")
- `label` - Localized field label (object with language keys: {"en": "English Label", "fr": "French Label"})
- `description` - Field description text
- `required` - Boolean indicating if field is required
- `readonly` - Boolean indicating if field is read-only
- `editable` - Boolean indicating if field can be edited (inverse of readonly)
- `visible` - Boolean indicating if field should be displayed in UI
- `options` - Array of options for select fields (each option has `value` and localized `label`)
---
## Dynamic Rendering Guidelines
The frontend must render all UI components dynamically based on backend metadata. No field definitions, labels, validation rules, or UI structure should be hardcoded.
### Table Column Generation
When rendering the file list table:
1. Fetch attribute definitions from `/api/attributes/FileItem`
2. Filter attributes where `visible: true` to determine which columns to display
3. Use `label` property for column headers (select appropriate language based on user preference)
4. Use `type` property to determine how to format cell values:
- `text` fields → Display as plain text
- `integer` fields → Display as formatted number (for fileSize, show human-readable format like "1.5 MB")
- `timestamp` fields → Format as relative time ("2 hours ago") or absolute date/time based on user preference
- `select` fields → Display value using label from options array (match value to option.value, then display option.label)
- `checkbox` fields → Display as checkmark icon or "Yes"/"No" text
5. Use `readonly` property to determine if column should be sortable (readonly fields may still be sortable, but editable fields definitely are)
6. Generate click handlers for column headers to update sort parameters and refetch data
7. **Add Actions Column:**
- Render action buttons in each table row on first load
- Include "Edit" button - opens popup/modal edit form for file name
- Include "Delete" button - shows confirmation dialog
- Include "Download" button - triggers file download
- Include "Add to Prompt" button - navigates to `/chat-playground` with file attached
- Buttons should be visible and accessible in each row
### Filter Control Generation
When rendering filter controls:
1. Fetch attribute definitions from `/api/attributes/FileItem`
2. Filter attributes where `visible: true` to determine which filters to show
3. For each visible field, generate appropriate filter UI based on `type`:
- `text` fields → Text input filter (supports "contains", "equals", "startsWith", "endsWith" operators)
- `integer` fields → Number range filter (min/max inputs) or single number input with comparison operators (gt, gte, lt, lte)
- `timestamp` fields → Date range picker or single date picker with comparison operators
- `select` fields → Dropdown filter with options from `options` array (use localized labels)
- `checkbox` fields → Boolean toggle filter (true/false/any)
4. Use `label` property for filter labels (localized)
5. When user applies filter, update `filters` object in pagination parameters and refetch data
6. Display active filters as chips/badges showing field label and value
7. Allow removing individual filters by removing them from `filters` object
### Search Implementation
For general search functionality:
1. Display a single search input box (not field-specific)
2. When user types, update `filters.search` in pagination parameters
3. Debounce search input (wait 300-500ms after user stops typing before sending request)
4. Search applies across all text fields in the file object
5. Reset to page 1 when search query changes
6. Combine search with field-specific filters (both are in the `filters` object)
### Form Field Generation
When rendering edit forms:
1. Fetch attribute definitions from `/api/attributes/FileItem`
2. Filter attributes where `visible: true` AND `editable: true` to determine which fields to show
3. For each editable field, generate appropriate form input based on `type`:
- `text` fields → Text input
- `integer` fields → Number input with appropriate min/max constraints
- `timestamp` fields → Date/time picker
- `select` fields → Dropdown/select input with options from `options` array (use localized labels)
- `checkbox` fields → Checkbox input
4. Use `label` property for field labels (localized)
5. Use `required` property to show required indicators (asterisk, etc.)
6. Use `description` property to show help text or tooltips
7. Validate form before submission:
- Check all `required: true` fields have values
- Validate types (e.g., integer fields must be numbers)
- Validate select fields (value must be in options array)
8. On submit, send only changed fields or all form data to update endpoint
### Display Formatting
When displaying field values:
1. Use `type` property to determine formatting:
- `text` → Display as-is (may need HTML escaping)
- `integer` → Format with thousand separators if needed
- For `fileSize` field specifically → Format as human-readable (e.g., "1.5 MB", "500 KB", "2.3 GB")
- `timestamp` → Format as relative time or absolute date/time
- `select` → Look up value in `options` array and display localized label
- `checkbox` → Display as checkmark icon or "Yes"/"No" text
2. Handle `null` or `undefined` values gracefully (show "-" or "Not set")
3. Use `readonly` property to determine if field should show edit indicators
4. Special formatting for file fields:
- File Size → Always show in human-readable format (bytes → KB → MB → GB)
- MIME Type → Display as badge with icon if possible
- File Hash → Display as truncated hash (first 8-12 characters) with copy button
- Creation Date → Show relative time in list view, absolute date in detail view
### File Size Formatting
For the `fileSize` field (integer in bytes), always format as human-readable:
```typescript
function formatFileSize(bytes: number): string {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return Math.round(bytes / Math.pow(k, i) * 100) / 100 + ' ' + sizes[i];
}
```
### Localization
All labels and options support multiple languages:
1. Use user's preferred language (from user settings or browser locale)
2. Access localized labels from `label` object: `label[userLanguage]` or `label.en` as fallback
3. For select options, use `option.label[userLanguage]` or `option.label.en` as fallback
4. If label for current language is missing, fall back to English
### Key Principles
- Never hardcode field names, labels, types, or validation rules
- Always fetch attribute definitions from backend before rendering UI
- Use attribute metadata to determine what to display and how to display it
- Support all field types dynamically - if backend adds new types, frontend should handle them
- Respect `visible`, `editable`, `readonly`, and `required` flags from backend
- Use localized labels from backend metadata
- Generate filters, forms, and tables entirely from attribute definitions
- When backend adds new fields, frontend should automatically display them without code changes
- Handle all error cases gracefully (403, 404, 400, 413, 500)
- Provide user feedback for all actions (loading states, success messages, error messages)
- Format file sizes in human-readable format
- Handle file uploads with proper duplicate detection feedback
---
## Summary
This document provides complete frontend requirements for all file management pages and components. All requirements follow the principle of **backend-driven UI generation**—no hardcoding of field definitions, labels, or validation rules. The frontend should dynamically generate all UI components from backend metadata provided through the `/api/attributes/FileItem` endpoint.
**Key Architecture Pattern:** The file management interface is a single page (`/files`) with different views managed through component state. All interactions happen within the same page component without separate routes.
For generic patterns that apply across all entity types (not just files), see the [Dynamic Forms and Pagination documentation](./dynamic-forms-and-pagination.md).

View file

@ -1,349 +0,0 @@
# Prompt Routes Frontend Documentation
This document describes customer journeys for managing prompts through the frontend, focusing on how users interact with prompt management and how the backend routes support these experiences. All UI components are dynamically generated from backend metadata—no hardcoding required.
## Table of Contents
1. [Overview](#overview)
2. [Customer Journey 1: Discovering and Browsing Prompts](#customer-journey-1-discovering-and-browsing-prompts)
3. [Customer Journey 2: Viewing Prompt Details](#customer-journey-2-viewing-prompt-details)
4. [Customer Journey 3: Creating New Prompts](#customer-journey-3-creating-new-prompts)
5. [Customer Journey 4: Editing Prompt Properties](#customer-journey-4-editing-prompt-properties)
6. [Customer Journey 5: Starting a Prompt Workflow](#customer-journey-5-starting-a-prompt-workflow)
7. [Customer Journey 6: Deleting Prompts](#customer-journey-6-deleting-prompts)
---
## Overview
The prompt routes (`/api/prompts`) enable users to manage prompts within their mandate. These routes focus on **prompt administration** including creation, editing, and deletion.
**Key Principles:**
- **User-Centric**: Documentation organized around what users want to accomplish
- **Backend-Driven**: All forms, tables, and UI components generated from backend metadata
- **No Hardcoding**: Field definitions, labels, validation rules, and options come from the backend
- **Permission-Aware**: Backend enforces permissions; frontend handles gracefully
- **Mandate-Scoped**: Prompts are managed within the context of mandates
---
## Customer Journey 1: Discovering and Browsing Prompts
### User Goal
"I want to see all prompts in my mandate and find the one I'm looking for."
### User Story
As a user, I want to browse prompts, search for specific prompts, filter by any field, sort them by different criteria, and quickly identify prompts by their name and content.
### User Story Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Backend
User->>Frontend: Navigate to /prompts
Frontend->>Backend: GET /api/attributes/Prompt
Backend-->>Frontend: Attribute definitions (fields, labels, types)
Frontend->>Backend: GET /api/prompts/?pagination=...
Backend-->>Frontend: Paginated prompts list
Frontend->>Frontend: Generate table columns from attributes
Frontend->>Frontend: Generate filter controls from attributes
Frontend->>Frontend: Render prompts table + search + filters
Frontend->>Frontend: Render action buttons in table (Start Prompt, Edit, Delete)
Frontend-->>User: Display prompt list with search/filter UI + action buttons
alt User performs general search
User->>Frontend: Type in search box (e.g., "invoice")
Frontend->>Frontend: Update search query
Frontend->>Backend: GET /api/prompts/?pagination=...filters:{"search":"invoice"}
Backend-->>Frontend: Filtered prompts list
Frontend-->>User: Display matching prompts
end
alt User applies field filter
User->>Frontend: Select filter field (e.g., "Name")
Frontend->>Frontend: Show filter options from attribute metadata
User->>Frontend: Select filter value (e.g., "Invoice")
Frontend->>Frontend: Update filter parameters
Frontend->>Backend: GET /api/prompts/?pagination=...filters:{"name":"Invoice"}
Backend-->>Frontend: Filtered prompts list
Frontend-->>User: Display filtered prompts
end
alt User combines search + filter + sort
User->>Frontend: Apply search + filter + sort
Frontend->>Frontend: Combine all parameters
Frontend->>Backend: GET /api/prompts/?pagination=...filters:{"search":"invoice","name":"Invoice"}...sort:desc
Backend-->>Frontend: Filtered, sorted prompts list
Frontend-->>User: Display results
end
User->>Frontend: Click column header (e.g., "Name")
Frontend->>Frontend: Update sort parameters
Frontend->>Backend: GET /api/prompts/?pagination=...sort:desc
Backend-->>Frontend: Sorted prompts list
Frontend-->>User: Display sorted prompts
User->>Frontend: Click prompt row
Frontend->>Frontend: Navigate to /prompts/promptId
Frontend-->>User: Show prompt detail page
```
---
## Customer Journey 2: Viewing Prompt Details
### User Goal
"I want to see everything about a specific prompt—its name and full content."
### User Story
As a user, I want to open a prompt and see its complete information, including name, content, and mandate association.
### User Story Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Backend
User->>Frontend: Click prompt from list
Frontend->>Backend: GET /api/prompts/promptId
Backend-->>Frontend: Prompt object
Frontend->>Backend: GET /api/attributes/Prompt
Backend-->>Frontend: Field definitions
Frontend->>Frontend: Generate UI from metadata
Frontend->>Frontend: Render prompt info section
Frontend->>Frontend: Separate editable vs read-only fields
Frontend-->>User: Display complete prompt view
alt User has editable fields and permission
Frontend->>Frontend: Show "Edit Prompt" button
end
alt User has permission
Frontend->>Frontend: Show "Delete Prompt" button
end
```
---
## Customer Journey 3: Creating New Prompts
### User Goal
"I want to create new prompts for my mandate."
### User Story
As a user, I want to create a new prompt by filling out a form with its name and content. The form should validate all required fields and show clear error messages.
### User Story Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Backend
User->>Frontend: Click "Create Prompt" button
Frontend->>Frontend: Navigate to /prompts/create
Frontend->>Backend: GET /api/attributes/Prompt
Backend-->>Frontend: Field definitions (editable fields)
Frontend->>Frontend: Filter editable fields
Frontend->>Frontend: Generate form from attributes
Frontend-->>User: Display create prompt form
User->>Frontend: Fill in form fields
User->>Frontend: Click "Create"
Frontend->>Frontend: Validate form (required fields, types)
alt Validation fails
Frontend-->>User: Show validation errors
else Validation passes
Frontend->>Frontend: Optimistic update: Show loading state, prepare UI for new prompt
Frontend->>Backend: POST /api/prompts + form data
alt Permission denied (403)
Backend-->>Frontend: 403 Forbidden
Frontend->>Frontend: Revert optimistic update: Show form with error
Frontend-->>User: Show permission error
else Validation error (400)
Backend-->>Frontend: 400 Bad Request + error details
Frontend->>Frontend: Revert optimistic update: Show form with errors
Frontend-->>User: Show backend validation errors
else Success (200)
Backend-->>Frontend: Created prompt object
Frontend->>Frontend: Keep optimistic update
Frontend->>Backend: GET /api/prompts/promptId (refetch)
Backend-->>Frontend: Created prompt object
Frontend->>Frontend: Update UI with fresh data
Frontend->>Frontend: Navigate to prompt detail page
Frontend-->>User: Show created prompt
end
end
```
---
## Customer Journey 4: Editing Prompt Properties
### User Goal
"I want to change prompt settings like its name or content."
### User Story
As a user, I want to edit a prompt's properties through a form that only shows fields I'm allowed to edit, with validation and clear error messages.
### User Story Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Backend
User->>Frontend: Click "Edit" button
Frontend->>Frontend: Navigate to /prompts/id/edit
Frontend->>Backend: GET /api/prompts/promptId
Backend-->>Frontend: Current prompt data
Frontend->>Backend: GET /api/attributes/Prompt
Backend-->>Frontend: Field definitions (editable fields)
Frontend->>Frontend: Filter editable fields
Frontend->>Frontend: Generate form from attributes
Frontend->>Frontend: Pre-populate form with prompt data
Frontend-->>User: Display edit form
User->>Frontend: Modify form fields
User->>Frontend: Click "Save"
Frontend->>Frontend: Validate form (required fields, types)
alt Validation fails
Frontend-->>User: Show validation errors
else Validation passes
Frontend->>Frontend: Optimistic update: Apply changes to UI immediately
Frontend->>Backend: PUT /api/prompts/promptId + form data
alt Permission denied (403)
Backend-->>Frontend: 403 Forbidden
Frontend->>Frontend: Revert optimistic update
Frontend-->>User: Show permission error
else Validation error (400)
Backend-->>Frontend: 400 Bad Request + error details
Frontend->>Frontend: Revert optimistic update
Frontend-->>User: Show backend validation errors
else Success (200)
Backend-->>Frontend: Updated prompt
Frontend->>Frontend: Keep optimistic update (or refresh from response)
Frontend->>Backend: GET /api/prompts/promptId (refetch)
Backend-->>Frontend: Updated prompt object
Frontend->>Frontend: Update UI with fresh data
Frontend->>Frontend: Navigate to detail page
Frontend-->>User: Show updated prompt
end
end
```
---
## Customer Journey 5: Starting a Prompt Workflow
### User Goal
"I want to start a workflow using a prompt I've created."
### User Story
As a user, I want to start a workflow in the chat playground using a prompt's content, so I can execute the prompt and see the results.
### User Story Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Backend
User->>Frontend: Click "Start Prompt" button in table
Frontend->>Backend: GET /api/prompts/promptId
Backend-->>Frontend: Prompt object (name, content)
Frontend->>Frontend: Navigate to /chat-playground
Frontend->>Frontend: Pre-fill prompt content in chat input
Frontend->>Frontend: Show prompt name as context
Frontend-->>User: Display chat playground with prompt loaded
User->>Frontend: Optionally modify prompt or add files
User->>Frontend: Click "Start" or "Send" button
Frontend->>Frontend: Validate user input
alt Validation fails
Frontend-->>User: Show validation errors
else Validation passes
Frontend->>Backend: POST /api/chat/playground/start?workflowMode=Dynamic<br/>Body: {prompt: promptContent, listFileId: [...], userLanguage: "en"}
alt Permission denied (403)
Backend-->>Frontend: 403 Forbidden
Frontend-->>User: Show permission error
else Validation error (400)
Backend-->>Frontend: 400 Bad Request + error details
Frontend-->>User: Show backend validation errors
else Success (200)
Backend-->>Frontend: Created workflow object
Frontend->>Frontend: Update chat playground UI with workflow
Frontend-->>User: Show workflow started, display messages/logs
end
end
```
---
## Customer Journey 6: Deleting Prompts
### User Goal
"I want to delete prompts that are no longer needed."
### User Story
As a user, I want to delete prompts with a clear confirmation to prevent accidental deletion.
### User Story Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Backend
User->>Frontend: Click "Delete" button
Frontend->>Backend: GET /api/prompts/promptId
Backend-->>Frontend: Prompt data (for name)
Frontend->>Frontend: Show confirmation dialog<br/>"Delete 'Prompt Name'?"
User->>Frontend: Cancel deletion
Frontend-->>User: Dialog closed, no action
User->>Frontend: Click "Delete" button again
Frontend->>Backend: GET /api/prompts/promptId
Backend-->>Frontend: Prompt data
Frontend->>Frontend: Show confirmation dialog
User->>Frontend: Confirm deletion
Frontend->>Frontend: Optimistic update: Remove prompt from UI immediately
Frontend->>Backend: DELETE /api/prompts/promptId
alt Permission denied (403)
Backend-->>Frontend: 403 Forbidden
Frontend->>Frontend: Revert optimistic update: Restore prompt in UI
Frontend-->>User: Show permission error
else Not found (404)
Backend-->>Frontend: 404 Not Found
Frontend->>Frontend: Revert optimistic update: Restore prompt in UI
Frontend-->>User: Show not found error
else Success (200)
Backend-->>Frontend: Success response
Frontend->>Frontend: Keep optimistic update (prompt already removed)
Frontend->>Frontend: Show success message
Frontend->>Frontend: Navigate to /prompts (if on detail page)
Frontend-->>User: Display prompt list (without deleted prompt)
end
```

View file

@ -1,549 +0,0 @@
# Prompt Page Requirements
This document contains the complete frontend requirements for all prompt management pages and components. All UI components are dynamically generated from backend metadata—no hardcoding required.
## Table of Contents
1. [Overview](#overview)
2. [Page Structure and Layout](#page-structure-and-layout)
3. [User Interactions and Functionality](#user-interactions-and-functionality)
4. [Backend Routes and API Integration](#backend-routes-and-api-integration)
5. [Field and Attribute Reference](#field-and-attribute-reference)
6. [Dynamic Rendering Guidelines](#dynamic-rendering-guidelines)
---
## Overview
The prompt management page enables users to manage prompts within their mandate. The frontend consists of a single page (`/prompts`) with different views/states:
- **List View** - Browse, search, filter, and sort prompts
- **Edit View** - Edit prompt properties
- **Create View** - Create new prompts
All views use backend-driven UI generation, meaning field definitions, labels, validation rules, and UI structure come entirely from backend metadata through the `/api/attributes/Prompt` endpoint. Views are managed through component state and routing within the same page, not as separate routes.
---
## Page Structure and Layout
### Prompt Management Page (`/prompts`)
The prompt management page uses different views/states to handle different user interactions. Views are managed through component state and routing within the same page component.
### List View
**State:** `view === 'list'` or `selectedPromptId === null`
**What the user sees:**
- **Main Content Area:**
- Table or card grid displaying all prompts in the mandate
- Each prompt row/card shows: name, content preview, mandate ID
- **Action buttons column** in table (rendered on first load):
- "Start Prompt" button - navigates to `/chat-playground` and starts workflow with prompt content
- "Edit" button - switches to Edit View
- "Delete" button - shows confirmation dialog and deletes prompt
- Clickable rows/cards that switch to Detail View (set selectedPromptId and view state)
- **Search and Filter Controls:**
- General search input box (searches across all text fields)
- Field-specific filter controls (one filter per visible field)
- Active filter indicators (chips/badges showing applied filters)
- "Clear all filters" button when filters are active
- **Sorting Controls:**
- Clickable column headers with sort indicators (up/down arrows)
- Visual indication of current sort field and direction
- Support for multi-level sorting
- **Pagination Controls:**
- Page information display ("Page X of Y", "Showing 1-20 of 45 prompts")
- Previous/Next page buttons
- Page number buttons
- Page size selector (10, 20, 50, 100 items per page)
- **Action Buttons:**
- "Create Prompt" button - switches to Create View
### Detail View
**State:** `view === 'detail'` and `selectedPromptId !== null`
**What the user sees:**
- **Prompt Header Section:**
- Prompt name (editable indicator if user has permission)
- Mandate ID (read-only)
- **Prompt Information Section:**
- All prompt properties displayed as formatted fields
- Read-only fields shown as formatted text
- Editable fields shown with edit indicators (if user has permission)
- Special formatting:
- Content → Display as formatted textarea or code block (if applicable)
- Name → Display as heading
- **Action Buttons:**
- Start Prompt button - navigates to `/chat-playground` and starts workflow with prompt content
- Edit button (if user has permission and editable fields exist) - switches to Edit View
- Delete button (if user has permission)
### Edit View
**State:** `view === 'edit'` and `selectedPromptId !== null`
**What the user sees:**
- **Form Section:**
- Dynamic form with editable prompt fields only
- Field labels with required indicators (asterisk for required fields)
- Help text/tooltips from field descriptions
- Input validation errors displayed inline
- **Action Buttons:**
- Save button (submits form)
- Cancel button (switches back to Detail View)
### Create View
**State:** `view === 'create'`
**What the user sees:**
- **Form Section:**
- Dynamic form with all editable prompt fields
- Field labels with required indicators
- Help text/tooltips from field descriptions
- Input validation errors displayed inline
- **Action Buttons:**
- Create button (submits form)
- Cancel button (switches back to List View)
- **Confirmation Dialogs:**
- Delete confirmation dialog (on prompt detail page)
---
## User Interactions and Functionality
### Browsing and Discovery
**Search Functionality:**
- User types in general search box
- Frontend debounces input (300-500ms delay)
- Search applies across all text fields in prompt objects
- Results update automatically
- Page resets to page 1 when search changes
**Field Filtering:**
- User selects field to filter by
- Frontend shows appropriate filter UI based on field type:
- Text fields → Text input with operator selection (contains, equals, startsWith, endsWith)
- Textarea fields → Text input filter
- Select fields → Dropdown with options from backend metadata
- Email fields → Email input filter
- Checkbox fields → Boolean toggle (true/false/any)
- User applies filter → Filter appears as active chip/badge
- User can remove individual filters
- Multiple filters work together (AND logic)
- Page resets to page 1 when filters change
**Sorting:**
- User clicks column header
- Sort direction toggles (asc → desc → remove)
- Multiple columns can be sorted (multi-level sorting)
- Sort indicators show on column headers
- All filters and search preserved when sorting
**Pagination:**
- User clicks page number or navigation button
- Page updates and data refetches
- All filters, search, and sort preserved
- User changes page size → Page resets to 1, data refetches
**View Switching:**
- User clicks prompt row/card → Switches to Detail View (set selectedPromptId and view state)
- User clicks prompt name → Switches to Detail View (set selectedPromptId and view state)
### Viewing Prompt Details
**Information Display:**
- All prompt fields displayed using dynamic rendering
- Read-only fields shown as formatted text
- Editable fields shown with edit indicators
- Special fields formatted appropriately (content as formatted text)
**Action Availability:**
- Edit button shown if editable fields exist and user has permission
- Delete button shown if user has permission
### Creating Prompts
**Form Interaction:**
- User clicks "Create Prompt" button → Switches to Create View (set `view: 'create'`)
- Form shows all editable fields
- User fills in fields
- Client-side validation shows errors immediately
- User clicks Create → Form validates and submits
- User clicks Cancel → Switches back to List View (set `view: 'list'`, `selectedPromptId: null`)
**Form Validation:**
- Required field validation (shows error if empty)
- Type validation (e.g., textarea fields must be valid text)
- Validation errors displayed inline below fields
**Form Submission:**
- Prompt data sent as Prompt object
- Success → Switch to Detail View for created prompt (set `selectedPromptId` to new prompt ID, `view: 'detail'`)
- Error handling:
- 403 (permission denied) → Show permission error
- 400 (validation errors) → Display backend validation errors
- Other errors → Show generic error message
### Editing Prompts
**Form Interaction:**
- User clicks "Edit" button → Switches to Edit View (set `view: 'edit'`)
- Form pre-populated with current prompt values
- User modifies fields
- Client-side validation shows errors immediately
- User clicks Save → Form validates and submits
- User clicks Cancel → Switches back to Detail View (set `view: 'detail'`)
**Form Validation:**
- Required field validation (shows error if empty)
- Type validation (e.g., textarea fields must be valid text)
- Validation errors displayed inline below fields
**Form Submission:**
- Only changed fields sent (or all form data)
- Success → Switch back to Detail View (set `view: 'detail'`) and show success message
- Error handling:
- 403 (permission denied) → Show permission error
- 400 (validation errors) → Display backend validation errors
- Other errors → Show generic error message
### Starting Prompts
**Start Prompt Action:**
- User clicks "Start Prompt" button in table row or detail page
- Frontend fetches prompt data to get prompt content
- Frontend navigates to `/chat-playground` page
- Frontend pre-fills the chat input with the prompt's content
- Frontend displays prompt name as context (optional)
- User can optionally modify the prompt or add files before starting
- User clicks "Start" or "Send" button in chat playground
- Frontend calls `POST /api/chat/playground/start` with:
- `workflowMode` query parameter: "Dynamic" (default) or user-selected mode
- `userInput` body: `{prompt: promptContent, listFileId: [...], userLanguage: "en"}`
**Start Prompt Submission:**
- Success → Workflow starts, chat playground updates with workflow data, messages/logs appear
- Error handling:
- 403 (permission denied) → Show permission error
- 400 (validation errors) → Display backend validation errors
- Other errors → Show generic error message
**Implementation Notes:**
- Action buttons (Start Prompt, Edit, Delete) are rendered in the table on first load
- Buttons should be visible in each table row
- Start Prompt button should be clearly distinguished (e.g., primary button style)
- Navigation to chat playground should preserve prompt context
### Deleting Prompts
**Delete Action:**
- User clicks delete button (on detail page or list)
- Confirmation dialog appears with prompt name
- Warning about permanent deletion
- User confirms → Prompt deleted
- User cancels → Dialog closes, no action
**Delete Success Handling:**
- Success message displayed
- If in Detail View → Switch back to List View (set `view: 'list'`, `selectedPromptId: null`)
- If in List View → Remove prompt from list or refresh
---
## Backend Routes and API Integration
### Complete Route Reference
All backend routes used by prompt pages:
| Route | Method | Purpose | When Used | Access Control |
|-------|--------|---------|-----------|----------------|
| `/api/prompts/` | GET | Get all prompts (with pagination) | Initial page load, pagination changes, sort changes, filter changes, search changes | All authenticated users (filtered by mandate) |
| `/api/prompts/{promptId}` | GET | Get prompt details | Detail page load, edit page load | All authenticated users |
| `/api/prompts/{promptId}` | PUT | Update prompt | Edit form submission | All authenticated users |
| `/api/prompts/{promptId}` | DELETE | Delete prompt | User confirms deletion | All authenticated users |
| `/api/prompts` | POST | Create prompt | Create form submission | All authenticated users |
| `/api/attributes/Prompt` | GET | Get field definitions | Page load (once per page) - used to generate all UI components | All authenticated users |
| `/api/chat/playground/start` | POST | Start workflow with prompt | User clicks "Start Prompt" button | All authenticated users |
### API Request Patterns
**Pagination Request:**
```
GET /api/prompts/?pagination={"page":1,"pageSize":20,"sort":[],"filters":null}
```
- `pagination` parameter is JSON-encoded string
- If user wants all prompts: omit `pagination` parameter entirely
- Filters structure: `{"search":"query","fieldName":"value",...}`
- Optional `mandateId` query parameter to filter by mandate
**Create Request:**
```
POST /api/prompts
Content-Type: application/json
Body: {
"name": "Invoice Processing",
"content": "Process the following invoice..."
}
```
- All Prompt model fields sent as Prompt object
- Handle 403 (permission denied) and 400 (validation errors)
**Update Request:**
```
PUT /api/prompts/{promptId}
Content-Type: application/json
Body: {fieldName: value, ...}
```
- Send only changed fields or all form data
- Handle 403 (permission denied) and 400 (validation errors)
**Start Prompt Request:**
```
POST /api/chat/playground/start?workflowMode=Dynamic
Content-Type: application/json
Body: {
"prompt": "Prompt content here...",
"listFileId": ["file1", "file2"],
"userLanguage": "en"
}
```
- `workflowMode` query parameter is required: "Actionplan", "Dynamic", or "Template" (default: "Dynamic")
- `prompt` field contains the prompt's content
- `listFileId` is optional array of file IDs to attach
- `userLanguage` should match user's preferred language
- Handle 403 (permission denied) and 400 (validation errors)
**Delete Requests:**
```
DELETE /api/prompts/{promptId}
```
- Delete operation requires user confirmation
- Handle 403 (permission denied) and 404 (not found) gracefully
### Response Handling
**Paginated Response:**
```json
{
"items": [...],
"pagination": {
"currentPage": 1,
"pageSize": 20,
"totalItems": 45,
"totalPages": 3,
"sort": [...],
"filters": {...}
}
}
```
**Error Responses:**
- 403 Forbidden → Show permission error message
- 404 Not Found → Show "not found" error message
- 400 Bad Request → Display validation errors from response
- 500 Internal Server Error → Show generic error message
---
## Field and Attribute Reference
### Complete Field List
The following is a comprehensive list of all parameters, attributes, and fields that will be displayed for prompts. All of these are provided by the backend through the `/api/attributes/Prompt` endpoint and should never be hardcoded in the frontend.
#### Core Prompt Fields
**Identification Fields:**
- `id` - Unique prompt identifier (text, readonly, not required, visible)
- `mandateId` - ID of the mandate this prompt belongs to (text, readonly, not required, visible)
**Content Fields:**
- `name` - Name of the prompt (text, editable, required, visible)
- `content` - Content of the prompt (textarea, editable, required, visible)
### Pagination Parameters
**Request Parameters (`PaginationParams`):**
- `page` - Current page number (1-based, minimum 1)
- `pageSize` - Number of items per page (minimum 1, maximum 1000)
- `sort` - Array of sort field configurations
- Each sort field contains:
- `field` - Field name to sort by (must match a prompt field name)
- `direction` - Sort direction: "asc" or "desc"
- `filters` - Filter criteria dictionary
- `search` - General search term (searches across all text fields, case-insensitive)
- Field-specific filters: `{fieldName: value}` or `{fieldName: {operator: "operator", value: value}}`
- Supported operators: "equals", "contains", "startsWith", "endsWith", "in", "notIn"
**Response Metadata (`PaginationMetadata`):**
- `currentPage` - Current page number (1-based)
- `pageSize` - Number of items per page
- `totalItems` - Total number of items across all pages (after filters applied)
- `totalPages` - Total number of pages (calculated from totalItems / pageSize)
- `sort` - Current sort configuration applied (array of SortField objects)
- `filters` - Current filters applied (mirrors request filters)
### Attribute Definition Structure
Each field returned from `/api/attributes/Prompt` contains:
- `name` - Field name (e.g., "name", "content", "id")
- `type` - Field data type (e.g., "text", "textarea", "select", "checkbox")
- `label` - Localized field label (object with language keys: {"en": "English Label", "fr": "French Label"})
- `description` - Field description text
- `required` - Boolean indicating if field is required
- `readonly` - Boolean indicating if field is read-only
- `editable` - Boolean indicating if field can be edited (inverse of readonly)
- `visible` - Boolean indicating if field should be displayed in UI
- `options` - Array of options for select fields (each option has `value` and localized `label`)
---
## Dynamic Rendering Guidelines
The frontend must render all UI components dynamically based on backend metadata. No field definitions, labels, validation rules, or UI structure should be hardcoded.
### Table Column Generation
When rendering the prompt list table:
1. Fetch attribute definitions from `/api/attributes/Prompt`
2. Filter attributes where `visible: true` to determine which columns to display
3. Use `label` property for column headers (select appropriate language based on user preference)
4. Use `type` property to determine how to format cell values:
- `text` fields → Display as plain text
- `textarea` fields → Display as truncated text with "..." or expandable preview
- `select` fields → Display value using label from options array (match value to option.value, then display option.label)
- `checkbox` fields → Display as checkmark icon or "Yes"/"No" text
5. Use `readonly` property to determine if column should be sortable (readonly fields may still be sortable, but editable fields definitely are)
6. Generate click handlers for column headers to update sort parameters and refetch data
7. **Add Actions Column:**
- Render action buttons in each table row on first load
- Include "Start Prompt" button (primary style) - navigates to `/chat-playground` with prompt content
- Include "Edit" button - switches to Edit View
- Include "Delete" button - shows confirmation dialog
- Buttons should be visible and accessible in each row
### Filter Control Generation
When rendering filter controls:
1. Fetch attribute definitions from `/api/attributes/Prompt`
2. Filter attributes where `visible: true` to determine which filters to show
3. For each visible field, generate appropriate filter UI based on `type`:
- `text` fields → Text input filter (supports "contains", "equals", "startsWith", "endsWith" operators)
- `textarea` fields → Text input filter (supports "contains", "equals", "startsWith", "endsWith" operators)
- `email` fields → Email input filter
- `select` fields → Dropdown filter with options from `options` array (use localized labels)
- `checkbox` fields → Boolean toggle filter (true/false/any)
4. Use `label` property for filter labels (localized)
5. When user applies filter, update `filters` object in pagination parameters and refetch data
6. Display active filters as chips/badges showing field label and value
7. Allow removing individual filters by removing them from `filters` object
### Search Implementation
For general search functionality:
1. Display a single search input box (not field-specific)
2. When user types, update `filters.search` in pagination parameters
3. Debounce search input (wait 300-500ms after user stops typing before sending request)
4. Search applies across all text fields in the prompt object
5. Reset to page 1 when search query changes
6. Combine search with field-specific filters (both are in the `filters` object)
### Form Field Generation
When rendering edit forms:
1. Fetch attribute definitions from `/api/attributes/Prompt`
2. Filter attributes where `visible: true` AND `editable: true` to determine which fields to show
3. For each editable field, generate appropriate form input based on `type`:
- `text` fields → Text input
- `textarea` fields → Textarea input (with appropriate rows/height)
- `email` fields → Email input
- `select` fields → Dropdown/select input with options from `options` array (use localized labels)
- `checkbox` fields → Checkbox input
4. Use `label` property for field labels (localized)
5. Use `required` property to show required indicators (asterisk, etc.)
6. Use `description` property to show help text or tooltips
7. Validate form before submission:
- Check all `required: true` fields have values
- Validate types (e.g., textarea fields must be valid text)
- Validate select fields (value must be in options array)
8. On submit, send only changed fields or all form data to update endpoint
### Create Form Field Generation
When rendering create forms:
1. Follow same pattern as edit forms for Prompt model fields
2. On submit, send Prompt object fields in request body
### Display Formatting
When displaying field values:
1. Use `type` property to determine formatting:
- `text` → Display as-is (may need HTML escaping)
- `textarea` → Display as formatted text (preserve line breaks, may truncate with "Read more" link)
- `select` → Look up value in `options` array and display localized label
- `checkbox` → Display as checkmark icon or "Yes"/"No" text
2. Handle `null` or `undefined` values gracefully (show "-" or "Not set")
3. Use `readonly` property to determine if field should show edit indicators
4. For content field (textarea), consider:
- Truncating long content in list view with "Show more" link
- Showing full content in detail view
- Preserving formatting (line breaks, whitespace)
### Localization
All labels and options support multiple languages:
1. Use user's preferred language (from user settings or browser locale)
2. Access localized labels from `label` object: `label[userLanguage]` or `label.en` as fallback
3. For select options, use `option.label[userLanguage]` or `option.label.en` as fallback
4. If label for current language is missing, fall back to English
### Key Principles
- Never hardcode field names, labels, types, or validation rules
- Always fetch attribute definitions from backend before rendering UI
- Use attribute metadata to determine what to display and how to display it
- Support all field types dynamically - if backend adds new types, frontend should handle them
- Respect `visible`, `editable`, `readonly`, and `required` flags from backend
- Use localized labels from backend metadata
- Generate filters, forms, and tables entirely from attribute definitions
- When backend adds new fields, frontend should automatically display them without code changes
- Handle all error cases gracefully (403, 404, 400, 500)
- Provide user feedback for all actions (loading states, success messages, error messages)
---
## Summary
This document provides complete frontend requirements for all prompt management pages and components. All requirements follow the principle of **backend-driven UI generation**—no hardcoding of field definitions, labels, or validation rules. The frontend should dynamically generate all UI components from backend metadata provided through the `/api/attributes/Prompt` endpoint.
**Key Architecture Pattern:** The prompt management interface is a single page (`/prompts`) with different views managed through component state. All interactions happen within the same page component without separate routes.
For generic patterns that apply across all entity types (not just prompts), see the [Dynamic Forms and Pagination documentation](./dynamic-forms-and-pagination.md).

View file

@ -1,516 +0,0 @@
# User Routes Frontend Documentation
This document describes customer journeys for managing users through the frontend, focusing on how administrators interact with user management and how the backend routes support these experiences. All UI components are dynamically generated from backend metadata—no hardcoding required.
**IMPORTANT:** All user management pages are **admin-only**. Non-admin users should not see navigation links or be able to access these pages. The frontend must check user privileges before rendering user management UI.
## Table of Contents
1. [Overview](#overview)
2. [Customer Journey 1: Discovering and Browsing Users](#customer-journey-1-discovering-and-browsing-users)
3. [Customer Journey 2: Viewing User Details](#customer-journey-2-viewing-user-details)
4. [Customer Journey 3: Creating New Users](#customer-journey-3-creating-new-users)
5. [Customer Journey 4: Editing User Properties](#customer-journey-4-editing-user-properties)
6. [Customer Journey 5: Enabling and Disabling Users](#customer-journey-5-enabling-and-disabling-users)
7. [Customer Journey 6: Resetting User Passwords](#customer-journey-6-resetting-user-passwords)
8. [Customer Journey 7: Revoking User Sessions](#customer-journey-7-revoking-user-sessions)
9. [Customer Journey 8: Deleting Users](#customer-journey-8-deleting-users)
9. [Backend Metadata System](#backend-metadata-system)
10. [Implementation Patterns](#implementation-patterns)
---
## Overview
The user routes (`/api/users`) enable administrators to manage users within their mandate. These routes focus on **user administration** including creation, editing, password management, and deletion.
**Key Principles:**
- **Admin-Only**: All user management functionality is restricted to administrators
- **User-Centric**: Documentation organized around what administrators want to accomplish
- **Backend-Driven**: All forms, tables, and UI components generated from backend metadata
- **No Hardcoding**: Field definitions, labels, validation rules, and options come from the backend
- **Permission-Aware**: Backend enforces permissions; frontend handles gracefully
- **Mandate-Scoped**: Users are managed within the context of mandates
---
## Customer Journey 1: Discovering and Browsing Users
### User Goal
"As an administrator, I want to see all users in my mandate and find the one I'm looking for."
### User Story
As an administrator, I want to browse users, search for specific users, filter by any field, sort them by different criteria, and quickly identify which users are enabled, their privilege levels, and their authentication methods.
### User Story Flow
```mermaid
sequenceDiagram
participant Admin
participant Frontend
participant Backend
Admin->>Frontend: Navigate to /users (admin only)
Frontend->>Frontend: Check if user is admin
alt User is not admin
Frontend-->>Admin: Redirect to unauthorized page or hide navigation
else User is admin
Frontend->>Backend: GET /api/attributes/User
Backend-->>Frontend: Attribute definitions (fields, labels, types)
Frontend->>Backend: GET /api/users/?pagination=...
Backend-->>Frontend: Paginated users list
Frontend->>Frontend: Generate table columns from attributes
Frontend->>Frontend: Generate filter controls from attributes
Frontend->>Frontend: Render users table + search + filters
Frontend-->>Admin: Display user list with search/filter UI
end
alt Admin performs general search
Admin->>Frontend: Type in search box (e.g., "john")
Frontend->>Frontend: Update search query
Frontend->>Backend: GET /api/users/?pagination=...filters:{"search":"john"}
Backend-->>Frontend: Filtered users list
Frontend-->>Admin: Display matching users
end
alt Admin applies field filter
Admin->>Frontend: Select filter field (e.g., "Privilege")
Frontend->>Frontend: Show filter options from attribute metadata
Admin->>Frontend: Select filter value (e.g., "admin")
Frontend->>Frontend: Update filter parameters
Frontend->>Backend: GET /api/users/?pagination=...filters:{"privilege":"admin"}
Backend-->>Frontend: Filtered users list
Frontend-->>Admin: Display filtered users
end
alt Admin combines search + filter + sort
Admin->>Frontend: Apply search + filter + sort
Frontend->>Frontend: Combine all parameters
Frontend->>Backend: GET /api/users/?pagination=...filters:{"search":"john","privilege":"admin"}...sort:desc
Backend-->>Frontend: Filtered, sorted users list
Frontend-->>Admin: Display results
end
Admin->>Frontend: Click column header (e.g., "Email")
Frontend->>Frontend: Update sort parameters
Frontend->>Backend: GET /api/users/?pagination=...sort:desc
Backend-->>Frontend: Sorted users list
Frontend-->>Admin: Display sorted users
Admin->>Frontend: Click user row
Frontend->>Frontend: Navigate to /users/userId
Frontend-->>Admin: Show user detail page
```
---
## Customer Journey 2: Viewing User Details
### User Goal
"As an administrator, I want to see everything about a specific user—their account information, privilege level, and status."
### User Story
As an administrator, I want to open a user and see their complete information, including username, email, full name, language preference, enabled status, privilege level, authentication authority, and mandate association.
### User Story Flow
```mermaid
sequenceDiagram
participant Admin
participant Frontend
participant Backend
Admin->>Frontend: Click user from list
Frontend->>Backend: GET /api/users/userId
Backend-->>Frontend: User object
Frontend->>Backend: GET /api/attributes/User
Backend-->>Frontend: Field definitions
Frontend->>Frontend: Generate UI from metadata
Frontend->>Frontend: Render user info section
Frontend->>Frontend: Separate editable vs read-only fields
Frontend-->>Admin: Display complete user view
alt User has editable fields and admin has permission
Frontend->>Frontend: Show "Edit User" button
end
alt Admin has permission
Frontend->>Frontend: Show "Reset Password" button
Frontend->>Frontend: Show "Revoke Sessions" button
Frontend->>Frontend: Show "Delete User" button
end
alt Admin clicks "Revoke Sessions"
Admin->>Frontend: Click "Revoke Sessions" button
Frontend->>Frontend: Show revocation dialog
Admin->>Frontend: Select authority filter (optional)
Admin->>Frontend: Enter reason (optional)
Admin->>Frontend: Click "Revoke"
Frontend->>Frontend: Optimistic update: Show loading state
Frontend->>Backend: POST /api/admin/tokens/revoke/user
alt Success
Backend-->>Frontend: {"revoked": count}
Frontend->>Frontend: Keep optimistic update
Frontend->>Backend: GET /api/users/userId (refetch)
Backend-->>Frontend: Updated user object
Frontend->>Frontend: Update UI with fresh data
Frontend-->>Admin: Show success message
else Error (403/400/500)
Backend-->>Frontend: Error response
Frontend->>Frontend: Revert optimistic update
Frontend-->>Admin: Show error message
end
end
alt Admin clicks "Reset Password"
Admin->>Frontend: Click "Reset Password" button
Frontend->>Frontend: Show password reset dialog
Admin->>Frontend: Enter new password
Admin->>Frontend: Confirm password
Admin->>Frontend: Click "Reset"
Frontend->>Frontend: Optimistic update: Show loading state
Frontend->>Backend: POST /api/users/userId/reset-password
alt Success
Backend-->>Frontend: Success response
Frontend->>Frontend: Keep optimistic update
Frontend->>Backend: GET /api/users/userId (refetch)
Backend-->>Frontend: Updated user object
Frontend->>Frontend: Update UI with fresh data
Frontend-->>Admin: Show success message
else Error (403/400/500)
Backend-->>Frontend: Error response
Frontend->>Frontend: Revert optimistic update
Frontend-->>Admin: Show error message
end
end
alt Admin clicks "Delete User"
Admin->>Frontend: Click "Delete User" button
Frontend->>Backend: GET /api/users/userId
Backend-->>Frontend: User data (for name)
Frontend->>Frontend: Show confirmation dialog
Admin->>Frontend: Confirm deletion
Frontend->>Frontend: Optimistic update: Remove user from UI
Frontend->>Backend: DELETE /api/users/userId
alt Success
Backend-->>Frontend: Success response
Frontend->>Frontend: Keep optimistic update
Frontend->>Frontend: Navigate to /users
Frontend-->>Admin: Show success message
else Error (403/404/500)
Backend-->>Frontend: Error response
Frontend->>Frontend: Revert optimistic update
Frontend-->>Admin: Show error message
end
end
```
## Customer Journey 3: Creating New Users
### User Goal
"As an administrator, I want to create new users for my mandate."
### User Story
As an administrator, I want to create a new user by filling out a form with their username, email, full name, language preference, privilege level, and initial password. The form should validate all required fields and show clear error messages.
### User Story Flow
```mermaid
sequenceDiagram
participant Admin
participant Frontend
participant Backend
Admin->>Frontend: Click "Create User" button
Frontend->>Frontend: Navigate to /users/create
Frontend->>Backend: GET /api/attributes/User
Backend-->>Frontend: Field definitions (editable fields)
Frontend->>Frontend: Filter editable fields
Frontend->>Frontend: Generate form from attributes
Frontend->>Frontend: Add password field (special case)
Frontend-->>Admin: Display create user form
Admin->>Frontend: Fill in form fields
Admin->>Frontend: Enter password
Admin->>Frontend: Click "Create"
Frontend->>Frontend: Validate form (required fields, types, email format)
alt Validation fails
Frontend-->>Admin: Show validation errors
else Validation passes
Frontend->>Backend: POST /api/users + form data + password
alt Permission denied (403)
Backend-->>Frontend: 403 Forbidden
Frontend-->>Admin: Show permission error
else Validation error (400)
Backend-->>Frontend: 400 Bad Request + error details
Frontend-->>Admin: Show backend validation errors
else Success (200)
Backend-->>Frontend: Created user object
Frontend->>Frontend: Navigate to user detail page
Frontend-->>Admin: Show created user
end
end
```
## Customer Journey 4: Editing User Properties
### User Goal
"As an administrator, I want to change user settings like their name, email, privilege level, or enabled status."
### User Story
As an administrator, I want to edit a user's properties through a form that only shows fields I'm allowed to edit, with validation and clear error messages.
### User Story Flow
```mermaid
sequenceDiagram
participant Admin
participant Frontend
participant Backend
Admin->>Frontend: Click "Edit" button
Frontend->>Frontend: Navigate to /users/id/edit
Frontend->>Backend: GET /api/users/userId
Backend-->>Frontend: Current user data
Frontend->>Backend: GET /api/attributes/User
Backend-->>Frontend: Field definitions (editable fields)
Frontend->>Frontend: Filter editable fields
Frontend->>Frontend: Generate form from attributes
Frontend->>Frontend: Pre-populate form with user data
Frontend-->>Admin: Display edit form
Admin->>Frontend: Modify form fields
Admin->>Frontend: Click "Save"
Frontend->>Frontend: Validate form (required fields, types)
alt Validation fails
Frontend-->>Admin: Show validation errors
else Validation passes
Frontend->>Frontend: Optimistic update: Apply changes to UI immediately
Frontend->>Backend: PUT /api/users/userId + form data
alt Permission denied (403)
Backend-->>Frontend: 403 Forbidden
Frontend->>Frontend: Revert optimistic update
Frontend-->>Admin: Show permission error
else Validation error (400)
Backend-->>Frontend: 400 Bad Request + error details
Frontend->>Frontend: Revert optimistic update
Frontend-->>Admin: Show backend validation errors
else Success (200)
Backend-->>Frontend: Updated user
Frontend->>Frontend: Keep optimistic update (or refresh from response)
Frontend->>Frontend: Navigate to detail page
Frontend-->>Admin: Show updated user
end
end
```
---
## Customer Journey 5: Enabling and Disabling Users
### User Goal
"As an administrator, I want to quickly enable or disable users directly from the user list without navigating to their detail page."
### User Story
As an administrator, I want to toggle a user's enabled status directly in the user list table. When I click the toggle, it should immediately update the user's status in the backend with an optimistic update, so the UI feels responsive and confident.
### User Story Flow
```mermaid
sequenceDiagram
participant Admin
participant Frontend
participant Backend
Admin->>Frontend: View user list table
Frontend->>Backend: GET /api/users/?pagination=...
Backend-->>Frontend: Paginated users list
Frontend->>Frontend: Render table with enabled toggle column
Frontend-->>Admin: Display user list with enabled toggles
Admin->>Frontend: Click enabled toggle for user
Frontend->>Frontend: Optimistic update: Toggle switch immediately<br/>(enabled: true → false or false → true)
Frontend->>Backend: PUT /api/users/userId + {enabled: newValue}
alt Success (200)
Backend->>Backend: Update user enabled status
Backend-->>Frontend: Updated user object
Frontend->>Frontend: Keep optimistic update (toggle already changed)
Frontend->>Backend: GET /api/users/?pagination=... (refetch list)
Backend-->>Frontend: Updated users list
Frontend->>Frontend: Update table with fresh data
Frontend-->>Admin: Show subtle success indicator (optional)
else Error (403/400/404/500)
Backend-->>Frontend: Error response
Frontend->>Frontend: Revert optimistic update: Toggle back to original state
Frontend-->>Admin: Show error message
end
```
## Customer Journey 6: Resetting User Passwords
### User Goal
"As an administrator, I want to reset a user's password when they forget it or need a new one."
### User Story
As an administrator, I want to reset a user's password by entering a new password. The system should validate password strength and automatically revoke all existing tokens for security.
### User Story Flow
```mermaid
sequenceDiagram
participant Admin
participant Frontend
participant Backend
Admin->>Frontend: Click "Reset Password" button
Frontend->>Frontend: Show password reset dialog
Admin->>Frontend: Enter new password
Admin->>Frontend: Confirm new password
Admin->>Frontend: Click "Reset"
Frontend->>Frontend: Validate password (min 8 characters)
Frontend->>Frontend: Validate passwords match
alt Validation fails
Frontend-->>Admin: Show validation errors
else Validation passes
Frontend->>Backend: POST /api/users/userId/reset-password + newPassword
alt Permission denied (403)
Backend-->>Frontend: 403 Forbidden
Frontend-->>Admin: Show permission error
else Validation error (400)
Backend-->>Frontend: 400 Bad Request (password too short)
Frontend-->>Admin: Show validation error
else Success (200)
Backend->>Backend: Reset password
Backend->>Backend: Revoke all user tokens
Backend-->>Frontend: Success response
Frontend-->>Admin: Show success message
end
end
```
### Frontend Requirements
> **📋 Complete frontend requirements for this journey are documented in [User Page Requirements](./user-page-requirements.md#customer-journey-6-resetting-user-passwords)**
The frontend must implement a password reset dialog with password strength validation. This is an admin-only action.
```typescript
const handleResetPassword = async (userId: string, newPassword: string) => {
// Validate password strength
if (newPassword.length < 8) {
showError('Password must be at least 8 characters long');
return;
}
const response = await fetch(`/api/users/${userId}/reset-password`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ newPassword })
});
if (response.ok) {
showSuccess('Password reset successfully. All user sessions have been revoked.');
} else {
const error = await response.json();
showError(error.detail || 'Failed to reset password');
}
};
```
---
## Customer Journey 7: Revoking User Sessions
### User Goal
"As an administrator, I want to revoke all active sessions for a user to force them to log in again."
### User Story
As an administrator, I want to revoke all active tokens/sessions for a user, optionally filtered by authentication authority (local, Google, Microsoft). This is useful for security purposes, such as when a user's account may have been compromised or when they need to be logged out of all devices.
### User Story Flow
```mermaid
sequenceDiagram
participant Admin
participant Frontend
participant Backend
Admin->>Frontend: Click "Revoke Sessions" button
Frontend->>Frontend: Show session revocation dialog
Admin->>Frontend: Optionally select authority filter (local/Google/Microsoft)
Admin->>Frontend: Optionally enter reason
Admin->>Frontend: Click "Revoke Sessions"
Frontend->>Backend: POST /api/admin/tokens/revoke/user + {userId, authority?, reason?}
alt Permission denied (403)
Backend-->>Frontend: 403 Forbidden
Frontend-->>Admin: Show permission error
else Success (200)
Backend->>Backend: Revoke all active tokens for user
Backend-->>Frontend: {"revoked": count}
Frontend-->>Admin: Show success message with count
end
```
---
## Customer Journey 8: Deleting Users
### User Goal
"As an administrator, I want to delete users that are no longer needed."
### User Story
As an administrator, I want to delete users with a clear confirmation to prevent accidental deletion.
### User Story Flow
```mermaid
sequenceDiagram
participant Admin
participant Frontend
participant Backend
Admin->>Frontend: Click "Delete" button
Frontend->>Backend: GET /api/users/userId
Backend-->>Frontend: User data (for name)
Frontend->>Frontend: Show confirmation dialog<br/>"Delete 'User Name'?"
Admin->>Frontend: Cancel deletion
Frontend-->>Admin: Dialog closed, no action
Admin->>Frontend: Click "Delete" button again
Frontend->>Backend: GET /api/users/userId
Backend-->>Frontend: User data
Frontend->>Frontend: Show confirmation dialog
Admin->>Frontend: Confirm deletion
Frontend->>Frontend: Optimistic update: Remove user from UI immediately
Frontend->>Backend: DELETE /api/users/userId
alt Permission denied (403)
Backend-->>Frontend: 403 Forbidden
Frontend->>Frontend: Revert optimistic update: Restore user in UI
Frontend-->>Admin: Show permission error
else Not found (404)
Backend-->>Frontend: 404 Not Found
Frontend->>Frontend: Revert optimistic update: Restore user in UI
Frontend-->>Admin: Show not found error
else Success (200)
Backend-->>Frontend: Success response
Frontend->>Frontend: Keep optimistic update (user already removed)
Frontend->>Frontend: Show success message
Frontend->>Frontend: Navigate to /users (if on detail page)
Frontend-->>Admin: Display user list (without deleted user)
end
```

View file

@ -1,843 +0,0 @@
# User Page Requirements
This document contains the complete frontend requirements for all user management pages and components. All UI components are dynamically generated from backend metadata—no hardcoding required.
**IMPORTANT:** All user management pages are **admin-only**. Non-admin users should not see navigation links or be able to access these pages. The frontend must check user privileges before rendering user management UI.
## Table of Contents
1. [Overview](#overview)
2. [Page Structure and Layout](#page-structure-and-layout)
3. [User Interactions and Functionality](#user-interactions-and-functionality)
4. [Backend Routes and API Integration](#backend-routes-and-api-integration)
5. [Field and Attribute Reference](#field-and-attribute-reference)
6. [Dynamic Rendering Guidelines](#dynamic-rendering-guidelines)
7. [Admin Access Control](#admin-access-control)
---
## Overview
The user management page enables administrators to manage users within their mandate. The frontend consists of a single page (`/users`) with different views/states:
- **List View** - Browse, search, filter, and sort users (admin-only)
- **Detail View** - View complete user information (admin-only)
- **Edit View** - Edit user properties (admin-only)
- **Create View** - Create new users (admin-only)
All views use backend-driven UI generation, meaning field definitions, labels, validation rules, and UI structure come entirely from backend metadata through the `/api/attributes/User` endpoint. Views are managed through component state and routing within the same page, not as separate routes.
---
## Page Structure and Layout
### User Management Page (`/users`)
**Access Control:** Admin-only. Non-admin users should not see this page or navigation links to it.
The user management page uses different views/states to handle different user interactions. Views are managed through component state and routing within the same page component.
### List View
**State:** `view === 'list'` or `selectedUserId === null`
**What the administrator sees:**
- **Main Content Area:**
- Table or card grid displaying all users in the mandate
- Each user row/card shows: username, email, full name, privilege badge, enabled toggle (interactive switch), authentication authority
- Enabled toggle is clickable and immediately updates user status with optimistic update
- Clickable rows/cards that switch to Detail View (set selectedUserId and view state)
- **Search and Filter Controls:**
- General search input box (searches across all text fields)
- Field-specific filter controls (one filter per visible field)
- Active filter indicators (chips/badges showing applied filters)
- "Clear all filters" button when filters are active
- **Sorting Controls:**
- Clickable column headers with sort indicators (up/down arrows)
- Visual indication of current sort field and direction
- Support for multi-level sorting
- **Pagination Controls:**
- Page information display ("Page X of Y", "Showing 1-20 of 45 users")
- Previous/Next page buttons
- Page number buttons
- Page size selector (10, 20, 50, 100 items per page)
- **Action Buttons:**
- "Create User" button (admin-only) - switches to Create View
### Detail View
**State:** `view === 'detail'` and `selectedUserId !== null`
**Access Control:** Admin-only.
**What the administrator sees:**
- **User Header Section:**
- Username (editable indicator if user has permission)
- Full name (if available)
- Privilege badge with color coding
- Enabled status indicator
- **User Information Section:**
- All user properties displayed as formatted fields
- Read-only fields shown as formatted text
- Editable fields shown with edit indicators (if admin has permission)
- Special formatting:
- Privilege → Color-coded badge (User/Admin/SysAdmin)
- Enabled → Checkmark icon or "Enabled"/"Disabled" text
- Authentication Authority → Badge with icon
- Email → Clickable mailto link
- **Action Buttons:**
- Edit button (if admin has permission and editable fields exist) - switches to Edit View
- Reset Password button (admin-only)
- Revoke Sessions button (admin-only)
- Delete button (if admin has permission)
### Edit View
**State:** `view === 'edit'` and `selectedUserId !== null`
**Access Control:** Admin-only.
**What the administrator sees:**
- **Form Section:**
- Dynamic form with editable user fields only
- Field labels with required indicators (asterisk for required fields)
- Help text/tooltips from field descriptions
- Input validation errors displayed inline
- **Action Buttons:**
- Save button (submits form)
- Cancel button (switches back to Detail View)
### Create View
**State:** `view === 'create'`
**Access Control:** Admin-only.
**What the administrator sees:**
- **Form Section:**
- Dynamic form with all editable user fields
- Password field (special field, not in User model attributes)
- Confirm password field (frontend-only validation)
- Field labels with required indicators
- Help text/tooltips from field descriptions
- Input validation errors displayed inline
- **Action Buttons:**
- Create button (submits form)
- Cancel button (switches back to List View)
- **Confirmation Dialogs:**
- Delete confirmation dialog (on user detail page)
- Password reset confirmation dialog
---
## User Interactions and Functionality
### Admin Access Control
**Before Rendering Any User Management UI:**
1. Check if current user has admin or sysadmin privilege
2. If not admin:
- Hide navigation links to user management pages
- Redirect if user tries to access pages directly
- Show unauthorized access message
3. If admin:
- Render user management UI normally
- Handle 403 errors gracefully (may occur if permissions change)
### Browsing and Discovery
**Search Functionality:**
- Administrator types in general search box
- Frontend debounces input (300-500ms delay)
- Search applies across all text fields in user objects
- Results update automatically
- Page resets to page 1 when search changes
**Field Filtering:**
- Administrator selects field to filter by
- Frontend shows appropriate filter UI based on field type:
- Text fields → Text input with operator selection (contains, equals, startsWith, endsWith)
- Select fields → Dropdown with options from backend metadata
- Email fields → Email input filter
- Checkbox fields → Boolean toggle (true/false/any)
- Administrator applies filter → Filter appears as active chip/badge
- Administrator can remove individual filters
- Multiple filters work together (AND logic)
- Page resets to page 1 when filters change
**Sorting:**
- Administrator clicks column header
- Sort direction toggles (asc → desc → remove)
- Multiple columns can be sorted (multi-level sorting)
- Sort indicators show on column headers
- All filters and search preserved when sorting
**Pagination:**
- Administrator clicks page number or navigation button
- Page updates and data refetches
- All filters, search, and sort preserved
- Administrator changes page size → Page resets to 1, data refetches
**View Switching:**
- Administrator clicks user row/card → Switches to Detail View (set `selectedUserId` and `view: 'detail'`)
- Administrator clicks username → Switches to Detail View (set `selectedUserId` and `view: 'detail'`)
### Viewing User Details
**Information Display:**
- All user fields displayed using dynamic rendering
- Read-only fields shown as formatted text
- Editable fields shown with edit indicators
- Special fields formatted appropriately (privilege badges, enabled status, email links)
**Action Availability:**
- Edit button shown if editable fields exist and admin has permission
- Reset Password button always shown (admin-only action)
- Revoke Sessions button always shown (admin-only action)
- Delete button shown if admin has permission
### Creating Users
**Form Interaction:**
- Administrator clicks "Create User" button → Switches to Create View (set `view: 'create'`)
- Form shows all editable fields plus password field
- Administrator fills in fields
- Client-side validation shows errors immediately
- Administrator clicks Create → Form validates and submits
- Administrator clicks Cancel → Switches back to List View (set `view: 'list'`, `selectedUserId: null`)
**Form Validation:**
- Required field validation (shows error if empty)
- Type validation (e.g., email fields must be valid email format)
- Select field validation (value must be in options array)
- Password validation (minimum 8 characters)
- Password confirmation validation (must match password)
- Validation errors displayed inline below fields
**Form Submission:**
- User data sent as User object
- Password sent as separate field in request body
- Success → Switch to Detail View for created user (set `selectedUserId` to new user ID, `view: 'detail'`)
- Error handling:
- 403 (permission denied) → Show permission error
- 400 (validation errors) → Display backend validation errors
- Other errors → Show generic error message
### Editing Users
**Form Interaction:**
- Administrator clicks "Edit" button → Switches to Edit View (set `view: 'edit'`)
- Form pre-populated with current user values
- Administrator modifies fields
- Client-side validation shows errors immediately
- Administrator clicks Save → Form validates and submits
- Administrator clicks Cancel → Switches back to Detail View (set `view: 'detail'`)
**Form Validation:**
- Required field validation (shows error if empty)
- Type validation (e.g., email fields must be valid email format)
- Select field validation (value must be in options array)
- Validation errors displayed inline below fields
**Form Submission:**
- Only changed fields sent (or all form data)
- Success → Switch back to Detail View (set `view: 'detail'`) and show success message
- Error handling:
- 403 (permission denied) → Show permission error
- 400 (validation errors) → Display backend validation errors
- Other errors → Show generic error message
### Enabling and Disabling Users
**Toggle Interaction:**
- Administrator views user list table
- Table displays enabled/disabled status as toggle switch in "Enabled" column
- Administrator clicks toggle switch for a user
- Frontend immediately updates toggle state (optimistic update)
- Frontend sends PUT request to update user's enabled property
- Administrator sees immediate feedback (toggle changes instantly)
**Toggle Submission:**
- Success → Keep optimistic update, refetch user list to ensure consistency
- Error → Revert toggle to original state, show error message
- No confirmation dialog needed - toggle is immediate and reversible
**Implementation Notes:**
- Toggle should be part of the main table column
- Use optimistic updates for instant feedback
- Refetch list after successful update
- Handle errors gracefully by reverting toggle state
### Customer Journey 5: Enabling and Disabling Users
> **📋 Complete customer journey documentation is available in [User Customer Journeys](./user-page-customer-journeys.md#customer-journey-5-enabling-and-disabling-users)**
### Resetting User Passwords
**Password Reset Interaction:**
- Administrator clicks "Reset Password" button
- Password reset dialog appears
- Administrator enters new password
- Administrator confirms new password
- Client-side validation:
- Password must be at least 8 characters
- Passwords must match
- Administrator clicks Reset → Password reset request sent
- Administrator clicks Cancel → Dialog closes, no action
**Password Reset Submission:**
- Success → Show success message, close dialog
- Backend automatically revokes all user tokens
- Error handling:
- 403 (permission denied) → Show permission error
- 400 (password too short) → Show validation error
- Other errors → Show generic error message
### Revoking User Sessions
**Session Revocation Interaction:**
- Administrator clicks "Revoke Sessions" button
- Session revocation dialog appears
- Administrator optionally selects authority filter:
- All authorities (default) - revokes all sessions
- Local only - revokes only local authentication sessions
- Google only - revokes only Google OAuth sessions
- Microsoft only - revokes only Microsoft OAuth sessions
- Administrator optionally enters reason (for audit logging)
- Administrator clicks "Revoke Sessions" → Session revocation request sent
- Administrator clicks Cancel → Dialog closes, no action
**Session Revocation Submission:**
- Success → Show success message with count of revoked sessions, close dialog
- User will need to log in again on all affected devices
- Error handling:
- 403 (permission denied) → Show permission error
- 400 (invalid parameters) → Show validation error
- Other errors → Show generic error message
**Use Cases:**
- Security incident: User's account may have been compromised
- Device management: User lost a device or needs to log out of specific service
- Account suspension: Temporarily disable user access
- Force re-authentication: Make user log in again without changing password
**Password Reset Interaction:**
- Administrator clicks "Reset Password" button
- Password reset dialog appears
- Administrator enters new password
- Administrator confirms new password
- Client-side validation:
- Password must be at least 8 characters
- Passwords must match
- Administrator clicks Reset → Password reset request sent
- Administrator clicks Cancel → Dialog closes, no action
**Password Reset Submission:**
- Success → Show success message, close dialog
- Backend automatically revokes all user tokens
- Error handling:
- 403 (permission denied) → Show permission error
- 400 (password too short) → Show validation error
- Other errors → Show generic error message
### Customer Journey 7: Revoking User Sessions
> **📋 Complete customer journey documentation is available in [User Customer Journeys](./user-page-customer-journeys.md#customer-journey-7-revoking-user-sessions)**
### Deleting Users
**Delete Action:**
- Administrator clicks delete button (on detail page or list)
- Confirmation dialog appears with user name/username
- Warning about permanent deletion
- Administrator confirms → User deleted
- Administrator cancels → Dialog closes, no action
**Delete Success Handling:**
- Success message displayed
- If in Detail View → Switch back to List View (set `view: 'list'`, `selectedUserId: null`)
- If in List View → Remove user from list or refresh
---
## Backend Routes and API Integration
### Complete Route Reference
All backend routes used by user pages:
| Route | Method | Purpose | When Used | Access Control |
|-------|--------|---------|-----------|----------------|
| `/api/users/` | GET | Get all users (with pagination) | Initial page load, pagination changes, sort changes, filter changes, search changes | All authenticated users (filtered by mandate) |
| `/api/users/{userId}` | GET | Get user details | Detail page load, edit page load | All authenticated users |
| `/api/users/{userId}` | PUT | Update user | Edit form submission | All authenticated users |
| `/api/users/{userId}` | DELETE | Delete user | User confirms deletion | All authenticated users |
| `/api/users` | POST | Create user | Create form submission | All authenticated users |
| `/api/users/{userId}/reset-password` | POST | Reset user password | Admin confirms password reset | **Admin-only** |
| `/api/admin/tokens/revoke/user` | POST | Revoke all active sessions for a user | Admin confirms session revocation | **Admin-only** |
| `/api/users/change-password` | POST | Change current user's password | User changes own password | Current user only (not admin-only) |
| `/api/attributes/User` | GET | Get field definitions | Page load (once per page) - used to generate all UI components | All authenticated users |
### API Request Patterns
**Pagination Request:**
```
GET /api/users/?pagination={"page":1,"pageSize":20,"sort":[],"filters":null}
```
- `pagination` parameter is JSON-encoded string
- If user wants all users: omit `pagination` parameter entirely
- Filters structure: `{"search":"query","fieldName":"value",...}`
- Optional `mandateId` query parameter to filter by mandate
**Create Request:**
```
POST /api/users
Content-Type: application/json
Body: {
"username": "john.doe",
"email": "john@example.com",
"fullName": "John Doe",
"language": "en",
"enabled": true,
"privilege": "user",
"authenticationAuthority": "local",
"password": "securepassword123"
}
```
- Password is sent as separate field in body (not part of User model)
- All User model fields sent as User object
- Handle 403 (permission denied) and 400 (validation errors)
**Update Request:**
```
PUT /api/users/{userId}
Content-Type: application/json
Body: {fieldName: value, ...}
```
- Send only changed fields or all form data
- Handle 403 (permission denied) and 400 (validation errors)
**Password Reset Request:**
```
POST /api/users/{userId}/reset-password
Content-Type: application/json
Body: {"newPassword": "newsecurepassword123"}
```
- **Admin-only endpoint**
- Password must be at least 8 characters
- Backend automatically revokes all user tokens
- Handle 403 (permission denied) and 400 (validation errors)
**Session Revocation Request:**
```
POST /api/admin/tokens/revoke/user
Content-Type: application/json
Body: {
"userId": "user-id-here",
"authority": "local", // Optional: "local", "google", "msft", or omit for all
"reason": "Security incident" // Optional reason for audit logging
}
```
- **Admin-only endpoint**
- `userId` is required
- `authority` is optional - if omitted, revokes all sessions regardless of authority
- `reason` is optional - defaults to "admin revoke" if not provided
- Returns `{"revoked": count}` - number of sessions revoked
- Handle 403 (permission denied) and 400 (validation errors)
**Delete Requests:**
```
DELETE /api/users/{userId}
```
- Delete operation requires user confirmation
- Handle 403 (permission denied) and 404 (not found) gracefully
### Response Handling
**Paginated Response:**
```json
{
"items": [...],
"pagination": {
"currentPage": 1,
"pageSize": 20,
"totalItems": 45,
"totalPages": 3,
"sort": [...],
"filters": {...}
}
}
```
**Error Responses:**
- 403 Forbidden → Show permission error message (admin-only actions)
- 404 Not Found → Show "not found" error message
- 400 Bad Request → Display validation errors from response
- 500 Internal Server Error → Show generic error message
---
## Field and Attribute Reference
### Complete Field List
The following is a comprehensive list of all parameters, attributes, and fields that will be displayed for users. All of these are provided by the backend through the `/api/attributes/User` endpoint and should never be hardcoded in the frontend.
#### Core User Fields
**Identification Fields:**
- `id` - Unique user identifier (text, readonly, not required, visible)
- `mandateId` - ID of the mandate this user belongs to (text, readonly, not required, visible)
**Account Fields:**
- `username` - Username for login (text, editable, required, visible)
- `email` - Email address of the user (email, editable, required, visible)
- `fullName` - Full name of the user (text, editable, not required, visible)
**Configuration Fields:**
- `language` - Preferred language of the user (select, editable, required, visible)
- Options: "de", "en", "fr", "it"
- Each option has localized labels (en/fr)
- `enabled` - Indicates whether the user is enabled (checkbox, editable, not required, visible)
- `privilege` - Permission level (select, editable, required, visible)
- Options: "user", "admin", "sysadmin"
- Each option has localized labels (en/fr)
- `authenticationAuthority` - Primary authentication authority (select, readonly, not required, visible)
- Options: "local", "google", "msft"
- Each option has localized labels (en/fr)
**Special Fields (Not in User Model):**
- `password` - Password field for create forms (password, not in attributes, required for creation)
- `confirmPassword` - Password confirmation (password, frontend-only, required for creation)
### Pagination Parameters
**Request Parameters (`PaginationParams`):**
- `page` - Current page number (1-based, minimum 1)
- `pageSize` - Number of items per page (minimum 1, maximum 1000)
- `sort` - Array of sort field configurations
- Each sort field contains:
- `field` - Field name to sort by (must match a user field name)
- `direction` - Sort direction: "asc" or "desc"
- `filters` - Filter criteria dictionary
- `search` - General search term (searches across all text fields, case-insensitive)
- Field-specific filters: `{fieldName: value}` or `{fieldName: {operator: "operator", value: value}}`
- Supported operators: "equals", "contains", "startsWith", "endsWith", "in", "notIn"
**Response Metadata (`PaginationMetadata`):**
- `currentPage` - Current page number (1-based)
- `pageSize` - Number of items per page
- `totalItems` - Total number of items across all pages (after filters applied)
- `totalPages` - Total number of pages (calculated from totalItems / pageSize)
- `sort` - Current sort configuration applied (array of SortField objects)
- `filters` - Current filters applied (mirrors request filters)
### Attribute Definition Structure
Each field returned from `/api/attributes/User` contains:
- `name` - Field name (e.g., "username", "email", "privilege")
- `type` - Field data type (e.g., "text", "email", "select", "checkbox")
- `label` - Localized field label (object with language keys: {"en": "English Label", "fr": "French Label"})
- `description` - Field description text
- `required` - Boolean indicating if field is required
- `readonly` - Boolean indicating if field is read-only
- `editable` - Boolean indicating if field can be edited (inverse of readonly)
- `visible` - Boolean indicating if field should be displayed in UI
- `options` - Array of options for select fields (each option has `value` and localized `label`)
---
## Dynamic Rendering Guidelines
The frontend must render all UI components dynamically based on backend metadata. No field definitions, labels, validation rules, or UI structure should be hardcoded.
### Table Column Generation
When rendering the user list table:
1. Fetch attribute definitions from `/api/attributes/User`
2. Filter attributes where `visible: true` to determine which columns to display
3. Use `label` property for column headers (select appropriate language based on user preference)
4. Use `type` property to determine how to format cell values:
- `text` fields → Display as plain text
- `email` fields → Display as clickable mailto link
- `select` fields → Display value using label from options array (match value to option.value, then display option.label)
- `checkbox` fields → Display as checkmark icon or "Enabled"/"Disabled" text
5. Use `readonly` property to determine if column should be sortable (readonly fields may still be sortable, but editable fields definitely are)
6. Generate click handlers for column headers to update sort parameters and refetch data
### Filter Control Generation
When rendering filter controls:
1. Fetch attribute definitions from `/api/attributes/User`
2. Filter attributes where `visible: true` to determine which filters to show
3. For each visible field, generate appropriate filter UI based on `type`:
- `text` fields → Text input filter (supports "contains", "equals", "startsWith", "endsWith" operators)
- `email` fields → Email input filter
- `select` fields → Dropdown filter with options from `options` array (use localized labels)
- `checkbox` fields → Boolean toggle filter (true/false/any)
4. Use `label` property for filter labels (localized)
5. When administrator applies filter, update `filters` object in pagination parameters and refetch data
6. Display active filters as chips/badges showing field label and value
7. Allow removing individual filters by removing them from `filters` object
### Search Implementation
For general search functionality:
1. Display a single search input box (not field-specific)
2. When administrator types, update `filters.search` in pagination parameters
3. Debounce search input (wait 300-500ms after user stops typing before sending request)
4. Search applies across all text fields in the user object
5. Reset to page 1 when search query changes
6. Combine search with field-specific filters (both are in the `filters` object)
### Form Field Generation
When rendering edit forms:
1. Fetch attribute definitions from `/api/attributes/User`
2. Filter attributes where `visible: true` AND `editable: true` to determine which fields to show
3. For each editable field, generate appropriate form input based on `type`:
- `text` fields → Text input
- `email` fields → Email input
- `select` fields → Dropdown/select input with options from `options` array (use localized labels)
- `checkbox` fields → Checkbox input
4. Use `label` property for field labels (localized)
5. Use `required` property to show required indicators (asterisk, etc.)
6. Use `description` property to show help text or tooltips
7. Validate form before submission:
- Check all `required: true` fields have values
- Validate types (e.g., email fields must be valid email format)
- Validate select fields (value must be in options array)
8. On submit, send only changed fields or all form data to update endpoint
### Create Form Field Generation
When rendering create forms:
1. Follow same pattern as edit forms for User model fields
2. **Add password field** (not in User model attributes):
- Password input field
- Confirm password input field (frontend-only validation)
- Both fields required for creation
- Validate password strength (minimum 8 characters)
- Validate passwords match
3. On submit, send User object fields plus `password` as separate field in request body
### Display Formatting
When displaying field values:
1. Use `type` property to determine formatting:
- `text` → Display as-is (may need HTML escaping)
- `email` → Display as clickable mailto link
- `select` → Look up value in `options` array and display localized label
- `checkbox` → Display as checkmark icon or "Enabled"/"Disabled" text
2. Handle `null` or `undefined` values gracefully (show "-" or "Not set")
3. Use `readonly` property to determine if field should show edit indicators
4. Special formatting for privilege field:
- Color-code badges (User = blue, Admin = orange, SysAdmin = red)
- Use localized labels from options
### Localization
All labels and options support multiple languages:
1. Use user's preferred language (from user settings or browser locale)
2. Access localized labels from `label` object: `label[userLanguage]` or `label.en` as fallback
3. For select options, use `option.label[userLanguage]` or `option.label.en` as fallback
4. If label for current language is missing, fall back to English
### Key Principles
- Never hardcode field names, labels, types, or validation rules
- Always fetch attribute definitions from backend before rendering UI
- Use attribute metadata to determine what to display and how to display it
- Support all field types dynamically - if backend adds new types, frontend should handle them
- Respect `visible`, `editable`, `readonly`, and `required` flags from backend
- Use localized labels from backend metadata
- Generate filters, forms, and tables entirely from attribute definitions
- When backend adds new fields, frontend should automatically display them without code changes
- Handle all error cases gracefully (403, 404, 400, 500)
- Provide user feedback for all actions (loading states, success messages, error messages)
- **Always check admin privileges before rendering user management UI**
---
## Admin Access Control
### Frontend Access Control
The frontend must implement access control to ensure only administrators can access user management pages:
**1. Navigation Link Visibility:**
```typescript
// Only show user management link if user is admin
{currentUser?.privilege === 'admin' || currentUser?.privilege === 'sysadmin' ? (
<NavLink to="/users">Manage Users</NavLink>
) : null}
```
**2. Route Protection:**
```typescript
// Protect route with admin check - single route for all views
function UserManagementPage() {
const { currentUser } = useAuth();
const [view, setView] = useState<'list' | 'detail' | 'edit' | 'create'>('list');
const [selectedUserId, setSelectedUserId] = useState<string | null>(null);
// Check admin status
if (currentUser?.privilege !== 'admin' && currentUser?.privilege !== 'sysadmin') {
return <UnauthorizedAccess />;
}
// Render appropriate view based on state
if (view === 'list') {
return <ListView onUserSelect={(id) => { setSelectedUserId(id); setView('detail'); }} onCreate={() => setView('create')} />;
} else if (view === 'detail' && selectedUserId) {
return <DetailView userId={selectedUserId} onEdit={() => setView('edit')} onBack={() => { setSelectedUserId(null); setView('list'); }} />;
} else if (view === 'edit' && selectedUserId) {
return <EditView userId={selectedUserId} onSave={() => setView('detail')} onCancel={() => setView('detail')} />;
} else if (view === 'create') {
return <CreateView onSave={(userId) => { setSelectedUserId(userId); setView('detail'); }} onCancel={() => setView('list')} />;
}
return null;
}
```
**3. Component-Level Checks:**
```typescript
// Check admin status before rendering components
function ListView({ onUserSelect }) {
const { currentUser } = useAuth();
if (currentUser?.privilege !== 'admin' && currentUser?.privilege !== 'sysadmin') {
return <UnauthorizedAccess />;
}
// Render list view UI
return (
<div>
<Button onClick={() => onUserSelect(null)}>Create User</Button>
{/* List table */}
</div>
);
}
```
**4. Error Handling:**
```typescript
// Handle 403 errors gracefully
try {
const response = await fetch('/api/users/userId/reset-password', {
method: 'POST',
body: JSON.stringify({ newPassword })
});
if (response.status === 403) {
showError('You do not have permission to reset passwords');
return;
}
// Handle other responses
} catch (error) {
showError('Failed to reset password');
}
```
**5. View State Management:**
```typescript
// Manage views within the same page component
function UserManagementPage() {
const [view, setView] = useState<'list' | 'detail' | 'edit' | 'create'>('list');
const [selectedUserId, setSelectedUserId] = useState<string | null>(null);
// Switch to detail view
const handleUserSelect = (userId: string) => {
setSelectedUserId(userId);
setView('detail');
};
// Switch to edit view
const handleEdit = () => {
setView('edit');
};
// Switch to create view
const handleCreate = () => {
setSelectedUserId(null);
setView('create');
};
// Switch back to list view
const handleBackToList = () => {
setSelectedUserId(null);
setView('list');
};
// Render based on view state
return (
<>
{view === 'list' && <ListView onUserSelect={handleUserSelect} onCreate={handleCreate} />}
{view === 'detail' && selectedUserId && <DetailView userId={selectedUserId} onEdit={handleEdit} onBack={handleBackToList} />}
{view === 'edit' && selectedUserId && <EditView userId={selectedUserId} onSave={() => setView('detail')} onCancel={() => setView('detail')} />}
{view === 'create' && <CreateView onSave={(userId) => { setSelectedUserId(userId); setView('detail'); }} onCancel={handleBackToList} />}
</>
);
}
```
### Admin-Only Actions
The following actions are admin-only and should only be available to administrators:
- **Reset User Password** (`POST /api/users/{userId}/reset-password`)
- Only admins can reset other users' passwords
- Backend enforces this with privilege check
- Frontend should hide button for non-admins
- **User Management Page**
- The user management page should be admin-only
- Navigation links should be hidden for non-admins
- Direct URL access should show unauthorized message for non-admins
### Security Best Practices
1. **Never trust frontend-only checks** - Backend always enforces permissions
2. **Handle 403 errors gracefully** - Show appropriate error messages
3. **Hide UI elements** - Don't show admin actions to non-admins
4. **Redirect unauthorized access** - Redirect non-admins away from admin pages
5. **Log security events** - Backend logs admin actions (handled by backend)
---
## Summary
This document provides complete frontend requirements for all user management pages and components. All requirements follow the principle of **backend-driven UI generation**—no hardcoding of field definitions, labels, or validation rules. The frontend should dynamically generate all UI components from backend metadata provided through the `/api/attributes/User` endpoint.
**Critical Security Requirement:** All user management pages are **admin-only**. The frontend must:
- Check user privileges before rendering navigation links
- Check user privileges before allowing access to pages
- Handle 403 Forbidden errors gracefully
- Never expose user management UI to non-admin users
For generic patterns that apply across all entity types (not just users), see the [Dynamic Forms and Pagination documentation](./dynamic-forms-and-pagination.md).

View file

@ -1,474 +0,0 @@
# Voice Service Customer Journeys
This document describes customer journeys for the Google Cloud Voice Services, focusing on how users interact with speech-to-text, translation, text-to-speech, and real-time voice interpretation features.
## Table of Contents
1. [Overview](#overview)
2. [Customer Journey 1: Converting Speech to Text](#customer-journey-1-converting-speech-to-text)
3. [Customer Journey 2: Translating Text](#customer-journey-2-translating-text)
4. [Customer Journey 3: Real-time Voice Interpretation](#customer-journey-3-real-time-voice-interpretation)
5. [Customer Journey 4: Converting Text to Speech](#customer-journey-4-converting-text-to-speech)
6. [Customer Journey 5: Managing Voice Settings](#customer-journey-5-managing-voice-settings)
7. [Customer Journey 6: Discovering Available Languages and Voices](#customer-journey-6-discovering-available-languages-and-voices)
8. [Customer Journey 7: Real-time Speech-to-Text via WebSocket](#customer-journey-7-real-time-speech-to-text-via-websocket)
9. [Customer Journey 8: Real-time Text-to-Speech via WebSocket](#customer-journey-8-real-time-text-to-speech-via-websocket)
---
## Overview
The voice service routes (`/api/voice-google`) enable users to interact with Google Cloud voice services including Speech-to-Text, Translation, Text-to-Speech, and real-time voice interpretation. These routes support both HTTP REST endpoints for file-based processing and WebSocket endpoints for real-time streaming.
**Key Principles:**
- **User-Centric**: Documentation organized around what users want to accomplish
- **Multi-Modal**: Supports both file upload and real-time streaming
- **Language-Aware**: All operations support multiple languages with user-configurable defaults
- **Settings-Driven**: User preferences stored and applied automatically
---
## Customer Journey 1: Converting Speech to Text
### User Goal
"I want to record my speech and convert it into text."
### User Story
As a user, I want to record my speech through the frontend microphone and get the transcribed text with confidence scores and language detection.
### User Story Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Backend
User->>Frontend: Select language (default: de-DE)
User->>Frontend: Click "Start Recording"
Frontend->>Frontend: Request microphone access
alt Microphone access denied
Frontend-->>User: Show permission error
else Microphone access granted
Frontend->>Frontend: Start audio recording
Frontend-->>User: Show recording indicator (red dot, timer)
User->>Frontend: Speak into microphone
Frontend->>Frontend: Capture audio stream
User->>Frontend: Click "Stop Recording"
Frontend->>Frontend: Stop audio recording
Frontend->>Frontend: Convert audio stream to audio file
Frontend->>Frontend: Validate audio file (size, format)
alt File validation fails
Frontend-->>User: Show validation error
else File validation passes
Frontend->>Frontend: Show loading state
Frontend->>Backend: POST /api/voice-google/speech-to-text<br/>(audioFile, language)
alt Authentication fails (401)
Backend-->>Frontend: 401 Unauthorized
Frontend-->>User: Show authentication error
else Invalid audio format (400)
Backend-->>Frontend: 400 Bad Request + error details
Frontend-->>User: Show format error message
else Speech recognition fails (400)
Backend-->>Frontend: 400 Bad Request + error details
Frontend-->>User: Show recognition error
else Success (200)
Backend-->>Frontend: {success: true, text, confidence, language, audio_info}
Frontend->>Frontend: Display transcribed text
Frontend->>Frontend: Display confidence score
Frontend->>Frontend: Display detected language
Frontend->>Frontend: Display audio metadata
Frontend-->>User: Show transcription result with metadata
end
end
end
```
---
## Customer Journey 2: Translating Text
### User Goal
"I want to translate text from one language to another."
### User Story
As a user, I want to enter text and translate it between languages, seeing both the original and translated text.
### User Story Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Backend
User->>Frontend: Enter text to translate
User->>Frontend: Select source language (default: de)
User->>Frontend: Select target language (default: en)
User->>Frontend: Click "Translate"
Frontend->>Frontend: Validate text is not empty
alt Text is empty
Frontend-->>User: Show validation error
else Text validation passes
Frontend->>Frontend: Show loading state
Frontend->>Backend: POST /api/voice-google/translate<br/>(text, sourceLanguage, targetLanguage)
alt Authentication fails (401)
Backend-->>Frontend: 401 Unauthorized
Frontend-->>User: Show authentication error
else Empty text (400)
Backend-->>Frontend: 400 Bad Request
Frontend-->>User: Show empty text error
else Translation fails (400)
Backend-->>Frontend: 400 Bad Request + error details
Frontend-->>User: Show translation error
else Success (200)
Backend-->>Frontend: {success: true, original_text, translated_text, source_language, target_language}
Frontend->>Frontend: Display original text
Frontend->>Frontend: Display translated text
Frontend->>Frontend: Display language information
Frontend-->>User: Show translation result
end
end
```
---
## Customer Journey 3: Real-time Voice Interpretation
### User Goal
"I want to speak in one language and get the translated text in another language."
### User Story
As a user, I want to record my speech through the frontend microphone and receive both the transcribed text in the source language and its translation in the target language.
### User Story Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Backend
User->>Frontend: Select source language (default: de-DE)
User->>Frontend: Select target language (default: en-US)
User->>Frontend: Click "Start Recording"
Frontend->>Frontend: Request microphone access
alt Microphone access denied
Frontend-->>User: Show permission error
else Microphone access granted
Frontend->>Frontend: Start audio recording
Frontend-->>User: Show recording indicator (red dot, timer)
User->>Frontend: Speak into microphone
Frontend->>Frontend: Capture audio stream
User->>Frontend: Click "Stop Recording"
Frontend->>Frontend: Stop audio recording
Frontend->>Frontend: Convert audio stream to audio file
Frontend->>Frontend: Validate audio file
alt File validation fails
Frontend-->>User: Show validation error
else File validation passes
Frontend->>Frontend: Show loading state
Frontend->>Backend: POST /api/voice-google/realtime-interpreter<br/>(audioFile, fromLanguage, toLanguage, connectionId?)
alt Authentication fails (401)
Backend-->>Frontend: 401 Unauthorized
Frontend-->>User: Show authentication error
else Invalid audio format (400)
Backend-->>Frontend: 400 Bad Request + error details
Frontend-->>User: Show format error
else Interpretation fails (400)
Backend-->>Frontend: 400 Bad Request + error details
Frontend-->>User: Show interpretation error
else Success (200)
Backend-->>Frontend: {success: true, original_text, translated_text, confidence, source_language, target_language, audio_info}
Frontend->>Frontend: Display original transcribed text
Frontend->>Frontend: Display translated text
Frontend->>Frontend: Display confidence score
Frontend->>Frontend: Display language information
Frontend->>Frontend: Display audio metadata
Frontend-->>User: Show interpretation result with both texts
end
end
end
```
---
## Customer Journey 4: Converting Text to Speech
### User Goal
"I want to convert written text into spoken audio."
### User Story
As a user, I want to enter text, select a language and voice, and receive an audio file of the spoken text.
### User Story Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Backend
User->>Frontend: Enter text to speak
User->>Frontend: Select language (default: de-DE)
User->>Frontend: Select voice (optional, default from settings)
User->>Frontend: Click "Generate Speech"
Frontend->>Frontend: Validate text is not empty
alt Text is empty
Frontend-->>User: Show validation error
else Text validation passes
Frontend->>Frontend: Show loading state
Frontend->>Backend: POST /api/voice-google/text-to-speech<br/>(text, language, voice?)
alt Authentication fails (401)
Backend-->>Frontend: 401 Unauthorized
Frontend-->>User: Show authentication error
else Empty text (400)
Backend-->>Frontend: 400 Bad Request
Frontend-->>User: Show empty text error
else Text-to-Speech fails (400)
Backend-->>Frontend: 400 Bad Request + error details
Frontend-->>User: Show TTS error
else Success (200)
Backend-->>Frontend: Audio file (audio/mpeg)<br/>Headers: X-Voice-Name, X-Language-Code
Frontend->>Frontend: Create audio blob from response
Frontend->>Frontend: Create download link or audio player
Frontend->>Frontend: Display voice name and language
Frontend-->>User: Show audio player with download option
end
end
```
---
## Customer Journey 5: Managing Voice Settings
### User Goal
"I want to configure my default voice settings for speech recognition, translation, and text-to-speech."
### User Story
As a user, I want to view and update my voice settings including default languages, voice preferences, and translation settings.
### User Story Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Backend
User->>Frontend: Navigate to voice settings
Frontend->>Backend: GET /api/voice-google/settings
Backend-->>Frontend: {success: true, data: {user_settings, default_settings}}
Frontend->>Frontend: Pre-populate form with user_settings or default_settings
Frontend-->>User: Display settings form
alt User views settings only
User->>Frontend: View current settings
Frontend-->>User: Display settings (read-only or editable)
else User updates settings
User->>Frontend: Modify settings (sttLanguage, ttsLanguage, ttsVoice, translationEnabled, targetLanguage)
User->>Frontend: Click "Save Settings"
Frontend->>Frontend: Validate required fields (sttLanguage, ttsLanguage, ttsVoice)
alt Validation fails
Frontend-->>User: Show validation errors
else Validation passes
Frontend->>Frontend: Show loading state
Frontend->>Backend: POST /api/voice-google/settings<br/>(settings object)
alt Authentication fails (401)
Backend-->>Frontend: 401 Unauthorized
Frontend-->>User: Show authentication error
else Missing required field (400)
Backend-->>Frontend: 400 Bad Request + field name
Frontend-->>User: Show missing field error
else Save fails (500)
Backend-->>Frontend: 500 Internal Server Error
Frontend-->>User: Show save error
else Success (200)
Backend-->>Frontend: {success: true, message, data: settings}
Frontend->>Frontend: Update UI with saved settings
Frontend->>Frontend: Show success message
Frontend-->>User: Display confirmation and updated settings
end
end
end
```
---
## Customer Journey 6: Discovering Available Languages and Voices
### User Goal
"I want to see what languages and voices are available for speech and translation services."
### User Story
As a user, I want to browse available languages and filter voices by language to configure my preferences.
### User Story Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Backend
alt User wants to see available languages
User->>Frontend: Navigate to language selection
Frontend->>Backend: GET /api/voice-google/languages
Backend-->>Frontend: {success: true, languages: [...]}
Frontend->>Frontend: Display language list
Frontend-->>User: Show available languages
end
alt User wants to see available voices
User->>Frontend: Navigate to voice selection
User->>Frontend: Optionally select language filter
Frontend->>Backend: GET /api/voice-google/voices<br/>?language_code=de-DE (optional)
Backend-->>Frontend: {success: true, voices: [...], language_filter: "de-DE"}
Frontend->>Frontend: Display voice list
Frontend->>Frontend: Group voices by language if no filter
Frontend-->>User: Show available voices
end
alt User filters voices by language
User->>Frontend: Select language in filter
Frontend->>Backend: GET /api/voice-google/voices?language_code=selected
Backend-->>Frontend: Filtered voices list
Frontend->>Frontend: Update voice list
Frontend-->>User: Show filtered voices
end
```
---
## Customer Journey 7: Real-time Speech-to-Text via WebSocket
### User Goal
"I want to get real-time transcription as I speak, without uploading a complete audio file."
### User Story
As a user, I want to establish a WebSocket connection and stream audio chunks to receive live transcription results.
### User Story Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Backend
User->>Frontend: Initiate real-time speech-to-text
User->>Frontend: Select language (default: de-DE)
Frontend->>Frontend: Start audio capture
Frontend->>Backend: WebSocket: /api/voice-google/ws/speech-to-text<br/>?userId=user&language=de-DE
Backend->>Backend: Accept WebSocket connection
Backend->>Backend: Initialize voice interface
Backend-->>Frontend: {type: "connected", connection_id, message}
Frontend-->>User: Show "Connected" status
loop User speaks
User->>Frontend: Speak into microphone
Frontend->>Frontend: Capture audio chunk
Frontend->>Frontend: Encode audio chunk to base64
Frontend->>Backend: {type: "audio_chunk", data: base64_audio, timestamp}
alt Processing error
Backend->>Backend: Log error
Backend-->>Frontend: {type: "error", error: "..."}
Frontend-->>User: Show error message
else Success
Backend->>Backend: Process audio chunk (Speech-to-Text)
Backend-->>Frontend: {type: "transcription_result", text, confidence, is_final}
Frontend->>Frontend: Update transcription display
Frontend-->>User: Show live transcription (interim or final)
end
end
alt User sends ping
User->>Frontend: Keep-alive ping
Frontend->>Backend: {type: "ping", timestamp}
Backend-->>Frontend: {type: "pong", timestamp}
end
alt User stops or disconnects
User->>Frontend: Stop recording
Frontend->>Backend: Close WebSocket
Backend->>Backend: Cleanup connection
Frontend-->>User: Show disconnected status
end
```
---
## Customer Journey 8: Real-time Text-to-Speech via WebSocket
### User Goal
"I want to send text and receive audio streams in real-time without waiting for a complete file."
### User Story
As a user, I want to establish a WebSocket connection, send text messages, and receive audio chunks for playback.
### User Story Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Backend
User->>Frontend: Initiate real-time text-to-speech
User->>Frontend: Select language (default: de-DE)
User->>Frontend: Select voice (default: de-DE-Wavenet-A)
Frontend->>Backend: WebSocket: /api/voice-google/ws/text-to-speech<br/>?userId=user&language=de-DE&voice=de-DE-Wavenet-A
Backend->>Backend: Accept WebSocket connection
Backend-->>Frontend: {type: "connected", connection_id, message}
Frontend-->>User: Show "Connected" status
loop User sends text
User->>Frontend: Enter text to speak
User->>Frontend: Click "Speak" or send
Frontend->>Backend: {type: "text_to_speak", text: "..."}
alt Processing error
Backend->>Backend: Log error
Backend-->>Frontend: {type: "error", error: "..."}
Frontend-->>User: Show error message
else Success
Backend->>Backend: Process text-to-speech
Backend-->>Frontend: {type: "audio_data", audio: base64_audio, format: "mp3"}
Frontend->>Frontend: Decode base64 audio
Frontend->>Frontend: Create audio blob
Frontend->>Frontend: Play audio or queue for playback
Frontend-->>User: Play generated speech audio
end
end
alt User sends ping
User->>Frontend: Keep-alive ping
Frontend->>Backend: {type: "ping", timestamp}
Backend-->>Frontend: {type: "pong", timestamp}
end
alt User disconnects
User->>Frontend: Close connection
Frontend->>Backend: Close WebSocket
Backend->>Backend: Cleanup connection
Frontend-->>User: Show disconnected status
end
```

File diff suppressed because it is too large Load diff

View file

@ -1,768 +0,0 @@
# Workflow Routes Frontend Documentation
This document describes customer journeys for managing workflows through the frontend, focusing on how users interact with workflows and how the backend routes support these experiences. All UI components are dynamically generated from backend metadata—no hardcoding required.
## Table of Contents
1. [Overview](#overview)
2. [Customer Journey 1: Discovering and Browsing Workflows](#customer-journey-1-discovering-and-browsing-workflows)
3. [Customer Journey 2: Viewing Workflow Details](#customer-journey-2-viewing-workflow-details)
4. [Customer Journey 3: Monitoring Workflow Execution](#customer-journey-3-monitoring-workflow-execution)
5. [Customer Journey 4: Editing Workflow Properties](#customer-journey-4-editing-workflow-properties)
6. [Customer Journey 5: Managing Workflow Messages](#customer-journey-5-managing-workflow-messages)
7. [Customer Journey 6: Cleaning Up Workflows](#customer-journey-6-cleaning-up-workflows)
8. [Backend Metadata System](#backend-metadata-system)
9. [Implementation Patterns](#implementation-patterns)
---
## Overview
The workflow routes (`/api/workflows`) enable users to manage and monitor workflows that are already running or completed. These routes focus on **management and monitoring** rather than creation (workflows are created through the chat playground routes).
**Key Principles:**
- **User-Centric**: Documentation organized around what users want to accomplish
- **Backend-Driven**: All forms, tables, and UI components generated from backend metadata
- **No Hardcoding**: Field definitions, labels, validation rules, and options come from the backend
- **Real-Time Updates**: Support for polling and incremental data loading
- **Permission-Aware**: Backend enforces permissions; frontend handles gracefully
---
## Customer Journey 1: Discovering and Browsing Workflows
### User Goal
"I want to see all my workflows and find the one I'm looking for."
### User Story
As a user, I want to browse my workflows, search for specific workflows, filter by any field, sort them by different criteria, and quickly identify which ones are running, completed, or have errors.
### User Story Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Backend
User->>Frontend: Navigate to /workflows
Frontend->>Backend: GET /api/attributes/ChatWorkflow
Backend-->>Frontend: Attribute definitions (fields, labels, types)
Frontend->>Backend: GET /api/workflows/?pagination=...
Backend-->>Frontend: Paginated workflows list
Frontend->>Frontend: Generate table columns from attributes
Frontend->>Frontend: Generate filter controls from attributes
Frontend->>Frontend: Render workflows table + search + filters
Frontend-->>User: Display workflow list with search/filter UI
alt User performs general search
User->>Frontend: Type in search box (e.g., "invoice")
Frontend->>Frontend: Update search query
Frontend->>Backend: GET /api/workflows/?pagination=...filters:{"search":"invoice"}
Backend-->>Frontend: Filtered workflows list
Frontend-->>User: Display matching workflows
end
alt User applies field filter
User->>Frontend: Select filter field (e.g., "Status")
Frontend->>Frontend: Show filter options from attribute metadata
User->>Frontend: Select filter value (e.g., "running")
Frontend->>Frontend: Update filter parameters
Frontend->>Backend: GET /api/workflows/?pagination=...filters:{"status":"running"}
Backend-->>Frontend: Filtered workflows list
Frontend-->>User: Display filtered workflows
end
alt User combines search + filter + sort
User->>Frontend: Apply search + filter + sort
Frontend->>Frontend: Combine all parameters
Frontend->>Backend: GET /api/workflows/?pagination=...filters:{"search":"invoice","status":"running"}...sort:desc
Backend-->>Frontend: Filtered, sorted workflows list
Frontend-->>User: Display results
end
User->>Frontend: Click column header (e.g., "Last Activity")
Frontend->>Frontend: Update sort parameters
Frontend->>Backend: GET /api/workflows/?pagination=...sort:desc
Backend-->>Frontend: Sorted workflows list
Frontend-->>User: Display sorted workflows
User->>Frontend: Click workflow row
Frontend->>Frontend: Navigate to /workflows/workflowId
Frontend-->>User: Show workflow detail page
```
## Customer Journey 2: Viewing Workflow Details
### User Goal
"I want to see everything about a specific workflow—its current state, what it's doing, and what it has accomplished."
### User Story
As a user, I want to open a workflow and see its complete information, including its configuration, current status, messages, and logs, all in one place.
### User Story Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Backend
User->>Frontend: Click workflow from list
Frontend->>Backend: GET /api/workflows/workflowId
Backend-->>Frontend: Workflow object
Frontend->>Backend: GET /api/attributes/ChatWorkflow
Backend-->>Frontend: Field definitions
Frontend->>Backend: GET /api/workflows/workflowId/messages
Backend-->>Frontend: Messages list
Frontend->>Backend: GET /api/workflows/workflowId/logs
Backend-->>Frontend: Logs list
Frontend->>Frontend: Generate UI from metadata
Frontend->>Frontend: Render workflow info section
Frontend->>Frontend: Render messages section
Frontend->>Frontend: Render logs section
Frontend-->>User: Display complete workflow view
```
### Frontend Requirements
> **📋 Complete frontend requirements for this journey are documented in [Workflow Page Requirements](./workflow-page-requirements.md#customer-journey-2-viewing-workflow-details)**
The frontend must implement a workflow detail page that displays workflow information, messages, and logs. All UI components are generated from backend metadata—see the requirements document for complete details.
```typescript
// Fetch workflow and attributes
const [workflow, attributes] = await Promise.all([
fetch(`/api/workflows/${workflowId}`).then(r => r.json()),
fetch('/api/attributes/ChatWorkflow').then(r => r.json())
]);
// Separate editable vs read-only fields
const readOnlyFields = attributes.attributes.filter(attr =>
attr.visible && !attr.editable
);
const editableFields = attributes.attributes.filter(attr =>
attr.visible && attr.editable
);
// Render information section
<WorkflowInfoSection>
{readOnlyFields.map(attr => (
<InfoField
key={attr.name}
label={attr.label}
value={formatValue(workflow[attr.name], attr.type, attr.options)}
/>
))}
</WorkflowInfoSection>
// Show edit button if user has editable fields and permission
{editableFields.length > 0 && (
<Button onClick={() => navigate(`/workflows/${workflowId}/edit`)}>
Edit Workflow
</Button>
)}
```
---
## Customer Journey 3: Monitoring Workflow Execution
### User Goal
"I want to watch my workflow as it runs and see updates in real-time."
### User Story
As a user, I want to monitor a running workflow and see new messages and logs appear automatically without refreshing the page.
### User Story Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Backend
User->>Frontend: Open workflow detail page
Frontend->>Backend: GET /api/workflows/id/status
Backend-->>Frontend: Current workflow status
Frontend->>Backend: GET /api/workflows/id/messages
Backend-->>Frontend: Initial messages
Frontend->>Backend: GET /api/workflows/id/logs
Backend-->>Frontend: Initial logs
Frontend-->>User: Display initial state
loop Every 5 seconds (if running)
Frontend->>Backend: GET /api/workflows/id/status
Backend-->>Frontend: Updated status
Frontend->>Frontend: Update status badge
Frontend-->>User: Show status update
end
loop Every 3 seconds (if running)
Frontend->>Backend: GET /api/workflows/id/messages?messageId=lastId
Backend-->>Frontend: New messages (if any)
alt New messages exist
Frontend->>Frontend: Append to messages list
Frontend-->>User: Show new messages
end
end
loop Every 3 seconds (if running)
Frontend->>Backend: GET /api/workflows/id/logs?logId=lastId
Backend-->>Frontend: New logs (if any)
alt New logs exist
Frontend->>Frontend: Prepend to logs list
Frontend-->>User: Show new logs
end
end
Backend->>Backend: Workflow completes
Frontend->>Backend: GET /api/workflows/id/status
Backend-->>Frontend: Status: "completed"
Frontend->>Frontend: Stop all polling
Frontend-->>User: Show completion message
```
## Customer Journey 4: Editing Workflow Properties
### User Goal
"I want to change workflow settings like its name, status, or mode."
### User Story
As a user, I want to edit a workflow's properties through a form that only shows fields I'm allowed to edit, with validation and clear error messages.
### User Story Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Backend
User->>Frontend: Click "Edit" button
Frontend->>Frontend: Navigate to /workflows/id/edit
Frontend->>Backend: GET /api/workflows/workflowId
Backend-->>Frontend: Current workflow data
Frontend->>Backend: GET /api/attributes/ChatWorkflow
Backend-->>Frontend: Field definitions (editable fields)
Frontend->>Frontend: Filter editable fields
Frontend->>Frontend: Generate form from attributes
Frontend->>Frontend: Pre-populate form with workflow data
Frontend-->>User: Display edit form
User->>Frontend: Modify form fields
User->>Frontend: Click "Save"
Frontend->>Frontend: Validate form (required fields, types)
alt Validation fails
Frontend-->>User: Show validation errors
else Validation passes
Frontend->>Frontend: Optimistic update: Apply changes to UI immediately
Frontend->>Backend: PUT /api/workflows/workflowId + form data
alt Permission denied (403)
Backend-->>Frontend: 403 Forbidden
Frontend->>Frontend: Revert optimistic update
Frontend-->>User: Show permission error
else Validation error (400)
Backend-->>Frontend: 400 Bad Request + error details
Frontend->>Frontend: Revert optimistic update
Frontend-->>User: Show backend validation errors
else Success (200)
Backend-->>Frontend: Updated workflow
Frontend->>Frontend: Keep optimistic update (or refresh from response)
Frontend->>Frontend: Navigate to detail page
Frontend-->>User: Show updated workflow
end
end
```
## Customer Journey 5: Cleaning Up Workflows
### User Goal
"I want to delete workflows I no longer need."
### User Story
As a user, I want to delete workflows that are completed or no longer useful, with a clear confirmation to prevent accidental deletion.
### User Story Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Backend
User->>Frontend: Click "Delete" button
Frontend->>Backend: GET /api/workflows/workflowId
Backend-->>Frontend: Workflow data (for name)
Frontend->>Frontend: Show confirmation dialog<br/>"Delete 'Workflow Name'?"
User->>Frontend: Cancel deletion
Frontend-->>User: Dialog closed, no action
User->>Frontend: Click "Delete" button again
Frontend->>Backend: GET /api/workflows/workflowId
Backend-->>Frontend: Workflow data
Frontend->>Frontend: Show confirmation dialog
User->>Frontend: Confirm deletion
Frontend->>Frontend: Optimistic update: Remove workflow from UI immediately
Frontend->>Backend: DELETE /api/workflows/workflowId
alt Permission denied (403)
Backend-->>Frontend: 403 Forbidden
Frontend->>Frontend: Revert optimistic update: Restore workflow in UI
Frontend-->>User: Show permission error
else Not found (404)
Backend-->>Frontend: 404 Not Found
Frontend->>Frontend: Revert optimistic update: Restore workflow in UI
Frontend-->>User: Show not found error
else Success (200)
Backend-->>Frontend: Success response
Frontend->>Frontend: Keep optimistic update (workflow already removed)
Frontend->>Frontend: Show success message
Frontend->>Frontend: Navigate to /workflows (if on detail page)
Frontend-->>User: Display workflow list (without deleted workflow)
end
```
### Frontend Requirements
> **📋 Complete frontend requirements for this journey are documented in [Workflow Page Requirements](./workflow-page-requirements.md#customer-journey-6-cleaning-up-workflows)**
The frontend must implement workflow deletion with confirmation dialogs and proper error handling. See the requirements document for complete details.
### Backend Routes Used
| Route | Purpose | When Used |
|-------|---------|-----------|
| `DELETE /api/workflows/{workflowId}` | Delete workflow | User confirmation |
### User Navigation Flow
```mermaid
stateDiagram-v2
[*] --> WorkflowDetailPage
WorkflowDetailPage --> ViewingDeleteButton: Hover delete button
ViewingDeleteButton --> ClickingDelete: Click delete
ClickingDelete --> FetchingWorkflowName: Fetch workflow name
FetchingWorkflowName --> ShowingConfirmation: Show dialog
ShowingConfirmation --> WorkflowDetailPage: Cancel
ShowingConfirmation --> ConfirmingDeletion: Confirm
ConfirmingDeletion --> DeletingWorkflow: API call
DeletingWorkflow --> WorkflowListPage: Success
DeletingWorkflow --> ShowingError: Error (403/404)
ShowingError --> WorkflowDetailPage: Dismiss error
note right of ShowingConfirmation
ConfirmationDialog Component:
- Workflow name
- Warning message
- Cancel/Confirm buttons
end note
note right of DeletingWorkflow
DELETE /api/workflows/{id}
- Backend deletes workflow
- Deletes all associated data
- Returns success response
end note
note right of WorkflowListPage
List automatically refreshes
Deleted workflow removed
Success message shown
end note
```
### Example User Flow
```
1. User is on workflow detail page
2. User clicks "Delete" button
3. Frontend shows confirmation dialog: "Are you sure you want to delete 'Workflow Name'? This action cannot be undone."
4. User confirms deletion
5. Frontend calls: DELETE /api/workflows/{workflowId}
6. Backend deletes workflow and all associated data
7. Frontend receives success response
8. Frontend shows success message: "Workflow deleted successfully"
9. Frontend redirects to /workflows (list page)
10. User sees updated workflow list (without deleted workflow)
```
### Implementation Pattern
```typescript
function WorkflowDetailPage({ workflowId }) {
const navigate = useNavigate();
const handleDelete = async () => {
// Fetch workflow name for confirmation
const workflow = await fetch(`/api/workflows/${workflowId}`).then(r => r.json());
if (!confirm(`Are you sure you want to delete "${workflow.name || 'this workflow'}"? This action cannot be undone.`)) {
return;
}
try {
const response = await fetch(`/api/workflows/${workflowId}`, {
method: 'DELETE'
});
if (response.status === 403) {
showError('You do not have permission to delete this workflow');
return;
}
if (response.status === 404) {
showError('Workflow not found');
return;
}
if (!response.ok) {
const error = await response.json();
showError(error.detail || 'Failed to delete workflow');
return;
}
showSuccess('Workflow deleted successfully');
navigate('/workflows');
} catch (error) {
showError('Failed to delete workflow');
}
};
return (
<div>
{/* Workflow content */}
<Button onClick={handleDelete} variant="danger">
Delete Workflow
</Button>
</div>
);
}
```
---
## Backend Metadata System
### How Metadata Works
The backend serves all UI metadata through the `/api/attributes/{entityType}` endpoint. This enables completely dynamic frontend generation with no hardcoding.
#### Attribute Definition Structure
```typescript
interface AttributeDefinition {
name: string; // Field name (e.g., "status", "name")
type: string; // Frontend type: "text", "select", "integer", "timestamp", "checkbox"
label: string; // Display label (localized to user's language)
description: string; // Field description
required: boolean; // Whether field is required
readonly: boolean; // Whether field is read-only
editable: boolean; // Whether field can be edited (inverse of readonly)
visible: boolean; // Whether field should be displayed
order: number; // Display order (lower = earlier)
placeholder: string; // Placeholder text for inputs
options?: Option[]; // Options for select fields (with localized labels)
default?: any; // Default value
}
interface Option {
value: string; // Option value (e.g., "running")
label: { // Localized labels
[language: string]: string; // e.g., {"en": "Running", "fr": "En cours"}
};
}
```
#### Fetching Metadata
```typescript
// Fetch attribute definitions for ChatWorkflow
const response = await fetch('/api/attributes/ChatWorkflow');
const data = await response.json();
const attributes = data.attributes; // AttributeDefinition[]
```
#### Using Metadata for Forms
```typescript
// Generate form fields from attributes
const formFields = attributes
.filter(attr => attr.visible && attr.editable) // Only editable, visible fields
.sort((a, b) => a.order - b.order) // Sort by order
.map(attr => ({
name: attr.name,
label: attr.label,
type: attr.type,
required: attr.required,
options: attr.options,
placeholder: attr.placeholder,
default: attr.default
}));
```
#### Using Metadata for Tables
```typescript
// Generate table columns from attributes
const tableColumns = attributes
.filter(attr => attr.visible) // Only visible fields
.sort((a, b) => a.order - b.order) // Sort by order
.map(attr => ({
key: attr.name,
label: attr.label,
type: attr.type,
sortable: true, // Can be made configurable
render: (value) => formatValue(value, attr.type, attr.options)
}));
```
### Field Type Handling
Different field types require different UI components:
| Type | UI Component | Example Values |
|------|--------------|----------------|
| `text` | Text input | "My Workflow" |
| `textarea` | Textarea | Long descriptions |
| `integer` | Number input | 5, 10, 100 |
| `select` | Dropdown | Options from `options` array |
| `checkbox` | Checkbox | true/false |
| `timestamp` | Date/time picker | Unix timestamp |
### Localization
All labels and option labels support multiple languages. The backend serves labels in the user's language (determined by authentication context). The frontend should:
1. Use `label` directly (already localized)
2. For select options, use `option.label[userLanguage]` or fallback to `option.value`
---
## Implementation Patterns
### Pattern 1: Dynamic Table Component
```typescript
function DynamicTable({ entityType, data, pagination, onSort, onPageChange, onRowClick }) {
const [attributes, setAttributes] = useState([]);
useEffect(() => {
fetch(`/api/attributes/${entityType}`)
.then(r => r.json())
.then(data => setAttributes(data.attributes.filter(attr => attr.visible)));
}, [entityType]);
const columns = attributes
.sort((a, b) => a.order - b.order)
.map(attr => ({
key: attr.name,
label: attr.label,
type: attr.type,
render: (value) => formatValue(value, attr.type, attr.options)
}));
return (
<Table>
<thead>
<tr>
{columns.map(col => (
<th key={col.key} onClick={() => handleSort(col.key)}>
{col.label}
</th>
))}
</tr>
</thead>
<tbody>
{data.map(row => (
<tr key={row.id} onClick={() => onRowClick?.(row)}>
{columns.map(col => (
<td key={col.key}>{col.render(row[col.key])}</td>
))}
</tr>
))}
</tbody>
</Table>
);
}
```
### Pattern 2: Dynamic Form Component
```typescript
function DynamicForm({ entityType, initialValues, onSubmit, onCancel }) {
const [attributes, setAttributes] = useState([]);
const [formData, setFormData] = useState(initialValues || {});
const [errors, setErrors] = useState({});
useEffect(() => {
fetch(`/api/attributes/${entityType}`)
.then(r => r.json())
.then(data => {
const editable = data.attributes.filter(attr => attr.visible && attr.editable);
setAttributes(editable);
});
}, [entityType]);
const handleSubmit = (e) => {
e.preventDefault();
// Validate
const newErrors = {};
attributes.forEach(attr => {
if (attr.required && !formData[attr.name]) {
newErrors[attr.name] = `${attr.label} is required`;
}
});
if (Object.keys(newErrors).length > 0) {
setErrors(newErrors);
return;
}
onSubmit(formData);
};
return (
<form onSubmit={handleSubmit}>
{attributes
.sort((a, b) => a.order - b.order)
.map(attr => (
<FormField
key={attr.name}
field={attr}
value={formData[attr.name] ?? attr.default}
onChange={(value) => setFormData(prev => ({ ...prev, [attr.name]: value }))}
error={errors[attr.name]}
/>
))}
<button type="submit">Save</button>
{onCancel && <button type="button" onClick={onCancel}>Cancel</button>}
</form>
);
}
```
### Pattern 3: Polling Hook
```typescript
function usePolling(url, interval, condition = true) {
const [data, setData] = useState(null);
useEffect(() => {
if (!condition) return;
const fetchData = async () => {
try {
const response = await fetch(url);
if (response.ok) {
const result = await response.json();
setData(result);
}
} catch (error) {
console.error('Polling error:', error);
}
};
fetchData(); // Initial fetch
const intervalId = setInterval(fetchData, interval);
return () => clearInterval(intervalId);
}, [url, interval, condition]);
return data;
}
// Usage
const workflow = usePolling(
`/api/workflows/${workflowId}/status`,
5000,
workflow?.status === 'running'
);
```
### Pattern 4: Incremental Data Loading
```typescript
function useIncrementalData(baseUrl, lastIdKey) {
const [items, setItems] = useState([]);
const [lastId, setLastId] = useState(null);
const loadInitial = async () => {
const response = await fetch(baseUrl).then(r => r.json());
const newItems = response.items || response;
setItems(newItems);
if (newItems.length > 0) {
setLastId(newItems[newItems.length - 1][lastIdKey]);
}
};
const loadNew = async () => {
if (!lastId) return;
const url = `${baseUrl}?${lastIdKey}=${lastId}`;
const response = await fetch(url).then(r => r.json());
const newItems = response.items || response;
if (newItems.length > 0) {
setItems(prev => [...prev, ...newItems]);
setLastId(newItems[newItems.length - 1][lastIdKey]);
}
};
useEffect(() => {
loadInitial();
}, [baseUrl]);
return { items, loadNew };
}
// Usage for messages
const { items: messages, loadNew: loadNewMessages } = useIncrementalData(
`/api/workflows/${workflowId}/messages`,
'messageId'
);
// Poll for new messages
useEffect(() => {
if (workflow?.status !== 'running') return;
const interval = setInterval(loadNewMessages, 3000);
return () => clearInterval(interval);
}, [workflow?.status, loadNewMessages]);
```
---
## Summary
This documentation focuses on **customer journeys**—what users want to accomplish with workflows. Each journey describes:
1. **User Goal**: What the user is trying to achieve
2. **User Story**: The scenario from the user's perspective
3. **Frontend Requirements**: What pages/components are needed
4. **Backend Routes**: Which API endpoints support the journey
5. **Example Flows**: Step-by-step user interactions
6. **Implementation Patterns**: Code examples for common patterns
The key principle throughout: **Everything is dynamic and driven by backend metadata**. The frontend should never hardcode field definitions, validation rules, labels, or UI structure. All of this comes from the backend's attribute definition system.
By following these customer journeys and using the backend metadata system, you can build a frontend that:
- Adapts automatically to backend changes
- Supports multiple languages
- Enforces permissions correctly
- Provides real-time updates
- Requires minimal maintenance

View file

@ -1,555 +0,0 @@
# Workflow Page Requirements
This document contains the complete frontend requirements for the workflow management page and its views/components. All UI components are dynamically generated from backend metadata—no hardcoding required.
## Table of Contents
1. [Overview](#overview)
2. [Page Structure and Layout](#page-structure-and-layout)
3. [User Interactions and Functionality](#user-interactions-and-functionality)
4. [Backend Routes and API Integration](#backend-routes-and-api-integration)
5. [Field and Attribute Reference](#field-and-attribute-reference)
6. [Dynamic Rendering Guidelines](#dynamic-rendering-guidelines)
---
## Overview
The workflow management page enables users to manage and monitor workflows that are already running or completed. The frontend consists of a single page (`/workflows`) with different views/states:
- **List View** - Browse, search, filter, and sort workflows
- **Detail View** - View complete workflow information, messages, and logs (expandable sections, roll down to see more)
- **Edit View** - Edit workflow properties (can be shown as popup/modal or inline edit)
All views use backend-driven UI generation, meaning field definitions, labels, validation rules, and UI structure come entirely from backend metadata through the `/api/attributes/ChatWorkflow` endpoint. Views are managed through component state and UI extensions (expandable sections, popups, modals) within the same page, not as separate routes.
---
## Page Structure and Layout
### Workflow Management Page (`/workflows`)
The workflow management page uses different views/states and UI extensions to handle different user interactions. Views are managed through component state and UI extensions (expandable sections, popups, modals) within the same page component.
### List View
**State:** `view === 'list'` or `selectedWorkflowId === null`
**What the user sees:**
- **Main Content Area:**
- Table or card grid displaying all workflows
- Each workflow row/card shows: name, status badge, last activity timestamp, progress indicators
- Clickable rows/cards that expand to show Detail View (expandable section or roll down)
- **Search and Filter Controls:**
- General search input box (searches across all text fields)
- Field-specific filter controls (one filter per visible field)
- Active filter indicators (chips/badges showing applied filters)
- "Clear all filters" button when filters are active
- **Sorting Controls:**
- Clickable column headers with sort indicators (up/down arrows)
- Visual indication of current sort field and direction
- Support for multi-level sorting
- **Pagination Controls:**
- Page information display ("Page X of Y", "Showing 1-20 of 45 workflows")
- Previous/Next page buttons
- Page number buttons
- Page size selector (10, 20, 50, 100 items per page)
### Detail View (Expandable Section)
**State:** `view === 'detail'` and `selectedWorkflowId !== null`
**UI Pattern:** Expandable section that rolls down from the selected workflow row, or inline expansion within the list
**What the user sees:**
- **Workflow Header Section:**
- Workflow name (editable indicator if user has permission)
- Status badge with color coding
- Key metrics (progress indicators, timestamps)
- **Workflow Information Section:**
- All workflow properties displayed as formatted fields
- Read-only fields shown as formatted text
- Editable fields shown with edit indicators (if user has permission)
- Special formatting:
- Status → Color-coded badge
- Timestamps → Relative time ("2 hours ago") or absolute date/time
- Progress fields → Progress bars
- Select fields → Display localized labels (not enum values)
- **Messages Section:**
- List of all messages in chronological order
- Each message shows: role (user/assistant/system), content, timestamp, attached files
- Message threading support (if `parentMessageId` exists)
- Pagination controls if many messages
- Delete button for each message (if user has permission)
- **Logs Section:**
- List of execution logs in reverse chronological order (newest first)
- Color-coded by type (info/warning/error)
- Progress indicators if `progress` field exists
- Filter controls by log type
- Pagination controls if many logs
- **Action Buttons:**
- Edit button (if user has permission and editable fields exist)
- Delete button (if user has permission)
- **Real-Time Updates** (when workflow is running):
- Status indicator that updates automatically
- New messages appearing in the messages list
- New logs appearing in the logs viewer
- Progress indicators updating
- Activity indicators showing workflow is active
### Workflow Edit Page (`/workflows/{workflowId}/edit`)
**What the user sees:**
- **Form Section:**
- Dynamic form with editable workflow fields only
- Field labels with required indicators (asterisk for required fields)
- Help text/tooltips from field descriptions
- Input validation errors displayed inline
- **Action Buttons:**
- Save button (submits form)
- Cancel button (navigates back to detail page)
- **Confirmation Dialogs:**
- Delete confirmation dialog (on workflow detail page)
- Message deletion confirmation dialog
- File deletion confirmation dialog
---
## User Interactions and Functionality
### Browsing and Discovery
**Search Functionality:**
- User types in general search box
- Frontend debounces input (300-500ms delay)
- Search applies across all text fields in workflow objects
- Results update automatically
- Page resets to page 1 when search changes
**Field Filtering:**
- User selects field to filter by
- Frontend shows appropriate filter UI based on field type:
- Text fields → Text input with operator selection (contains, equals, startsWith, endsWith)
- Select fields → Dropdown with options from backend metadata
- Integer fields → Number input with comparison operators (gt, gte, lt, lte) or range inputs
- Timestamp fields → Date picker with comparison operators or date range picker
- Checkbox fields → Boolean toggle (true/false/any)
- User applies filter → Filter appears as active chip/badge
- User can remove individual filters
- Multiple filters work together (AND logic)
- Page resets to page 1 when filters change
**Sorting:**
- User clicks column header
- Sort direction toggles (asc → desc → remove)
- Multiple columns can be sorted (multi-level sorting)
- Sort indicators show on column headers
- All filters and search preserved when sorting
**Pagination:**
- User clicks page number or navigation button
- Page updates and data refetches
- All filters, search, and sort preserved
- User changes page size → Page resets to 1, data refetches
**View Switching:**
- User clicks workflow row/card → Expands Detail View (expandable section rolls down, or switches to Detail View state)
- User clicks workflow name → Expands Detail View (expandable section rolls down, or switches to Detail View state)
- User clicks collapse/back button → Collapses Detail View, returns to List View
### Viewing Workflow Details
**Information Display:**
- All workflow fields displayed using dynamic rendering
- Read-only fields shown as formatted text
- Editable fields shown with edit indicators
- Special fields formatted appropriately (status badges, timestamps, progress bars)
**Messages Display:**
- Messages shown in chronological order (`publishedAt`)
- Role-based styling (user/assistant/system)
- Attached files displayed with download/view options
- Threading support for parent-child message relationships
- Pagination if many messages
**Logs Display:**
- Logs shown in reverse chronological order (newest first)
- Color-coded by type (info/warning/error)
- Progress indicators displayed if available
- Filtering by log type supported
**Real-Time Monitoring** (when workflow is running):
- Status polling every 2-5 seconds
- New messages polling every 2-3 seconds (incremental loading)
- New logs polling every 2-3 seconds (incremental loading)
- All polling stops when workflow status changes to "completed", "stopped", or "error"
- Completion message shown when workflow finishes
### Editing Workflows
**Form Interaction:**
- User clicks "Edit" button → Opens Edit View as popup/modal overlay
- Form pre-populated with current workflow values
- User modifies fields
- Client-side validation shows errors immediately
- User clicks Save → Form validates and submits
- User clicks Cancel → Closes popup/modal, returns to Detail View
**Form Validation:**
- Required field validation (shows error if empty)
- Type validation (e.g., integer fields must be numbers)
- Select field validation (value must be in options array)
- Validation errors displayed inline below fields
**Form Submission:**
- Only changed fields sent (or all form data)
- Success → Close popup/modal, refresh Detail View data, show success message
- Error handling:
- 403 (permission denied) → Show permission error in popup
- 400 (validation errors) → Display backend validation errors in popup
- Other errors → Show generic error message in popup
### Managing Messages
**Message Actions:**
- User clicks delete button on message
- Confirmation dialog appears
- User confirms → Message deleted, list updates
- User cancels → Dialog closes, no action
**File Actions:**
- User clicks delete button on file attachment
- Confirmation dialog appears
- User confirms → File removed from message, display updates
- User cancels → Dialog closes, no action
### Deleting Workflows
**Delete Action:**
- User clicks delete button (on detail page or list)
- Confirmation dialog appears with workflow name
- Warning about permanent deletion
- User confirms → Workflow deleted
- User cancels → Dialog closes, no action
**Delete Success Handling:**
- Success message displayed
- If Detail View is expanded → Collapse Detail View, return to List View
- If in List View → Remove workflow from list or refresh
---
## Backend Routes and API Integration
### Complete Route Reference
All backend routes used by workflow pages:
| Route | Method | Purpose | When Used |
|-------|--------|---------|-----------|
| `/api/workflows/` | GET | Get all workflows (with pagination) | Initial page load, pagination changes, sort changes, filter changes, search changes |
| `/api/workflows/{workflowId}` | GET | Get workflow details | Detail View expansion, Edit View popup open |
| `/api/workflows/{workflowId}` | PUT | Update workflow | Edit form submission in popup |
| `/api/workflows/{workflowId}` | DELETE | Delete workflow | User confirms deletion in popup |
| `/api/workflows/{workflowId}/status` | GET | Get current workflow status | Real-time polling (every 2-5s when running, Detail View expanded) |
| `/api/workflows/{workflowId}/messages` | GET | Get workflow messages | Detail View expansion, refresh, real-time polling (every 2-3s when running) |
| `/api/workflows/{workflowId}/messages` | GET | Get new messages (incremental) | Real-time polling with `messageId` parameter (Detail View expanded) |
| `/api/workflows/{workflowId}/messages/{messageId}` | DELETE | Delete message | User confirms message deletion in popup |
| `/api/workflows/{workflowId}/messages/{messageId}/files/{fileId}` | DELETE | Delete file from message | User confirms file deletion in popup |
| `/api/workflows/{workflowId}/logs` | GET | Get workflow logs | Detail View expansion, refresh, real-time polling (every 2-3s when running) |
| `/api/workflows/{workflowId}/logs` | GET | Get new logs (incremental) | Real-time polling with `logId` parameter (Detail View expanded) |
| `/api/attributes/ChatWorkflow` | GET | Get field definitions | Page load (once per page) - used to generate all UI components |
### API Request Patterns
**Pagination Request:**
```
GET /api/workflows/?pagination={"page":1,"pageSize":20,"sort":[],"filters":null}
```
- `pagination` parameter is JSON-encoded string
- If user wants all workflows: omit `pagination` parameter entirely
- Filters structure: `{"search":"query","fieldName":"value",...}`
**Incremental Loading (Polling):**
```
GET /api/workflows/{workflowId}/messages?messageId={lastMessageId}
GET /api/workflows/{workflowId}/logs?logId={lastLogId}
```
- Used for real-time updates
- Only fetch new items after the specified ID
- Prevents reloading all data
**Update Request:**
```
PUT /api/workflows/{workflowId}
Content-Type: application/json
Body: {fieldName: value, ...}
```
- Send only changed fields or all form data
- Handle 403 (permission denied) and 400 (validation errors)
**Delete Requests:**
```
DELETE /api/workflows/{workflowId}
DELETE /api/workflows/{workflowId}/messages/{messageId}
DELETE /api/workflows/{workflowId}/messages/{messageId}/files/{fileId}
```
- All delete operations require user confirmation
- Handle 403 (permission denied) and 404 (not found) gracefully
### Response Handling
**Paginated Response:**
```json
{
"items": [...],
"pagination": {
"currentPage": 1,
"pageSize": 20,
"totalItems": 45,
"totalPages": 3,
"sort": [...],
"filters": {...}
}
}
```
**Error Responses:**
- 403 Forbidden → Show permission error message
- 404 Not Found → Show "not found" error message
- 400 Bad Request → Display validation errors from response
- 500 Internal Server Error → Show generic error message
---
## Field and Attribute Reference
### Complete Field List
The following is a comprehensive list of all parameters, attributes, and fields that will be displayed for workflows. All of these are provided by the backend through the `/api/attributes/ChatWorkflow` endpoint and should never be hardcoded in the frontend.
#### Core Workflow Fields
**Identification Fields:**
- `id` - Unique workflow identifier (text, readonly, not required, visible)
- `mandateId` - ID of the mandate this workflow belongs to (text, readonly, not required, visible)
**Status and Configuration Fields:**
- `status` - Current workflow status (select, editable, not required, visible)
- Options: "running", "completed", "stopped", "error"
- Each option has localized labels (en/fr)
- `name` - Workflow name (text, editable, required, visible)
- `workflowMode` - Workflow execution mode (select, editable, not required, visible)
- Options: "Dynamic", "Automation", "Actionplan"
- Each option has localized labels (en/fr)
- `maxSteps` - Maximum number of iterations in react mode (integer, editable, not required, visible)
**Progress Tracking Fields:**
- `currentRound` - Current round number in workflow execution (integer, readonly, not required, visible)
- `currentTask` - Current task number within the current round (integer, readonly, not required, visible)
- `currentAction` - Current action number within the current task (integer, readonly, not required, visible)
- `totalTasks` - Total number of tasks in the workflow (integer, readonly, not required, visible)
- `totalActions` - Total number of actions in the workflow (integer, readonly, not required, visible)
**Timestamp Fields:**
- `startedAt` - When the workflow started (timestamp, readonly, not required, visible)
- `lastActivity` - Timestamp of last activity (timestamp, readonly, not required, visible)
**Related Data Fields (Lists):**
- `logs` - List of workflow log entries (text/list, readonly, not required, visible)
- `messages` - List of workflow messages (text/list, readonly, not required, visible)
- `stats` - List of workflow statistics (text/list, readonly, not required, visible)
- `tasks` - List of tasks in the workflow (text/list, readonly, not required, visible)
- `expectedFormats` - List of expected file format extensions (text/list, readonly, not required, visible)
### Pagination Parameters
**Request Parameters (`PaginationParams`):**
- `page` - Current page number (1-based, minimum 1)
- `pageSize` - Number of items per page (minimum 1, maximum 1000)
- `sort` - Array of sort field configurations
- Each sort field contains:
- `field` - Field name to sort by (must match a workflow field name)
- `direction` - Sort direction: "asc" or "desc"
- `filters` - Filter criteria dictionary
- `search` - General search term (searches across all text fields, case-insensitive)
- Field-specific filters: `{fieldName: value}` or `{fieldName: {operator: "operator", value: value}}`
- Supported operators: "equals", "contains", "startsWith", "endsWith", "gt", "gte", "lt", "lte", "in", "notIn"
**Response Metadata (`PaginationMetadata`):**
- `currentPage` - Current page number (1-based)
- `pageSize` - Number of items per page
- `totalItems` - Total number of items across all pages (after filters applied)
- `totalPages` - Total number of pages (calculated from totalItems / pageSize)
- `sort` - Current sort configuration applied (array of SortField objects)
- `filters` - Current filters applied (mirrors request filters)
### Attribute Definition Structure
Each field returned from `/api/attributes/ChatWorkflow` contains:
- `name` - Field name (e.g., "status", "name", "lastActivity")
- `type` - Field data type (e.g., "text", "select", "integer", "timestamp", "checkbox")
- `label` - Localized field label (object with language keys: {"en": "English Label", "fr": "French Label"})
- `description` - Field description text
- `required` - Boolean indicating if field is required
- `readonly` - Boolean indicating if field is read-only
- `editable` - Boolean indicating if field can be edited (inverse of readonly)
- `visible` - Boolean indicating if field should be displayed in UI
- `options` - Array of options for select fields (each option has `value` and localized `label`)
---
## Dynamic Rendering Guidelines
The frontend must render all UI components dynamically based on backend metadata. No field definitions, labels, validation rules, or UI structure should be hardcoded.
### Table Column Generation
When rendering the workflow list table:
1. Fetch attribute definitions from `/api/attributes/ChatWorkflow`
2. Filter attributes where `visible: true` to determine which columns to display
3. Use `label` property for column headers (select appropriate language based on user preference)
4. Use `type` property to determine how to format cell values:
- `text` fields → Display as plain text
- `select` fields → Display value using label from options array (match value to option.value, then display option.label)
- `integer` fields → Display as formatted number
- `timestamp` fields → Format as relative time ("2 hours ago") or absolute date/time based on user preference
- `checkbox` fields → Display as checkmark icon or boolean indicator
5. Use `readonly` property to determine if column should be sortable (readonly fields may still be sortable, but editable fields definitely are)
6. Generate click handlers for column headers to update sort parameters and refetch data
### Filter Control Generation
When rendering filter controls:
1. Fetch attribute definitions from `/api/attributes/ChatWorkflow`
2. Filter attributes where `visible: true` to determine which filters to show
3. For each visible field, generate appropriate filter UI based on `type`:
- `text` fields → Text input filter (supports "contains", "equals", "startsWith", "endsWith" operators)
- `select` fields → Dropdown filter with options from `options` array (use localized labels)
- `integer` fields → Number range filter (min/max inputs) or single number input with comparison operators (gt, gte, lt, lte)
- `timestamp` fields → Date range picker or single date picker with comparison operators
- `checkbox` fields → Boolean toggle filter (true/false/any)
4. Use `label` property for filter labels (localized)
5. When user applies filter, update `filters` object in pagination parameters and refetch data
6. Display active filters as chips/badges showing field label and value
7. Allow removing individual filters by removing them from `filters` object
### Search Implementation
For general search functionality:
1. Display a single search input box (not field-specific)
2. When user types, update `filters.search` in pagination parameters
3. Debounce search input (wait 300-500ms after user stops typing before sending request)
4. Search applies across all text fields in the workflow object
5. Reset to page 1 when search query changes
6. Combine search with field-specific filters (both are in the `filters` object)
### Form Field Generation
When rendering edit forms:
1. Fetch attribute definitions from `/api/attributes/ChatWorkflow`
2. Filter attributes where `visible: true` AND `editable: true` to determine which fields to show
3. For each editable field, generate appropriate form input based on `type`:
- `text` fields → Text input
- `select` fields → Dropdown/select input with options from `options` array (use localized labels)
- `integer` fields → Number input with appropriate min/max constraints
- `timestamp` fields → Date/time picker
- `checkbox` fields → Checkbox input
4. Use `label` property for field labels (localized)
5. Use `required` property to show required indicators (asterisk, etc.)
6. Use `description` property to show help text or tooltips
7. Validate form before submission:
- Check all `required: true` fields have values
- Validate types (e.g., integer fields must be numbers)
- Validate select fields (value must be in options array)
8. On submit, send only changed fields or all form data to update endpoint
### Display Formatting
When displaying field values:
1. Use `type` property to determine formatting:
- `text` → Display as-is (may need HTML escaping)
- `select` → Look up value in `options` array and display localized label
- `integer` → Format with thousand separators if needed
- `timestamp` → Format as relative time or absolute date/time
- `checkbox` → Display as checkmark icon or "Yes"/"No" text
2. Handle `null` or `undefined` values gracefully (show "-" or "Not set")
3. For list fields (logs, messages, stats), render as expandable sections or separate tables
4. Use `readonly` property to determine if field should show edit indicators
### Real-Time Polling
When monitoring running workflows:
1. **Status Polling:**
- Poll every 2-5 seconds if workflow status is "running"
- Stop polling if status is "completed", "stopped", or "error"
- Update status badge and workflow information on each poll
2. **Message Polling (Incremental Loading):**
- Store ID of last displayed message
- Poll every 2-3 seconds for messages after last message ID
- Append new messages to list (don't reload all)
- Only poll if workflow is "running"
3. **Log Polling (Incremental Loading):**
- Store ID of last displayed log
- Poll every 2-3 seconds for logs after last log ID
- Prepend new logs to list (newest first)
- Only poll if workflow is "running"
4. **Polling Management:**
- Stop all polling when workflow completes
- Show completion message
- Update UI to indicate workflow is finished
### Localization
All labels and options support multiple languages:
1. Use user's preferred language (from user settings or browser locale)
2. Access localized labels from `label` object: `label[userLanguage]` or `label.en` as fallback
3. For select options, use `option.label[userLanguage]` or `option.label.en` as fallback
4. If label for current language is missing, fall back to English
### Key Principles
- Never hardcode field names, labels, types, or validation rules
- Always fetch attribute definitions from backend before rendering UI
- Use attribute metadata to determine what to display and how to display it
- Support all field types dynamically - if backend adds new types, frontend should handle them
- Respect `visible`, `editable`, `readonly`, and `required` flags from backend
- Use localized labels from backend metadata
- Generate filters, forms, and tables entirely from attribute definitions
- When backend adds new fields, frontend should automatically display them without code changes
- Handle all error cases gracefully (403, 404, 400, 500)
- Provide user feedback for all actions (loading states, success messages, error messages)
---
## Summary
This document provides complete frontend requirements for the workflow management page and its views/components. All requirements follow the principle of **backend-driven UI generation**—no hardcoding of field definitions, labels, or validation rules. The frontend should dynamically generate all UI components from backend metadata provided through the `/api/attributes/ChatWorkflow` endpoint.
**Key Architecture Pattern:** The workflow management interface is a single page (`/workflows`) with different views managed through component state. Detail View is shown as an expandable section (roll down from selected workflow row), and Edit View is shown as a popup/modal overlay. All interactions happen within the same page component without separate routes.
For generic patterns that apply across all entity types (not just workflows), see the [Dynamic Forms and Pagination documentation](./dynamic-forms-and-pagination.md).

View file

@ -1,169 +0,0 @@
# Überblick und Projektstruktur
[← Zurück zum Inhaltsverzeichnis](README.md) | [Weiter: Datenmodell erstellen →](02-datamodels.md)
## Überblick
Das Feature "realEstate" bietet eine **stateless API** für Real Estate-Datenbankoperationen mit AI-basierter natürlicher Sprachverarbeitung:
### Hauptfunktionalität
- **Natürliche Sprache → CRUD-Operationen**: User-Input wird mit AI analysiert und in entsprechende Datenbankoperationen übersetzt
- **Direkte Datenbankabfragen**: SQL-Queries können direkt ausgeführt werden
- **CRUD-Operationen**: Erstellen, Lesen, Aktualisieren und Löschen von Real Estate-Entitäten
- **PostgreSQL-Datenbankzugriff**: Über den bestehenden DatabaseConnector
- **RESTful API-Endpunkte**: Einfache, stateless Endpunkte ohne Session-Management
- **Benutzerauthentifizierung und Zugriffskontrolle**: Integriert in bestehende UAM-Struktur
### Architektur-Ansatz
**Stateless Design:**
- Keine Chat-Sessions notwendig (optional für zukünftige Erweiterungen)
- Jeder Request ist unabhängig
- Direkter Flow: User-Input → AI-Analyse → CRUD-Operation → Ergebnis
- Keine Query-History (kann optional später hinzugefügt werden)
**AI-Integration:**
- Nutzt `serviceAi` für Intent-Erkennung
- Übersetzt natürliche Sprache in CRUD-Operationen
- Unterstützt CREATE, READ, UPDATE, DELETE, QUERY-Intents
**Real Estate-Datenmodell-Entitäten:**
- **Kernentitäten**: Projekt, Parzelle
- **Unterstützend**: Dokument, Kontext
- **Geografisch**: GeoPolylinie, GeoPunkt
- **Administrativ**: Land, Kanton, Gemeinde
### Architektur-Komponenten
Die Architektur folgt dem Muster bestehender Features:
- **Routes** (`modules/routes/`) - API-Endpunkte (stateless)
- **Features** (`modules/features/`) - Geschäftslogik mit AI-Integration
- **Interfaces** (`modules/interfaces/`) - Datenbankzugriff (CRUD-Operationen)
- **DataModels** (`modules/datamodels/`) - Pydantic-Modelle für Real Estate-Entitäten
- **Services** (`modules/services/`) - AI-Service für Intent-Analyse
---
## Projektstruktur
```
gateway/
├── modules/
│ ├── routes/
│ │ └── routeRealEstate.py # NEU: Stateless API-Endpunkte
│ │ ├── POST /api/realestate/command # Natürliche Sprache → CRUD
│ │ └── POST /api/realestate/query # Direkte SQL-Query
│ │
│ ├── features/
│ │ └── realEstate/
│ │ └── mainRealEstate.py # NEU: Feature-Logik mit AI-Integration
│ │ ├── processNaturalLanguageCommand() # Hauptfunktion
│ │ ├── analyzeUserIntent() # AI-basierte Intent-Analyse
│ │ └── executeIntentBasedOperation() # CRUD-Ausführung
│ │
│ ├── interfaces/
│ │ ├── interfaceDbRealEstateAccess.py # NEU: Zugriffskontrolle
│ │ ├── interfaceDbRealEstateObjects.py # NEU: CRUD-Interface
│ │ └── interfaceDbRealEstateChatObjects.py # OPTIONAL: Für Session-Support
│ │
│ ├── datamodels/
│ │ ├── datamodelRealEstate.py # NEU: Real Estate Datenmodelle
│ │ │ ├── Projekt, Parzelle, Dokument, etc.
│ │ └── datamodelRealEstateChat.py # OPTIONAL: Für Session-Support
│ │
│ ├── services/
│ │ └── serviceAi/ # BEREITS VORHANDEN
│ │ └── mainServiceAi.py # Wird für Intent-Analyse genutzt
│ │
│ └── connectors/
│ └── connectorDbPostgre.py # BEREITS VORHANDEN
├── app.py # Router-Registrierung
├── env_dev.env # Environment-Konfiguration
└── modules/features/featuresLifecycle.py # Feature-Lifecycle
```
### Wichtige Dateien
**Erforderlich:**
- `routeRealEstate.py` - API-Endpunkte (stateless)
- `mainRealEstate.py` - Feature-Logik mit AI-Integration
- `interfaceDbRealEstateAccess.py` - Zugriffskontrolle
- `interfaceDbRealEstateObjects.py` - CRUD-Interface
- `datamodelRealEstate.py` - Datenmodelle
**Optional (für zukünftige Session-Unterstützung):**
- `interfaceDbRealEstateChatObjects.py` - Session-Management
- `datamodelRealEstateChat.py` - Session-Modelle
---
## Datenfluss: User-Input → Ergebnis
### Flow: Natürliche Sprache ohne Session
```
1. User sendet Request
POST /api/realestate/command
Body: { "userInput": "Erstelle ein neues Projekt namens 'Hauptstrasse 42'" }
2. Route empfängt Request
routeRealEstate.process_command()
→ Auth: getCurrentUser()
3. Feature-Logik verarbeitet
mainRealEstate.processNaturalLanguageCommand()
→ Services initialisieren: getServices(currentUser, workflow=None)
4. AI analysiert Intent
analyzeUserIntent(services.ai, userInput)
→ services.ai.callAiPlanning(intentPrompt)
→ AI gibt zurück: { "intent": "CREATE", "entity": "Projekt", "parameters": {...} }
5. CRUD-Operation ausführen
executeIntentBasedOperation(intent, entity, parameters)
→ getRealEstateInterface(currentUser)
→ RealEstateObjects.createProjekt(projekt)
→ DatabaseConnector.recordCreate(Projekt)
6. Ergebnis zurückgeben
HTTP 200 OK
{ "success": true, "intent": "CREATE", "result": {...} }
```
### Flow: Direkte SQL-Query
```
1. User sendet Request
POST /api/realestate/query
Body: { "queryText": "SELECT * FROM Projekt WHERE plz = '8000'" }
2. Route empfängt Request
routeRealEstate.execute_direct_query()
→ Auth: getCurrentUser()
3. Query ausführen
getChatInterface(currentUser)
→ RealEstateChatObjects.executeQuery(queryText)
→ DatabaseConnector.executeQuery(sql)
4. Ergebnis zurückgeben
HTTP 200 OK
{ "rows": [...], "columns": [...], "rowCount": 15 }
```
---
## Vorteile des stateless Ansatzes
- **Einfachheit**: Kein Session-Management notwendig
- **Performance**: Weniger Datenbank-Operationen pro Request
- **Skalierbarkeit**: Stateless Requests sind einfacher zu skalieren
- **Flexibilität**: Jeder Request ist unabhängig
- **Erweiterbarkeit**: Session-Support kann später optional hinzugefügt werden
---
**Nächster Schritt:** [02-datamodels.md](02-datamodels.md)

View file

@ -1,288 +0,0 @@
# Schritt 2: Interface erstellen
[← Zurück: Datenmodell erstellen](02-datamodels.md) | [Weiter: Feature-Logik implementieren →](04-feature-logic.md)
## Übersicht: Was sind Interfaces?
**Interfaces** sind aktive Klassen, die den **Datenbankzugriff** implementieren. Sie unterscheiden sich von **Datamodels** (die nur die Datenstruktur definieren):
| **Aspekt** | **Datamodels** | **Interfaces** |
|------------|----------------|----------------|
| **Zweck** | Definiert **WAS** (Datenstruktur) | Implementiert **WIE** (Datenzugriff) |
| **Inhalt** | Pydantic-Modelle mit Feldern und Validierung | Klassen mit CRUD-Methoden (`create`, `get`, `update`, `delete`) |
| **Beispiel** | `class Projekt(BaseModel): ...` | `def createProjekt(...) -> Projekt: ...` |
| **Aktivität** | Passiv (nur Struktur) | Aktiv (führt Operationen aus) |
**Analogie:**
- **Datamodel** = Bauplan (beschreibt das Haus)
- **Interface** = Bauunternehmer (baut das Haus)
---
## Struktur: Real Estate CRUD-Interface
Da das Feature **stateless** arbeitet, benötigen wir nur **ein Interface** für CRUD-Operationen auf Real Estate-Entitäten:
### Real Estate-Datenmodelle → Real Estate CRUD-Interface
**Datamodel:** `datamodelRealEstate.py`
- `Projekt`
- `Parzelle`
- `Dokument`
- `Kanton`, `Gemeinde`, `Land`
- `GeoPolylinie`, `GeoPunkt`
- `Kontext`
- etc.
**Interface:** `interfaceDbRealEstateObjects.py`
- `RealEstateObjects` (Haupt-Interface)
- `RealEstateAccess` (Zugriffskontrolle)
- Methoden: `createProjekt()`, `getParzelle()`, `updateDokument()`, etc.
**Hinweis:** Das Haupt-Interface enthält auch `executeQuery()` für direkte SQL-Queries (stateless)
---
## Warum nur ein Haupt-Interface?
1. **Stateless Design**:
- Keine Session-Verwaltung notwendig
- Direkte CRUD-Operationen auf Real Estate-Modellen
2. **Einfache Architektur**:
- Ein Interface für alle CRUD-Operationen
- Weniger Komplexität, bessere Wartbarkeit
3. **Query-Funktionalität**:
- `executeQuery()` ist direkt im Haupt-Interface verfügbar
- Für direkte SQL-Queries (stateless)
- Keine Session-Management-Funktionen
---
## Zu erstellende Dateien
### Schritt 2a: Real Estate CRUD-Interface (ERFORDERLICH)
**Zwei separate Dateien** (wie bei anderen Features):
#### Datei 1: `modules/interfaces/interfaceDbRealEstateAccess.py`
**Enthält:**
- `RealEstateAccess` - Zugriffskontrolle für Real Estate-Entitäten
- Methoden: `uam()`, `canModify()`
**Zweck:** Prüft Zugriffsrechte und filtert Daten basierend auf Benutzerprivilegien
#### Datei 2: `modules/interfaces/interfaceDbRealEstateObjects.py`
**Enthält:**
- `RealEstateObjects` - Haupt-Interface für CRUD-Operationen
- `getInterface()` - Factory-Funktion
- Nutzt `RealEstateAccess` aus der Access-Datei
**Zweck:** Verwaltet Real Estate-Entitäten (Projekt, Parzelle, Dokument, etc.)
**Nutzt:**
- `datamodelRealEstate.py` (Projekt, Parzelle, Dokument, etc.)
- `interfaceDbRealEstateAccess.py` (für Zugriffskontrolle)
**Wann benötigt:** Für alle CRUD-Operationen auf Real Estate-Entitäten (z.B. Projekte erstellen/bearbeiten, Parzellen verwalten). Dies ist das Haupt-Interface für das Feature.
---
## Übersicht: Dateien und ihre Beziehungen
```
┌─────────────────────────────────────────────────────────────┐
│ DATAMODELS (Struktur) │
├─────────────────────────────────────────────────────────────┤
│ datamodelRealEstate.py │
│ ├── Projekt │
│ ├── Parzelle │
│ ├── Dokument │
│ ├── Kanton, Gemeinde, Land │
│ ├── GeoPolylinie, GeoPunkt │
│ ├── Kontext │
│ └── ... │
└─────────────────────────────────────────────────────────────┘
│ nutzt
┌─────────────────────────────────────────────────────────────┐
│ INTERFACES (Zugriff) │
├─────────────────────────────────────────────────────────────┤
│ REAL ESTATE CRUD-INTERFACE (ERFORDERLICH) │
│ │
│ interfaceDbRealEstateAccess.py │
│ └── RealEstateAccess │
│ ├── uam() │
│ └── canModify() │
│ │
│ interfaceDbRealEstateObjects.py │
│ ├── RealEstateObjects │
│ │ ├── createProjekt() │
│ │ ├── getProjekt() │
│ │ ├── updateProjekt() │
│ │ ├── deleteProjekt() │
│ │ ├── createParzelle() │
│ │ ├── getParzelle() │
│ │ └── ... (CRUD für alle Entitäten) │
│ └── getInterface() │
│ └── nutzt RealEstateAccess │
│ │
│ │
│ HINWEIS: executeQuery() ist im Haupt-Interface verfügbar │
│ (kein separates Chat-Interface notwendig) │
└─────────────────────────────────────────────────────────────┘
```
---
## Interface-Struktur: Access vs. Objects
Jedes Interface besteht aus **zwei Klassen**:
### 1. `*Access` Klasse (Zugriffskontrolle)
**Zweck:** Prüft, wer was sehen/dürfen darf
**Methoden:**
- `uam()` - Filtert Daten basierend auf Benutzerprivilegien
- `canModify()` - Prüft, ob Benutzer ändern darf
**Beispiel:** `RealEstateAccess`
### 2. `*Objects` Klasse (Haupt-Interface)
**Zweck:** Führt CRUD-Operationen aus
**Methoden:**
- `create*()` - Erstellt neue Einträge
- `get*()` - Lädt einzelne Einträge nach ID
- `get*()` (Plural) - Lädt Listen von Einträgen mit optionalen Filtern
- `update*()` - Aktualisiert Einträge
- `delete*()` - Löscht Einträge
- `executeQuery()` - Führt direkte SQL-Queries aus (stateless)
**Nutzt:** `*Access` für Zugriffskontrolle
**Beispiel:** `RealEstateObjects`
**Warum getrennt?**
- Separation of Concerns: Zugriffskontrolle ist separate Verantwortlichkeit
- Wiederverwendbarkeit: Access-Klasse kann von mehreren Interfaces genutzt werden
- Testbarkeit: Zugriffskontrolle kann unabhängig getestet werden
---
## Implementierung: Real Estate CRUD-Interface
Das Real Estate CRUD-Interface besteht aus **zwei separaten Dateien**, genau wie bei anderen Features (`interfaceDbAppObjects.py` + `interfaceDbAppAccess.py`).
### Datei 1: Access-Implementierung
**Datei:** `modules/interfaces/interfaceDbRealEstateAccess.py`
**Enthält:**
- `RealEstateAccess` Klasse
- Methoden: `uam()`, `canModify()`
**Funktionalität:**
- **`uam()`**: Filtert Datensätze basierend auf Benutzerprivilegien (SYSADMIN sieht alles, ADMIN sieht Mandat, User sieht nur eigene)
- **`canModify()`**: Prüft, ob Benutzer Datensätze ändern/löschen darf
- Fügt Zugriffskontroll-Attribute hinzu: `_hideView`, `_hideEdit`, `_hideDelete`
---
### Datei 2: Objects-Implementierung
**Datei:** `modules/interfaces/interfaceDbRealEstateObjects.py`
**Enthält:**
- `RealEstateObjects` Klasse (Haupt-Interface)
- `getInterface()` Factory-Funktion (Singleton-Pattern)
**Datenbank-Konfiguration:**
- Verwendet `DB_REALESTATE_*` Umgebungsvariablen (nicht `DB_APP_*`)
- Variablen: `DB_REALESTATE_HOST`, `DB_REALESTATE_DATABASE`, `DB_REALESTATE_USER`, `DB_REALESTATE_PASSWORD_SECRET`, `DB_REALESTATE_PORT`
**CRUD-Methoden für alle Entitäten:**
- **Projekt**: `createProjekt()`, `getProjekt()`, `getProjekte()`, `updateProjekt()`, `deleteProjekt()`
- **Parzelle**: `createParzelle()`, `getParzelle()`, `getParzellen()`, `updateParzelle()`, `deleteParzelle()`
- **Dokument**: `createDokument()`, `getDokument()`, `getDokumente()`, `updateDokument()`, `deleteDokument()`
- **Gemeinde**: `createGemeinde()`, `getGemeinde()`, `getGemeinden()`, `updateGemeinde()`, `deleteGemeinde()`
- **Kanton**: `createKanton()`, `getKanton()`, `getKantone()`, `updateKanton()`, `deleteKanton()`
- **Land**: `createLand()`, `getLand()`, `getLaender()`, `updateLand()`, `deleteLand()`
**Zusätzliche Funktionalität:**
- **List-Methoden**: Alle Entitäten haben `get*()` (Plural) Methoden für Listen mit optionalen Filtern
- **Location-Resolution**: `getParzellen()` löst automatisch Gemeinde-Namen zu IDs auf
- **Query-Ausführung**: `executeQuery()` für direkte SQL-Queries (stateless)
- **Supporting Tables**: Automatische Erstellung von Land, Kanton, Gemeinde, Dokument Tabellen bei Initialisierung
## Wichtige Punkte:
1. **DatabaseConnector**: Nutzt `connectorDbPostgre.DatabaseConnector` für Datenbankzugriff
2. **Access Control**: `RealEstateAccess` implementiert Benutzer- und Mandaten-Filterung
3. **Singleton Pattern**: `getInterface()` erstellt pro User eine Instanz
4. **CRUD-Operationen**: `recordCreate`, `recordModify`, `recordDelete`, `getRecordset` vom Connector
5. **MandateId**: Wird automatisch gesetzt, wenn nicht vorhanden
6. **List-Methoden**: Alle Entitäten haben `get*()` (Plural) Methoden für Listen mit optionalen Filtern
7. **Location-Resolution**: Parzelle-Filter können Gemeinde-Namen enthalten, die automatisch zu IDs aufgelöst werden
8. **Query-Ausführung**: `executeQuery()` ist direkt im Haupt-Interface verfügbar (kein separates Chat-Interface notwendig)
9. **Datenbank-Initialisierung**: Unterstützende Tabellen (Land, Kanton, Gemeinde, Dokument) werden automatisch erstellt
---
## Query-Ausführung: executeQuery()
Das Haupt-Interface `RealEstateObjects` enthält die Methode `executeQuery()` für direkte SQL-Queries. **Kein separates Chat-Interface ist notwendig.**
### Verwendung
**Für CRUD-Operationen (EMPFOHLEN):**
- Verwenden Sie die strukturierten CRUD-Methoden (`createProjekt()`, `getProjekte()`, etc.)
- Vorteile: Validierung, Zugriffskontrolle, Typsicherheit, keine SQL-Injection-Risiken
**Für komplexe SELECT-Queries (OPTIONAL):**
- Verwenden Sie `executeQuery()` direkt im Haupt-Interface
- **Warnung**: Nur für SELECT-Queries, immer Parameterisierung verwenden, Queries validieren
### Hinweise zur Query-Ausführung
1. **Stateless**: Keine Session-Management-Funktionen
2. **Nur für Queries**: Primär für SELECT-Queries gedacht
3. **Sicherheit**: Immer Parameterisierung verwenden
4. **Validierung**: Queries sollten validiert werden (z.B. nur SELECT erlauben)
---
## Zusammenfassung: Benötigte Dateien
### Erforderlich (für CRUD-Operationen):
1. ✅ `modules/datamodels/datamodelRealEstate.py`
- Real Estate-Datenmodelle (Projekt, Parzelle, Dokument, etc.)
2. ✅ `modules/interfaces/interfaceDbRealEstateAccess.py`
- Zugriffskontrolle für Real Estate-Entitäten (RealEstateAccess)
3. ✅ `modules/interfaces/interfaceDbRealEstateObjects.py`
- Real Estate CRUD-Interface (RealEstateObjects)
- Nutzt `interfaceDbRealEstateAccess.py`
- Haupt-Interface für alle CRUD-Operationen
### Hinweis zu Query-Ausführung:
4. ✅ `executeQuery()` ist bereits im Haupt-Interface verfügbar
- Kein separates Chat-Interface notwendig
- Direkt in `RealEstateObjects` verfügbar
- Stateless, keine Session-Management
---
[← Zurück: Datenmodell erstellen](02-datamodels.md) | [Weiter: Feature-Logik implementieren →](04-feature-logic.md)

View file

@ -1,236 +0,0 @@
# Schritt 3: Feature-Logik implementieren
[← Zurück: Interface erstellen](03-interfaces.md) | [Weiter: Routen erstellen →](05-routes.md)
**Datei:** `modules/features/realEstate/mainRealEstate.py`
Die Feature-Logik enthält die Geschäftslogik für das Feature. Sie wird von den Routen aufgerufen und arbeitet **stateless** ohne Session-Management.
## Übersicht: Stateless Feature-Logik mit AI-Integration
Die Feature-Logik verwendet **AI**, um natürliche Sprache direkt in CRUD-Operationen zu übersetzen - ohne Session-Management:
```
User Input (natürliche Sprache)
AI-Analyse (Intent-Erkennung)
CRUD-Operation identifizieren
Parameter extrahieren
Interface CRUD-Methode aufrufen
Datenbank-Operation ausführen
Ergebnis zurückgeben (keine Session-Speicherung)
```
**Beispiel:**
- User: "Erstelle ein neues Projekt namens 'Hauptstrasse 42'"
- AI analysiert → Intent: CREATE, Entity: Projekt, Parameter: {label: "Hauptstrasse 42"}
- Feature-Logik ruft auf → Interface-Methode `createProjekt()` mit extrahierten Parametern
- Ergebnis wird direkt zurückgegeben (keine Session, keine History)
## AI-Integration: Services initialisieren
Um AI zu verwenden, müssen Sie die **Services** initialisieren. Services sind eine zentrale Schnittstelle zu verschiedenen Systemkomponenten (AI, Chat, Database, etc.).
### Services-Initialisierung
**Wichtig:**
- Services werden normalerweise im Feature-Logik-Modul initialisiert und an Funktionen weitergegeben
- Für Query-Ausführung wird `getRealEstateInterface()` verwendet, nicht `getChatInterface()`
---
## AI-basierte Intent-Erkennung und CRUD-Operationen
### Schritt 1: Intent-Analyse mit AI
Die AI analysiert User-Input und identifiziert:
- **Intent**: CREATE, READ, UPDATE, DELETE, QUERY
- **Entity**: Projekt, Parzelle, Dokument, etc.
- **Parameter**: Extrahierte Werte aus dem User-Input
### Schritt 2: CRUD-Operation ausführen
Basierend auf der AI-Analyse wird die entsprechende Interface-Methode aufgerufen.
## Wichtige Punkte:
### 1. Services-Initialisierung
- **`getServices(currentUser, workflow=None)`** - Initialisiert Services für AI-Zugriff
- **`services.ai`** - Zugriff auf AI-Service für AI-Aufrufe
### 2. AI-Aufrufe
- **`callAiPlanning()`** - Für strukturierte JSON-Antworten (Intent-Analyse, SQL-Übersetzung)
- **`callAiText()`** - Für einfache Text-Generierung
- **`callAiDocuments()`** - Für Dokumenten-Verarbeitung
### 3. Intent-Analyse
Die AI analysiert User-Input und gibt zurück:
- **Intent**: CREATE, READ, UPDATE, DELETE, QUERY
- **Entity**: Projekt, Parzelle, Dokument, etc.
- **Parameters**: Extrahierte Werte aus dem Input
### 4. CRUD-Operationen
Basierend auf der Intent-Analyse werden folgende Operationen unterstützt:
**Unterstützte Entities:**
- Projekt, Parzelle, Gemeinde, Kanton, Land, Dokument
**CREATE** → `interface.createProjekt()`, `interface.createParzelle()`, `interface.createGemeinde()`, `interface.createKanton()`, `interface.createLand()`, `interface.createDokument()`
**READ** →
- Einzelne Entität: `interface.getProjekt(id)`, `interface.getParzelle(id)`, etc.
- Liste mit Filtern: `interface.getProjekte(recordFilter)`, `interface.getParzellen(recordFilter)`, etc.
- **Wichtig:** READ-Operationen validieren Filter-Felder gegen das Datenmodell
**UPDATE** → `interface.updateProjekt(id, updateData)`, `interface.updateParzelle(id, updateData)`, etc.
**DELETE** → `interface.deleteProjekt(id)`, `interface.deleteParzelle(id)`, etc.
**QUERY** → `interface.executeQuery(queryText, parameters)` für direkte SQL-Ausführung
### 5. Field Validation
- **READ-Operationen** validieren Filter-Felder gegen das Datenmodell
- Ungültige Felder werden ignoriert und geloggt
- **Wichtig:** Location-Queries sollten Parzelle-Entity verwenden, nicht Projekt direkt
### 6. Error Handling
- Umfassendes Error Handling für AI-Aufrufe
- JSON-Parsing mit Fallback (extrahiert JSON aus Markdown-Code-Blöcken)
- Validierung der AI-Response-Struktur
- Logging für Debugging mit `exc_info=True` für vollständige Stack-Traces
- Entity-Validierung: Prüft ob Entity existiert vor Update/Delete
---
## Vollständiger Flow: User-Input → CRUD-Operation (stateless)
### Beispiel: "Erstelle ein neues Projekt namens 'Hauptstrasse 42'"
```
1. User sendet HTTP POST Request
POST /api/realestate/command
Body: {"userInput": "Erstelle ein neues Projekt namens 'Hauptstrasse 42'"}
2. Route ruft Feature-Logik auf
→ processNaturalLanguageCommand() wird aufgerufen
→ Keine Session-ID notwendig!
3. Feature-Logik initialisiert Services
→ Services werden für den aktuellen User initialisiert
→ AI-Service wird aus Services abgerufen
4. AI analysiert User-Input
→ analyzeUserIntent() wird aufgerufen
→ AI gibt zurück: Intent "CREATE", Entity "Projekt", Parameter {"label": "Hauptstrasse 42"}
5. Feature-Logik führt CRUD-Operation aus
→ executeIntentBasedOperation() wird mit Intent und Parametern aufgerufen
→ Real Estate Interface wird initialisiert
→ Projekt-Objekt wird aus Parametern erstellt
→ createProjekt() wird aufgerufen
6. Interface speichert in Datenbank
→ Datenbank-Operation wird über Interface ausgeführt
→ PostgreSQL INSERT wird durchgeführt
7. Ergebnis wird direkt zurückgegeben
→ Route gibt HTTP Response zurück
→ Keine Session-Speicherung, keine History
→ Frontend zeigt Erfolg
```
---
## AI-Service Methoden im Detail
### `callAiPlanning()` - Für strukturierte Antworten
**Verwendung:** Intent-Analyse, SQL-Übersetzung, strukturierte Daten-Extraktion
**Vorteile:**
- Optimiert für strukturierte JSON-Antworten
- Verwendet beste Modelle für Planungs-Aufgaben
- Automatisches Debug-File-Writing
### `callAiText()` - Für einfache Text-Generierung
**Verwendung:** Text-Generierung, Zusammenfassungen, Erklärungen
**Hinweis:** Response ist direkt ein Text-String (kein JSON-Parsing nötig)
### `callAiDocuments()` - Für Dokumenten-Verarbeitung
**Verwendung:** Dokumenten-Analyse, Extraktion, Generierung mit Dokumenten-Kontext
**Hinweis:** Unterstützt optionales `outputFormat` Parameter für strukturierte Ausgaben (z.B. "json")
---
## Best Practices für AI-Integration
### 1. Prompt-Engineering
- **Klare Struktur**: Definieren Sie genau, welche Antwort Sie erwarten
- **Beispiele**: Geben Sie Beispiele für bessere Ergebnisse
- **Format**: Spezifizieren Sie das erwartete Format (JSON, SQL, etc.)
### 2. Error Handling
- **JSON-Parsing**: Immer try/except für JSON-Parsing
- **Fallback**: Planen Sie Fallback-Strategien bei AI-Fehlern
- **Validierung**: Validieren Sie AI-Antworten vor Verwendung
### 3. Sicherheit
- **Query-Validierung**: Validieren Sie SQL-Queries vor Ausführung
- **Parameter-Sanitization**: Sanitizen Sie alle Parameter
- **MandateId-Filter**: Stellen Sie sicher, dass MandateId immer gefiltert wird
### 4. Performance
- **Caching**: Cache häufige AI-Antworten wenn möglich
- **Model-Auswahl**: Lassen Sie das System automatisch das beste Modell wählen
- **Async**: Nutzen Sie async/await für nicht-blockierende Operationen
### 5. Debugging
- **Debug-Files**: Nutzen Sie `debugType` Parameter für Debug-Dateien
- **Logging**: Loggen Sie alle AI-Aufrufe und Antworten
- **Confidence-Scores**: Nutzen Sie Confidence-Scores für Fehlerbehandlung
---
## Erweiterte Features
### Schema-Aware Prompting
Sie können das Datenbank-Schema in Prompts einbinden, um der AI besseren Kontext zu geben. Laden Sie Schema-Informationen dynamisch und fügen Sie diese in den Prompt ein.
### Context-Aware Operations (Optional)
Falls Sie später Kontext zwischen Queries benötigen, können Sie optional eine Session verwenden. Für stateless Operationen ist dies normalerweise nicht notwendig. Falls gewünscht, können Sie vorherige Queries aus einer Session laden und als Kontext in den Prompt einbinden.
### Multi-Step Operations
Für komplexe Operationen können Sie mehrere AI-Calls machen:
1. **Intent-Analyse**: Zuerst den User-Intent analysieren
2. **Parameter-Validierung**: Optional Parameter mit AI validieren
3. **CRUD-Operation**: Die eigentliche Operation ausführen
---
[← Zurück: Interface erstellen](03-interfaces.md) | [Weiter: Routen erstellen →](05-routes.md)

View file

@ -1,225 +0,0 @@
# Schritt 4: Routen erstellen
[← Zurück: Feature-Logik implementieren](04-feature-logic.md) | [Weiter: Router registrieren →](06-router-registration.md)
**Datei:** `modules/routes/routeRealEstate.py`
Die Routen definieren die REST-API-Endpunkte für das Feature. Das Feature arbeitet **stateless** ohne Session-Management.
## Route-Struktur
```
/api/realestate/
├── POST /command → Natürliche Sprache → CRUD-Operation
├── POST /query → Direkte SQL-Query
├── GET /tables → Liste aller verfügbaren Tabellen
├── GET /table/{table} → Daten aus einer Tabelle (mit optionaler Pagination)
└── POST /table/{table} → Neuen Datensatz in einer Tabelle erstellen
```
## Wichtige Punkte:
### 1. Stateless Design
- **Keine Session-Management**: Alle Endpunkte arbeiten stateless
- **Direkte Verarbeitung**: User-Input wird direkt verarbeitet und Ergebnis zurückgegeben
- **Keine History**: Queries werden nicht gespeichert (kann optional später hinzugefügt werden)
### 2. API-Endpunkte
**`POST /api/realestate/command`**
- Verarbeitet natürliche Sprache
- Nutzt AI für Intent-Analyse
- Führt CRUD-Operationen aus
- Gibt Ergebnis direkt zurück
- **CSRF-Token erforderlich** (X-CSRF-Token Header)
**`POST /api/realestate/query`**
- Führt direkte SQL-Queries aus
- Request Body: `{"queryText": "...", "parameters": {...}}`
- Keine Session notwendig
- Gibt Query-Ergebnis direkt zurück
- **CSRF-Token erforderlich** (X-CSRF-Token Header)
**`GET /api/realestate/tables`**
- Gibt Liste aller verfügbaren Tabellen zurück
- Enthält Tabellennamen, Beschreibungen und Model-Namen
- **CSRF-Token erforderlich** (X-CSRF-Token Header)
**`GET /api/realestate/table/{table}`**
- Gibt alle Daten aus einer spezifischen Tabelle zurück
- Unterstützt optionale Pagination über Query-Parameter
- Sortierung und Filterung möglich
- Leere Tabellen geben ein leeres Modell-Instanz zurück (für Schema-Extraktion)
- **CSRF-Token erforderlich** (X-CSRF-Token Header)
**`POST /api/realestate/table/{table}`**
- Erstellt einen neuen Datensatz in einer spezifischen Tabelle
- Request Body enthält die Datensatz-Daten
- mandateId wird automatisch gesetzt falls nicht vorhanden
- **CSRF-Token erforderlich** (X-CSRF-Token Header)
### 3. Sicherheit
- **Rate Limiting**: 120 Requests pro Minute für alle Endpunkte
- **Authentication**: Alle Endpunkte erfordern authentifizierte User
- **CSRF-Token-Validierung**: Alle Endpunkte validieren CSRF-Token im X-CSRF-Token Header
- Token muss hexadezimaler String sein
- Token-Länge: 16-64 Zeichen
- Fehlende oder ungültige Token führen zu 403 Forbidden
- **Query-Validierung**: WICHTIG - Validieren Sie SQL-Queries vor Ausführung
- **MandateId-Filter**: Wird automatisch durch Interfaces angewendet
### 4. Error Handling
- Umfassendes Error Handling mit HTTPException
- Unterschiedliche Status-Codes:
- **400 Bad Request**: Validierungsfehler (z.B. fehlende Parameter, ungültige Daten)
- **403 Forbidden**: CSRF-Token fehlt oder ist ungültig
- **404 Not Found**: Ressource nicht gefunden
- **500 Internal Server Error**: Server-Fehler
- Detaillierte Fehlermeldungen für Debugging
- Logging mit vollständigen Stack-Traces (`exc_info=True`)
### 5. Response-Struktur
**Command-Endpunkt:**
- Erfolgreiche Response enthält: `success`, `intent`, `entity`, `result`
- Result enthält die Operation-Details und das erstellte/aktualisierte/gelesene Objekt
**Query-Endpunkt:**
- Response enthält: `status`, `rows`, `columns`, `rowCount`, `executionTime`
**Tables-Endpunkt:**
- Response enthält: `tables` (Array mit Tabellen-Informationen), `count`
**Table GET-Endpunkt:**
- Response ist eine `PaginatedResponse` mit `items` und `pagination` Metadata
- Ohne Pagination: Alle Items werden zurückgegeben
- Mit Pagination: Enthält `currentPage`, `pageSize`, `totalItems`, `totalPages`, `sort`, `filters`
**Table POST-Endpunkt:**
- Response ist das erstellte Objekt als Dictionary (model_dump())
---
## Flow: Route → Feature-Logik
### Command-Endpunkt Flow
```
POST /api/realestate/command
CSRF-Token-Validierung
routeRealEstate.process_command()
getCurrentUser() # Auth
processNaturalLanguageCommand(currentUser, userInput)
mainRealEstate.processNaturalLanguageCommand()
analyzeUserIntent() → executeIntentBasedOperation()
return Dict mit Ergebnis
```
### Query-Endpunkt Flow
```
POST /api/realestate/query
CSRF-Token-Validierung
routeRealEstate.execute_query()
getCurrentUser() # Auth
Body-Parsing (queryText, parameters)
executeDirectQuery(currentUser, queryText, parameters)
mainRealEstate.executeDirectQuery()
getRealEstateInterface(currentUser)
Interface.executeQuery(queryText, parameters)
return Dict mit rows, columns, rowCount
```
### Table-Endpunkte Flow
**GET /api/realestate/table/{table}:**
```
GET /api/realestate/table/{table}
CSRF-Token-Validierung
getCurrentUser() # Auth
Tabellen-Name validieren
getRealEstateInterface(currentUser)
Interface.getProjekte() / getParzellen() / etc.
Pagination anwenden (falls angegeben)
return PaginatedResponse
```
**POST /api/realestate/table/{table}:**
```
POST /api/realestate/table/{table}
CSRF-Token-Validierung
getCurrentUser() # Auth
Tabellen-Name validieren
Model-Instanz aus Body-Daten erstellen
getRealEstateInterface(currentUser)
Interface.createProjekt() / createParzelle() / etc.
return erstelltes Objekt
```
---
## Verfügbare Tabellen
Die folgenden Tabellen sind verfügbar:
- **Projekt**: Real estate projects
- **Parzelle**: Plots/parcels
- **Dokument**: Documents
- **Gemeinde**: Municipalities
- **Kanton**: Cantons
- **Land**: Countries
## Pagination
Der `GET /api/realestate/table/{table}` Endpunkt unterstützt Pagination über einen Query-Parameter:
- **Parameter**: `pagination` (JSON-encoded string)
- **Format**: `{"page": 1, "pageSize": 10, "sort": [{"field": "label", "direction": "asc"}], "filters": []}`
- **Ohne Pagination**: Alle Datensätze werden zurückgegeben
## Vorteile des stateless Ansatzes
- **Einfachheit**: Kein Session-Management notwendig
- **Performance**: Weniger Datenbank-Operationen pro Request
- **Skalierbarkeit**: Stateless Requests sind einfacher zu skalieren
- **Flexibilität**: Jeder Request ist unabhängig
- **Schnell**: Direkte Verarbeitung ohne Overhead
---
[← Zurück: Feature-Logik implementieren](04-feature-logic.md) | [Weiter: Router registrieren →](06-router-registration.md)

View file

@ -1,53 +0,0 @@
# Schritt 6: Environment-Konfiguration
[← Zurück: Router registrieren](06-router-registration.md) | [Weiter: Feature Lifecycle →](08-lifecycle.md)
**Datei:** `env_dev.env`
Für das realEstate-Feature benötigen wir keine zusätzlichen Environment-Variablen, da es die bereits vorhandenen PostgreSQL-Konfigurationen nutzt:
```env
# PostgreSQL Storage (bereits vorhanden)
DB_APP_HOST=localhost
DB_APP_DATABASE=poweron_app
DB_APP_USER=poweron_dev
DB_APP_PASSWORD_SECRET = DEV_ENC:...
DB_APP_PORT=5432
```
**Optional**: Falls Sie eine separate Datenbank für Real Estate verwenden möchten, können Sie zusätzliche Variablen hinzufügen:
```env
# Optional: Separate Real Estate Database
DB_REALESTATE_HOST=localhost
DB_REALESTATE_DATABASE=poweron_realestate
DB_REALESTATE_USER=poweron_dev
DB_REALESTATE_PASSWORD_SECRET = DEV_ENC:...
DB_REALESTATE_PORT=5432
```
In diesem Fall müssten Sie die `_initializeDatabase()` Methode im Interface anpassen:
```python
def _initializeDatabase(self):
"""Initialize PostgreSQL database connection."""
try:
# Use Real Estate specific config if available, otherwise fall back to APP config
dbHost = APP_CONFIG.get("DB_REALESTATE_HOST") or APP_CONFIG.get("DB_APP_HOST", "localhost")
dbDatabase = APP_CONFIG.get("DB_REALESTATE_DATABASE") or APP_CONFIG.get("DB_APP_DATABASE", "poweron_app")
dbUser = APP_CONFIG.get("DB_REALESTATE_USER") or APP_CONFIG.get("DB_APP_USER")
dbPassword = APP_CONFIG.get("DB_REALESTATE_PASSWORD_SECRET") or APP_CONFIG.get("DB_APP_PASSWORD_SECRET")
dbPort = int(APP_CONFIG.get("DB_REALESTATE_PORT") or APP_CONFIG.get("DB_APP_PORT", 5432))
# ... rest of initialization ...
```
---
[← Zurück: Router registrieren](06-router-registration.md) | [Weiter: Feature Lifecycle →](08-lifecycle.md)

View file

@ -1,491 +0,0 @@
# Swiss Topo STAC API Integration Guide
This document provides comprehensive conceptual documentation for integrating the Swiss Federal Office of Topography (Swisstopo) STAC (SpatioTemporal Asset Catalog) API into the Real Estate feature. This integration enables two primary user workflows: creating projects with enriched parcel data, and browsing maps to explore parcels and their project associations.
## Table of Contents
1. [Overview](#overview)
2. [Architecture](#architecture)
3. [User Story 1: Create Project and Connect Parcels](#user-story-1-create-project-and-connect-parcels)
4. [User Story 2: Browse Map and Explore Parcels](#user-story-2-browse-map-and-explore-parcels)
5. [API Routes and Endpoints](#api-routes-and-endpoints)
6. [Implementation Components](#implementation-components)
7. [Data Flow Summary](#data-flow-summary)
8. [Error Handling and Security](#error-handling-and-security)
9. [Testing and Configuration](#testing-and-configuration)
10. [Summary](#summary)
---
## Overview
### Purpose
The STAC API integration enables the Real Estate feature to support two distinct user workflows:
**User Story 1**: Create a new project, select parcels on a map, automatically enrich them with geospatial data, and store everything in the database for project management.
**User Story 2**: Browse a map, click on parcels to fetch their data from STAC, and see whether each parcel is already connected to an existing project or available for new projects.
### STAC API Overview
The Swiss Federal Office of Topography provides a STAC-compliant API that follows open standards for describing geospatial data. The API provides:
- **Collections**: Groups of related geospatial data (e.g., cadastral parcels, zoning maps)
- **Items**: Individual geospatial features (e.g., a specific parcel, a zoning polygon)
- **Assets**: Downloadable files associated with items (e.g., GeoPackage files, PDFs)
### Key STAC Collections for Real Estate
| Collection ID | Description | Use Case |
|--------------|-------------|----------|
| `ch.swisstopo.amtliche-vermessung` | Official cadastral survey | Identify parcel boundaries |
| `ch.swisstopo.swissboundaries3d-gemeinde-flaeche` | Municipality boundaries | Resolve Gemeinde from coordinates |
| `ch.swisstopo.swissboundaries3d-kanton-flaeche` | Canton boundaries | Resolve Kanton from coordinates |
| `ch.are.nutzungsplanung` | Land use planning (zoning) | Extract bauzone, baulinie |
| `ch.bafu.laermbelastung` | Noise pollution zones | Set laermschutzzone |
| `ch.bafu.hochwassergefahrenkarte` | Flood hazard map | Set hochwasserschutzzone |
| `ch.bafu.grundwasserschutz` | Groundwater protection zones | Set grundwasserschutzzone |
---
## Architecture
The integration follows the existing Gateway architecture pattern with clear separation of concerns:
**Frontend Layer**: User interaction components including map widgets, project forms, and parcel exploration views that communicate with the backend via HTTP/REST.
**API Routes Layer**: HTTP endpoint definitions that handle request validation, authentication, and response formatting. New domain-focused endpoints will replace generic table-based routes.
**Feature Logic Layer**: Business rules and orchestration logic that coordinates STAC queries, data transformation, and enrichment processes. This layer contains the core intelligence for processing location selections, fetching parcel data, and checking parcel-project associations.
**Service Layer**: Specialized services including AI-powered document extraction and text processing capabilities that can analyze zoning regulations from PDF documents.
**Interface Layer**: Normalized data access layer providing CRUD operations on Real Estate entities (Projekt, Parzelle, Gemeinde, etc.) with proper access control and mandate filtering.
**Connector Layer**: External API communication layer that handles STAC API interactions, including query construction, response parsing, error handling, and retry logic.
**Data Storage**: PostgreSQL database for persistent storage of project data, and the Swiss Topo STAC API as the external geospatial data source.
---
## User Story 1: Create Project and Connect Parcels
**User Goal**: Create a new construction project, select parcels on a map, automatically enrich them with geospatial data, and store everything in the database for project management.
### Workflow Steps
1. **Create New Project**: User provides project name and mandate identifier. Backend creates Projekt object with initial status "Analyse" and empty collections. ✅ Already implemented
2. **Select Location on Map**: User clicks on map at location of interest. Frontend sends coordinates (LV95/EPSG:2056) to backend. ❌ New endpoint needed
3. **Identify Parcel from STAC**: Backend queries STAC cadastral collection for parcels intersecting the clicked point. Returns parcel geometry, identifier, properties, and assets. ❌ New functionality needed
4. **Create Parzelle and Connect**: Backend converts STAC geometry to internal GeoPolylinie format, creates Parzelle object, and attaches it to Projekt. Parcel becomes part of project data model for enrichment, annotation, and offline access. ❌ New functionality needed
5. **Enrich Administrative Context**: Backend searches STAC for Gemeinde and Kanton boundaries, creates/updates entities, and establishes hierarchy: Parzelle → Gemeinde → Kanton → Land. ❌ New functionality needed
6. **Extract Zoning Information**: Backend searches zoning collection, calculates intersection areas, selects dominant zone by largest overlap, and extracts bauzone and baulinie. ❌ New functionality needed
7. **Identify Protection Zones**: Backend searches noise, flood, and groundwater collections, finds zones with largest overlap, and extracts zone designations (laermschutzzone, hochwasserschutzzone, grundwasserschutzzone). ❌ New functionality needed
8. **Link Source Documents**: Backend extracts assets from STAC items (GeoPackages, PDFs), creates Dokument objects with metadata, and links them to Parzelle for audit trail. ❌ New functionality needed
9. **AI Extraction (Optional)**: Backend filters PDF documents, calls AI service to extract building parameters (AZ, BZ, vollgeschossZahl, gebaeudehoeheMax, regulations), and updates Parzelle with extracted values. ⚠️ Partial - AI service exists, extraction method needs implementation
10. **Save to Database**: All entities (Projekt, Parzelle, Gemeinde, Kanton, Land, Dokument) are saved to PostgreSQL. Frontend receives enriched Parzelle with enrichment status. ❌ New functionality needed
11. **User Continues Planning**: Users can edit project status, add more parcels, upload documents, add notes, override AI values, and update parcel properties. ⚠️ Partial - Update endpoints exist but may need enhancement
---
## User Story 2: Browse Map and Explore Parcels
**User Goal**: Browse a map, click on parcels to fetch their data from STAC, and see whether each parcel is already connected to an existing project or available for new projects.
### Workflow Steps
1. **Open Map Browser**: User navigates to map browsing interface displaying Switzerland map. ❌ New interface needed
2. **Click on Map**: User clicks at any location. Frontend sends GET request with coordinates and optional mandate ID. ❌ New endpoint needed
3. **Query STAC for Parcel**: Backend queries STAC cadastral collection for parcels at coordinates. Returns parcel data if found. ❌ New functionality needed
4. **Check Project Associations**: Backend searches database for Parzelle records matching STAC parcel identifier, retrieves associated Projekte, filters by mandate if provided, and determines status: Connected (list projects) or Available (not connected). ❌ New functionality needed
5. **Fetch Basic Context (Optional)**: Backend performs lightweight enrichment: administrative boundaries (Gemeinde, Kanton), basic zoning, and protection zones. Uses caching for performance. ❌ New functionality needed
6. **Display Parcel Information**: Frontend shows parcel details, geometry on map, project association status with action buttons (View Project or Create New Project), protection zones, and STAC source indication. ❌ New interface needed
7. **Explore Multiple Parcels**: User can continue clicking to explore multiple parcels. Map shows multiple parcels with color-coded association status. ❌ New functionality needed
8. **Connect Parcel to Project (Optional)**: If parcel is available, user can create new project or add to existing project. System validates permissions, fetches full parcel data, creates Parzelle, triggers full enrichment (User Story 1 Steps 5-9), and saves to database. ❌ New functionality needed
### Key Differences from User Story 1
**User Story 2** focuses on **exploration and discovery**:
- No project creation required upfront
- Lightweight data fetching (can be cached)
- Read-only exploration mode
- Project association checking
- Optional connection to projects
**User Story 1** focuses on **project creation and data persistence**:
- Project must exist first
- Full data enrichment and storage
- All data saved to database
- Complete administrative, zoning, and protection zone context
- AI extraction of building rules
---
## API Routes and Endpoints
### Route Migration Overview
With STAC API integration, the route structure is refactored from generic table-based endpoints to domain-focused endpoints that better align with user workflows and business logic.
### Routes to Deprecate
**POST /api/realestate/query**: Direct SQL queries are a security risk. Use `/command` endpoint for natural language queries or specific GET endpoints for structured data retrieval. ⚠️ Deprecate
**POST /api/realestate/table/{table}**: Generic table creation doesn't reflect domain model. Replace with dedicated project and parcel endpoints. ⚠️ Deprecate
### Routes to Keep
**POST /api/realestate/command**: Keep for natural language commands. May need AI prompt updates for STAC workflows. ✅ Keep
**GET /api/realestate/tables**: Keep for frontend schema discovery. ✅ Keep
**GET /api/realestate/table/{table}**: Keep for admin/debugging. Consider adding domain-specific alternatives. ✅ Keep
### New Domain-Focused Routes
#### Project Management
- **POST /api/realestate/projects**: Create new project (replaces `POST /api/realestate/table/Projekt`)
- **GET /api/realestate/projects**: List projects with filtering and pagination
- **GET /api/realestate/projects/{projekt_id}**: Get single project with full details
- **PATCH /api/realestate/projects/{projekt_id}**: Update project properties
- **DELETE /api/realestate/projects/{projekt_id}**: Delete project with access control
#### Parcel Management (User Story 1)
- **POST /api/realestate/projects/{projekt_id}/locations**: Select location and create Parzelle with full enrichment
- **GET /api/realestate/projects/{projekt_id}/parcels**: List all parcels for a project
- **GET /api/realestate/projects/{projekt_id}/parcels/{parzelle_id}**: Get single parcel with full details
- **PATCH /api/realestate/projects/{projekt_id}/parcels/{parzelle_id}**: Update parcel properties
- **DELETE /api/realestate/projects/{projekt_id}/parcels/{parzelle_id}**: Remove parcel from project
- **POST /api/realestate/projects/{projekt_id}/parcels/{parzelle_id}/refresh-context**: Re-enrich parcel with updated STAC data
#### Map Browsing (User Story 2)
- **GET /api/realestate/parcels/explore**: Browse map and fetch parcel data from STAC with project association check
- **POST /api/realestate/projects/{projekt_id}/parcels/connect**: Connect explored parcel to project (triggers full enrichment)
### Migration Strategy
1. **Phase 1**: Add new domain-focused endpoints alongside existing routes
2. **Phase 2**: Update frontend to use new endpoints
3. **Phase 3**: Mark old endpoints as deprecated with warnings
4. **Phase 4**: Remove deprecated endpoints after migration period
---
## Implementation Components
### STAC Connector
**Purpose**: Encapsulate all STAC API interactions following Gateway connector pattern.
**Key Methods**:
- Search parcels by point (cadastral collection)
- Search administrative boundaries (Gemeinde, Kanton)
- Search zoning (land use planning)
- Search protection zones (noise, flood, groundwater)
- Get item assets (downloadable files)
**Features**: Retry logic with exponential backoff, coordinate system transformations, error handling, response transformation to internal data structures.
**Caching Strategy**: Cache administrative boundaries (rarely change), cache map browsing lookups (short TTL), don't cache project creation searches (user-specific), cache collection metadata.
### Feature Logic Extensions
**For User Story 1**:
- Process location selection and create Parzelle
- Enrich parcel with STAC data (orchestrates full enrichment)
- Extract zoning by calculating intersection areas
- Extract protection zones by overlap calculation
- Geometry conversion helpers (STAC GeoJSON ↔ internal GeoPolylinie)
**For User Story 2**:
- Fetch parcel data from STAC (lightweight)
- Check parcel-project associations (database queries)
- Get basic parcel context (quick administrative/zoning lookup)
- Connect parcel to project (transition to User Story 1)
### AI Service Extension
**Purpose**: Extract building rules from zoning PDF documents.
**Process**: Download PDFs, extract text (OCR if needed), use LLM with structured schema to extract AZ, BZ, vollgeschossZahl, gebaeudehoeheMax, and regulation descriptions.
**Status**: ⚠️ Partial - AI service exists, but zoning rule extraction method needs implementation
---
## Data Flow Summary
### User Story 1: Location Selection Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Route
participant FeatureLogic
participant STACConnector
participant STACAPI
participant Database
participant AIService
User->>Frontend: Click on map
Frontend->>Route: POST /projects/{id}/locations<br/>(coordinates, project_id)
Route->>Route: Validate CSRF token<br/>Validate coordinates<br/>Check project access
Route->>FeatureLogic: processLocationSelection()
FeatureLogic->>STACConnector: search_parcels_by_point(x, y)
STACConnector->>STACAPI: Query cadastral collection<br/>(point geometry)
STACAPI-->>STACConnector: Parcel items (geometry, properties, assets)
STACConnector-->>FeatureLogic: Parcel data
FeatureLogic->>FeatureLogic: Convert STAC geometry<br/>to GeoPolylinie
FeatureLogic->>FeatureLogic: Create Parzelle object
FeatureLogic->>Database: Attach Parzelle to Projekt
FeatureLogic->>FeatureLogic: Trigger enrichment
FeatureLogic->>STACConnector: search_administrative_boundaries()
STACConnector->>STACAPI: Query Gemeinde/Kanton collections
STACAPI-->>STACConnector: Boundary data
STACConnector-->>FeatureLogic: Administrative boundaries
FeatureLogic->>Database: Create/update Gemeinde, Kanton, Land
FeatureLogic->>STACConnector: search_zoning()
STACConnector->>STACAPI: Query zoning collection
STACAPI-->>STACConnector: Zoning polygons
STACConnector-->>FeatureLogic: Zoning data
FeatureLogic->>FeatureLogic: Calculate intersection areas<br/>Select dominant zone
FeatureLogic->>FeatureLogic: Extract bauzone, baulinie
FeatureLogic->>STACConnector: search_protection_zones()
STACConnector->>STACAPI: Query noise/flood/groundwater collections
STACAPI-->>STACConnector: Protection zone data
STACConnector-->>FeatureLogic: Protection zones
FeatureLogic->>FeatureLogic: Extract zone designations
FeatureLogic->>FeatureLogic: Extract assets from STAC items
FeatureLogic->>Database: Create Dokument objects
opt AI Extraction Enabled
FeatureLogic->>FeatureLogic: Filter PDF documents
FeatureLogic->>AIService: extractZoningRules(documents, bauzone)
AIService->>AIService: Download PDFs<br/>Extract text (OCR if needed)
AIService->>AIService: LLM analysis with structured schema
AIService-->>FeatureLogic: Extracted values (AZ, BZ, etc.)
FeatureLogic->>FeatureLogic: Update Parzelle with AI results
FeatureLogic->>Database: Add Kontext entry
end
FeatureLogic->>Database: Save all entities<br/>(Projekt, Parzelle, Gemeinde, etc.)
FeatureLogic-->>Route: Enriched Parzelle + status
Route-->>Frontend: Response with enriched Parzelle
Frontend->>User: Display enriched parcel data
```
### User Story 2: Map Browse Flow
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Route
participant FeatureLogic
participant STACConnector
participant STACAPI
participant Database
User->>Frontend: Click on map (browse mode)
Frontend->>Route: GET /parcels/explore<br/>(coordinates, mandate_id?)
Route->>Route: Validate coordinates<br/>Validate authentication
Route->>FeatureLogic: fetchParcelData()
FeatureLogic->>STACConnector: search_parcels_by_point(x, y)
STACConnector->>STACAPI: Query cadastral collection<br/>(point geometry)
STACAPI-->>STACConnector: Parcel items (geometry, properties)
STACConnector-->>FeatureLogic: Parcel data
FeatureLogic->>Database: Check parcel-project associations<br/>(search Parzelle by STAC identifier)
Database-->>FeatureLogic: Matching Parzelle records<br/>with Projekt IDs
alt Parcels Found in Database
FeatureLogic->>Database: Get Projekt details
Database-->>FeatureLogic: Projekt information
FeatureLogic->>FeatureLogic: Status: Connected<br/>(list projects)
else No Parcels Found
FeatureLogic->>FeatureLogic: Status: Available
end
opt Basic Context Requested
FeatureLogic->>STACConnector: search_administrative_boundaries()<br/>search_zoning()<br/>search_protection_zones()
STACConnector->>STACAPI: Query collections (cached if possible)
STACAPI-->>STACConnector: Context data
STACConnector-->>FeatureLogic: Basic context
end
FeatureLogic-->>Route: Parcel data + association status + context
Route-->>Frontend: Response with parcel info
Frontend->>User: Display parcel details<br/>Show project association status<br/>Show action buttons
opt User Chooses to Connect
User->>Frontend: Click "Create Project" or "Add to Project"
Frontend->>Route: POST /projects/{id}/parcels/connect<br/>(parcel_id, project_id)
Route->>FeatureLogic: connectParcelToProject()
Note over FeatureLogic: Triggers User Story 1<br/>enrichment process
FeatureLogic->>Database: Create Parzelle + enrichment
FeatureLogic-->>Route: Created Parzelle
Route-->>Frontend: Success response
end
```
### AI Extraction Flow (User Story 1)
```mermaid
sequenceDiagram
participant FeatureLogic
participant Parzelle
participant AIService
participant PDFSource
participant LLM
participant Database
Note over FeatureLogic: After STAC enrichment completes
FeatureLogic->>Parzelle: Get dokumente collection
Parzelle-->>FeatureLogic: List of Dokument objects
FeatureLogic->>FeatureLogic: Filter documents:<br/>- mimeType == "application/pdf"<br/>- dokumentTyp in [BZO, Bauverordnung]
FeatureLogic->>AIService: extractZoningRules(<br/>parzelleId,<br/>documents[],<br/>bauzone)
loop For each PDF document
AIService->>PDFSource: Download PDF from dokumentReferenz
PDFSource-->>AIService: PDF file
AIService->>AIService: Extract text content<br/>(OCR if scanned PDF)
AIService->>AIService: Preprocess text
end
AIService->>LLM: Analyze text with structured schema<br/>(prompt: extract building parameters)
LLM->>LLM: Parse zoning regulations
LLM-->>AIService: Structured extraction:<br/>- az (float)<br/>- bz (float)<br/>- vollgeschossZahl (int)<br/>- gebaeudehoeheMax (float)<br/>- regelnGrenzabstand (array)<br/>- regelnMehrlaengenzuschlag (array)<br/>- regelnMehrhoehenzuschlag (array)
AIService-->>FeatureLogic: Extraction results
FeatureLogic->>FeatureLogic: Parse and validate results
FeatureLogic->>Parzelle: Update fields:<br/>parzelle.az = result.az<br/>parzelle.bz = result.bz<br/>parzelle.vollgeschossZahl = result.vollgeschossZahl<br/>parzelle.gebaeudehoeheMax = result.gebaeudehoeheMax<br/>parzelle.regelnGrenzabstand = result.regelnGrenzabstand<br/>parzelle.regelnMehrlaengenzuschlag = result.regelnMehrlaengenzuschlag<br/>parzelle.regelnMehrhoehenzuschlag = result.regelnMehrhoehenzuschlag
FeatureLogic->>Database: Create Kontext entry:<br/>thema: "Automatisch extrahierte Baukennzahlen"<br/>inhalt: "AZ/BZ etc. wurden aus BZO [Gemeinde] Stand [Date] extrahiert."
FeatureLogic->>Database: Save updated Parzelle
Database-->>FeatureLogic: Confirmation
FeatureLogic-->>FeatureLogic: Return enrichment results<br/>including AI extraction status
```
---
## Error Handling and Security
### Error Handling
**STAC API Errors**: Retry with exponential backoff (3 attempts), validate coordinates (Switzerland bounds), handle no results found (404 for Story 1, informative response for Story 2), continue with available collections if some fail.
**Database Errors**: Transaction management with rollback, validate relationships before saving, handle parcel already connected scenarios.
**AI Extraction Errors**: Skip failed documents, return partial results, don't fail entire enrichment process.
### Security
**CSRF Protection**: All POST/PATCH endpoints require CSRF tokens. GET endpoints validate authentication.
**Input Validation**: Validate coordinate ranges (Switzerland bounds), whitelist coordinate systems (EPSG:2056, EPSG:4326), validate UUID formats.
**Rate Limiting**: 60 requests/minute for location selection, 120 requests/minute for map browsing, 30 requests/minute for context refresh.
**Data Privacy**: STAC queries are read-only, parcel data stored per mandate with access control, mandate filtering for project associations.
**Access Control**: Users must have permission to create/modify projects, project association information filtered by mandate access, parcel connection requires project modification permissions.
---
## Testing and Configuration
### Testing Approach
**Unit Tests**: STAC connector methods with mock responses, feature logic with mocked connector, project association checking with various database states.
**Integration Tests**: End-to-end flows for both user stories, enrichment pipeline, project association scenarios (not connected, one project, multiple projects, different mandates).
**Mock STAC Responses**: Create realistic mock responses for development and testing without external API dependency.
### Configuration Requirements
**Environment Variables**: STAC base URL, timeout settings, retry configuration, caching settings (different for User Story 1 vs User Story 2), map browse cache TTL.
**Configuration Files**: API endpoint URLs, timeout and retry parameters, caching behavior, collection identifiers.
### Dependencies
**Python Packages**: STAC API client, geospatial operations library, GeoJSON support library.
**System Requirements**: Python 3.10+, internet connection for STAC API, PostgreSQL database, optional PostGIS extension.
**External Services**: Swiss Topo STAC API (public, no authentication), AI service infrastructure (existing).
---
## Summary
This integration guide provides a comprehensive conceptual blueprint for integrating the Swiss Topo STAC API into the Real Estate feature. The implementation enables two distinct user workflows:
**User Story 1: Create Project and Connect Parcels**
- Create new projects and select parcels on a map
- Automatic enrichment with administrative, zoning, and protection zone data
- Full data persistence in database
- AI-powered extraction of building rules from documents
- Complete project management workflow
**User Story 2: Browse Map and Explore Parcels**
- Explore parcels on a map without project creation
- Lightweight data fetching from STAC
- Check if parcels are connected to existing projects
- Optional connection to projects with full enrichment
The architecture follows the existing Gateway patterns:
- **Connectors** for external API communication
- **Interfaces** for normalized data access
- **Features** for business logic
- **Routes** for API endpoints
Both user stories share the STAC connector and enrichment logic, but serve different purposes: User Story 1 focuses on project creation and data persistence, while User Story 2 focuses on exploration and discovery before committing to project creation.
The route structure is refactored from generic table-based endpoints to domain-focused endpoints that better align with user workflows, with a phased migration strategy to ensure backward compatibility.
---
**Document Version**: 2.1
**Last Updated**: 2025-01-28
**Author**: Gateway Development Team

View file

@ -1,47 +0,0 @@
# Feature Integration Guide: realEstate
Diese Dokumentation erklärt Schritt für Schritt, wie Sie ein neues Feature "realEstate" in das Gateway-Projekt integrieren. Das Feature ermöglicht es, über ein Chat-Interface Datenbankabfragen auf Real Estate-Daten (Architektur-Planungs-App) durchzuführen.
**Referenz:** Das zugrundeliegende Datenmodell ist in `../PEK_datamodel_desc.md` beschrieben (PEK ist ein Beispiel für eine Real Estate-Firma, das Modell ist aber allgemein verwendbar).
## Inhaltsverzeichnis
1. [Überblick und Projektstruktur](01-overview.md)
2. [Schritt 1: Datenmodell erstellen](02-datamodels.md)
3. [Schritt 2: Interface erstellen](03-interfaces.md)
4. [Schritt 3: Feature-Logik implementieren](04-feature-logic.md)
5. [Schritt 4: Routen erstellen](05-routes.md)
6. [Schritt 5: Router registrieren](06-router-registration.md)
7. [Schritt 6: Environment-Konfiguration](07-environment.md)
8. [Schritt 7: Feature Lifecycle (optional)](08-lifecycle.md)
9. [Datenbank-Schema und Tabellenerstellung](09-database-schema.md)
10. [Sicherheitshinweise](10-security.md)
11. [Testing](11-testing.md)
12. [Troubleshooting](12-troubleshooting.md)
13. [Zusammenfassung](13-summary.md)
14. [Swiss Topo STAC API Integration](14-stac-api-integration.md)
---
## Schnellstart
Für eine schnelle Übersicht über alle zu erstellenden Dateien, siehe [Zusammenfassung](13-summary.md).
## Architektur-Überblick
Die Architektur folgt dem Muster bestehender Features wie `chatPlayground`:
- **Routes** (`modules/routes/`) - API-Endpunkte
- **Features** (`modules/features/`) - Geschäftslogik
- **Interfaces** (`modules/interfaces/`) - Datenbankzugriff
- **DataModels** (`modules/datamodels/`) - Pydantic-Modelle
---
**Nächster Schritt:** [01-overview.md](01-overview.md)

View file

@ -1,89 +0,0 @@
Analyze the following user command and extract the intent, entity, and parameters.
User Command: "wie viele projekte in zürich gibt es?"
Available intents:
- CREATE: User wants to create a new entity
- READ: User wants to read/query entities
- UPDATE: User wants to update an existing entity
- DELETE: User wants to delete an entity
- QUERY: User wants to execute a database query (SQL statements)
Available entities and their fields:
**Projekt** (Real estate project):
- id: string (primary key)
- mandateId: string (mandate ID)
- label: string (project designation/name)
- statusProzess: string enum (Eingang, Analyse, Studie, Planung, Baurechtsverfahren, Umsetzung, Archiv)
- perimeter: GeoPolylinie (geographic boundary, JSONB)
- baulinie: GeoPolylinie (building line, JSONB)
- parzellen: List[Parzelle] (plots belonging to project, JSONB)
- dokumente: List[Dokument] (documents, JSONB)
- kontextInformationen: List[Kontext] (context info, JSONB)
**Parzelle** (Plot/parcel):
- id: string (primary key)
- mandateId: string (mandate ID)
- label: string (plot designation)
- strasseNr: string (street and house number)
- plz: string (postal code)
- kontextGemeinde: string (municipality ID, Foreign Key to Gemeinde table)
- bauzone: string (building zone, e.g. W3, WG2)
- az: float (Ausnützungsziffer)
- bz: float (Bebauungsziffer)
- vollgeschossZahl: int (number of allowed full floors)
- gebaeudehoeheMax: float (maximum building height in meters)
- laermschutzzone: string (noise protection zone)
- hochwasserschutzzone: string (flood protection zone)
- grundwasserschutzzone: string (groundwater protection zone)
- parzelleBebaut: JaNein enum (is plot built)
- parzelleErschlossen: JaNein enum (is plot developed)
- parzelleHanglage: JaNein enum (is plot on slope)
**Important relationships:**
- Projekte contain Parzellen (projects have plots)
- Parzelle links to Gemeinde (via kontextGemeinde)
- Gemeinde links to Kanton (via id_kanton)
- Kanton links to Land (via id_land)
- Location queries (city, postal code) should use Parzelle.kontextGemeinde (municipality name will be resolved to ID)
- Projekt does NOT have location fields directly - location is stored in associated Parzellen
Return a JSON object with the following structure:
{
"intent": "CREATE|READ|UPDATE|DELETE|QUERY",
"entity": "Projekt|Parzelle|Dokument|Kanton|Gemeinde|null",
"parameters": {
// Extracted parameters from user input
// For CREATE/UPDATE: include all relevant fields using EXACT field names from above
// For READ: include filter criteria using EXACT field names (id, label, plz, kontextGemeinde, etc.)
// For DELETE: include entity ID if mentioned
// For QUERY: include queryText if SQL is detected
// IMPORTANT: Use only field names that exist in the entity definition above
},
"confidence": 0.0-1.0 // Confidence score for the analysis
}
Examples:
- Input: "Erstelle ein neues Projekt namens 'Hauptstrasse 42'"
Output: {"intent": "CREATE", "entity": "Projekt", "parameters": {"label": "Hauptstrasse 42"}, "confidence": 0.95}
- Input: "Zeige mir alle Projekte"
Output: {"intent": "READ", "entity": "Projekt", "parameters": {}, "confidence": 0.9}
- Input: "Zeige mir Projekte in Zürich"
Output: {"intent": "READ", "entity": "Parzelle", "parameters": {"kontextGemeinde": "Zürich"}, "confidence": 0.9}
Note: Location queries should query Parzelle, not Projekt directly
- Input: "Zeige mir Parzellen mit PLZ 8000"
Output: {"intent": "READ", "entity": "Parzelle", "parameters": {"plz": "8000"}, "confidence": 0.95}
- Input: "Aktualisiere Projekt XYZ mit Status 'Planung'"
Output: {"intent": "UPDATE", "entity": "Projekt", "parameters": {"id": "XYZ", "statusProzess": "Planung"}, "confidence": 0.85}
- Input: "SELECT * FROM Projekt WHERE label = 'Test'"
Output: {"intent": "QUERY", "entity": null, "parameters": {"queryText": "SELECT * FROM Projekt WHERE label = 'Test'", "queryType": "sql"}, "confidence": 1.0}
- Input: "Lösche Parzelle ABC"
Output: {"intent": "DELETE", "entity": "Parzelle", "parameters": {"id": "ABC"}, "confidence": 0.9}

View file

@ -1,17 +0,0 @@
```json
{
"intent": "READ",
"entity": "Parzelle",
"parameters": {
"kontextGemeinde": "Zürich"
},
"confidence": 0.9
}
```
**Reasoning:**
- The user is asking "how many projects in Zürich are there?" which is a query/read operation
- Since location information (city/municipality) is stored in `Parzelle` via the `kontextGemeinde` field, not directly in `Projekt`, we need to query `Parzelle` entities
- The parameter `kontextGemeinde` is set to "Zürich" to filter parcels by municipality
- To get projects in Zürich, the system would need to find all Parzellen with kontextGemeinde="Zürich" and then retrieve the associated Projekte
- Confidence is 0.9 because the intent is clear, though the user asks about "projects" while we're querying "Parzelle" (which is the correct approach given the data model)

View file

@ -1,89 +0,0 @@
Analyze the following user command and extract the intent, entity, and parameters.
User Command: "wie viele Projekte in Zürich gibt es?"
Available intents:
- CREATE: User wants to create a new entity
- READ: User wants to read/query entities
- UPDATE: User wants to update an existing entity
- DELETE: User wants to delete an entity
- QUERY: User wants to execute a database query (SQL statements)
Available entities and their fields:
**Projekt** (Real estate project):
- id: string (primary key)
- mandateId: string (mandate ID)
- label: string (project designation/name)
- statusProzess: string enum (Eingang, Analyse, Studie, Planung, Baurechtsverfahren, Umsetzung, Archiv)
- perimeter: GeoPolylinie (geographic boundary, JSONB)
- baulinie: GeoPolylinie (building line, JSONB)
- parzellen: List[Parzelle] (plots belonging to project, JSONB)
- dokumente: List[Dokument] (documents, JSONB)
- kontextInformationen: List[Kontext] (context info, JSONB)
**Parzelle** (Plot/parcel):
- id: string (primary key)
- mandateId: string (mandate ID)
- label: string (plot designation)
- strasseNr: string (street and house number)
- plz: string (postal code)
- kontextGemeinde: string (municipality ID, Foreign Key to Gemeinde table)
- bauzone: string (building zone, e.g. W3, WG2)
- az: float (Ausnützungsziffer)
- bz: float (Bebauungsziffer)
- vollgeschossZahl: int (number of allowed full floors)
- gebaeudehoeheMax: float (maximum building height in meters)
- laermschutzzone: string (noise protection zone)
- hochwasserschutzzone: string (flood protection zone)
- grundwasserschutzzone: string (groundwater protection zone)
- parzelleBebaut: JaNein enum (is plot built)
- parzelleErschlossen: JaNein enum (is plot developed)
- parzelleHanglage: JaNein enum (is plot on slope)
**Important relationships:**
- Projekte contain Parzellen (projects have plots)
- Parzelle links to Gemeinde (via kontextGemeinde)
- Gemeinde links to Kanton (via id_kanton)
- Kanton links to Land (via id_land)
- Location queries (city, postal code) should use Parzelle.kontextGemeinde (municipality name will be resolved to ID)
- Projekt does NOT have location fields directly - location is stored in associated Parzellen
Return a JSON object with the following structure:
{
"intent": "CREATE|READ|UPDATE|DELETE|QUERY",
"entity": "Projekt|Parzelle|Dokument|Kanton|Gemeinde|null",
"parameters": {
// Extracted parameters from user input
// For CREATE/UPDATE: include all relevant fields using EXACT field names from above
// For READ: include filter criteria using EXACT field names (id, label, plz, kontextGemeinde, etc.)
// For DELETE: include entity ID if mentioned
// For QUERY: include queryText if SQL is detected
// IMPORTANT: Use only field names that exist in the entity definition above
},
"confidence": 0.0-1.0 // Confidence score for the analysis
}
Examples:
- Input: "Erstelle ein neues Projekt namens 'Hauptstrasse 42'"
Output: {"intent": "CREATE", "entity": "Projekt", "parameters": {"label": "Hauptstrasse 42"}, "confidence": 0.95}
- Input: "Zeige mir alle Projekte"
Output: {"intent": "READ", "entity": "Projekt", "parameters": {}, "confidence": 0.9}
- Input: "Zeige mir Projekte in Zürich" or "Wie viele Projekte in Zürich"
Output: {"intent": "READ", "entity": "Projekt", "parameters": {"location_filter": "Zürich"}, "confidence": 0.9}
Note: For project location queries, use Projekt entity with location_filter parameter
- Input: "Zeige mir Parzellen mit PLZ 8000"
Output: {"intent": "READ", "entity": "Parzelle", "parameters": {"plz": "8000"}, "confidence": 0.95}
- Input: "Aktualisiere Projekt XYZ mit Status 'Planung'"
Output: {"intent": "UPDATE", "entity": "Projekt", "parameters": {"id": "XYZ", "statusProzess": "Planung"}, "confidence": 0.85}
- Input: "SELECT * FROM Projekt WHERE label = 'Test'"
Output: {"intent": "QUERY", "entity": null, "parameters": {"queryText": "SELECT * FROM Projekt WHERE label = 'Test'", "queryType": "sql"}, "confidence": 1.0}
- Input: "Lösche Parzelle ABC"
Output: {"intent": "DELETE", "entity": "Parzelle", "parameters": {"id": "ABC"}, "confidence": 0.9}

View file

@ -1,17 +0,0 @@
```json
{
"intent": "READ",
"entity": "Projekt",
"parameters": {
"location_filter": "Zürich"
},
"confidence": 0.9
}
```
**Analysis:**
- **Intent**: READ - The user wants to query/count existing projects ("wie viele ... gibt es?" = "how many ... are there?")
- **Entity**: Projekt - The user is asking about "Projekte" (projects)
- **Parameters**:
- `location_filter: "Zürich"` - The user wants to filter projects by location (Zürich). Since Projekt doesn't have direct location fields, this will need to be resolved through the associated Parzellen's kontextGemeinde relationship
- **Confidence**: 0.9 - High confidence as the intent and entity are clear, though the query involves a relationship traversal (Projekt → Parzelle → Gemeinde)

View file

@ -1,89 +0,0 @@
Analyze the following user command and extract the intent, entity, and parameters.
User Command: "Erstelle ein neues Projekt in Zürich"
Available intents:
- CREATE: User wants to create a new entity
- READ: User wants to read/query entities
- UPDATE: User wants to update an existing entity
- DELETE: User wants to delete an entity
- QUERY: User wants to execute a database query (SQL statements)
Available entities and their fields:
**Projekt** (Real estate project):
- id: string (primary key)
- mandateId: string (mandate ID)
- label: string (project designation/name)
- statusProzess: string enum (Eingang, Analyse, Studie, Planung, Baurechtsverfahren, Umsetzung, Archiv)
- perimeter: GeoPolylinie (geographic boundary, JSONB)
- baulinie: GeoPolylinie (building line, JSONB)
- parzellen: List[Parzelle] (plots belonging to project, JSONB)
- dokumente: List[Dokument] (documents, JSONB)
- kontextInformationen: List[Kontext] (context info, JSONB)
**Parzelle** (Plot/parcel):
- id: string (primary key)
- mandateId: string (mandate ID)
- label: string (plot designation)
- strasseNr: string (street and house number)
- plz: string (postal code)
- kontextGemeinde: string (municipality ID, Foreign Key to Gemeinde table)
- bauzone: string (building zone, e.g. W3, WG2)
- az: float (Ausnützungsziffer)
- bz: float (Bebauungsziffer)
- vollgeschossZahl: int (number of allowed full floors)
- gebaeudehoeheMax: float (maximum building height in meters)
- laermschutzzone: string (noise protection zone)
- hochwasserschutzzone: string (flood protection zone)
- grundwasserschutzzone: string (groundwater protection zone)
- parzelleBebaut: JaNein enum (is plot built)
- parzelleErschlossen: JaNein enum (is plot developed)
- parzelleHanglage: JaNein enum (is plot on slope)
**Important relationships:**
- Projekte contain Parzellen (projects have plots)
- Parzelle links to Gemeinde (via kontextGemeinde)
- Gemeinde links to Kanton (via id_kanton)
- Kanton links to Land (via id_land)
- Location queries (city, postal code) should use Parzelle.kontextGemeinde (municipality name will be resolved to ID)
- Projekt does NOT have location fields directly - location is stored in associated Parzellen
Return a JSON object with the following structure:
{
"intent": "CREATE|READ|UPDATE|DELETE|QUERY",
"entity": "Projekt|Parzelle|Dokument|Kanton|Gemeinde|null",
"parameters": {
// Extracted parameters from user input
// For CREATE/UPDATE: include all relevant fields using EXACT field names from above
// For READ: include filter criteria using EXACT field names (id, label, plz, kontextGemeinde, etc.)
// For DELETE: include entity ID if mentioned
// For QUERY: include queryText if SQL is detected
// IMPORTANT: Use only field names that exist in the entity definition above
},
"confidence": 0.0-1.0 // Confidence score for the analysis
}
Examples:
- Input: "Erstelle ein neues Projekt namens 'Hauptstrasse 42'"
Output: {"intent": "CREATE", "entity": "Projekt", "parameters": {"label": "Hauptstrasse 42"}, "confidence": 0.95}
- Input: "Zeige mir alle Projekte"
Output: {"intent": "READ", "entity": "Projekt", "parameters": {}, "confidence": 0.9}
- Input: "Zeige mir Projekte in Zürich" or "Wie viele Projekte in Zürich"
Output: {"intent": "READ", "entity": "Projekt", "parameters": {"location_filter": "Zürich"}, "confidence": 0.9}
Note: For project location queries, use Projekt entity with location_filter parameter
- Input: "Zeige mir Parzellen mit PLZ 8000"
Output: {"intent": "READ", "entity": "Parzelle", "parameters": {"plz": "8000"}, "confidence": 0.95}
- Input: "Aktualisiere Projekt XYZ mit Status 'Planung'"
Output: {"intent": "UPDATE", "entity": "Projekt", "parameters": {"id": "XYZ", "statusProzess": "Planung"}, "confidence": 0.85}
- Input: "SELECT * FROM Projekt WHERE label = 'Test'"
Output: {"intent": "QUERY", "entity": null, "parameters": {"queryText": "SELECT * FROM Projekt WHERE label = 'Test'", "queryType": "sql"}, "confidence": 1.0}
- Input: "Lösche Parzelle ABC"
Output: {"intent": "DELETE", "entity": "Parzelle", "parameters": {"id": "ABC"}, "confidence": 0.9}

View file

@ -1,17 +0,0 @@
```json
{
"intent": "CREATE",
"entity": "Projekt",
"parameters": {
"location_filter": "Zürich"
},
"confidence": 0.85
}
```
**Explanation:**
- **Intent**: CREATE - The user wants to create a new project ("Erstelle ein neues Projekt")
- **Entity**: Projekt - The entity type is clearly specified
- **Parameters**:
- `location_filter`: "Zürich" - The user mentions "in Zürich" as the location. Since Projekt doesn't have direct location fields (location is stored in associated Parzellen), I'm using `location_filter` to indicate the intended location context. This will need to be handled by creating associated Parzellen with the appropriate `kontextGemeinde` value.
- **Confidence**: 0.85 - High confidence in intent and entity, slightly lower because the location reference for a new project is indirect (projects get location through their parcels) and no project name/label was provided.

View file

@ -1,89 +0,0 @@
Analyze the following user command and extract the intent, entity, and parameters.
User Command: "wie viele Projekte in zürich gibt es jetzt?"
Available intents:
- CREATE: User wants to create a new entity
- READ: User wants to read/query entities
- UPDATE: User wants to update an existing entity
- DELETE: User wants to delete an entity
- QUERY: User wants to execute a database query (SQL statements)
Available entities and their fields:
**Projekt** (Real estate project):
- id: string (primary key)
- mandateId: string (mandate ID)
- label: string (project designation/name)
- statusProzess: string enum (Eingang, Analyse, Studie, Planung, Baurechtsverfahren, Umsetzung, Archiv)
- perimeter: GeoPolylinie (geographic boundary, JSONB)
- baulinie: GeoPolylinie (building line, JSONB)
- parzellen: List[Parzelle] (plots belonging to project, JSONB)
- dokumente: List[Dokument] (documents, JSONB)
- kontextInformationen: List[Kontext] (context info, JSONB)
**Parzelle** (Plot/parcel):
- id: string (primary key)
- mandateId: string (mandate ID)
- label: string (plot designation)
- strasseNr: string (street and house number)
- plz: string (postal code)
- kontextGemeinde: string (municipality ID, Foreign Key to Gemeinde table)
- bauzone: string (building zone, e.g. W3, WG2)
- az: float (Ausnützungsziffer)
- bz: float (Bebauungsziffer)
- vollgeschossZahl: int (number of allowed full floors)
- gebaeudehoeheMax: float (maximum building height in meters)
- laermschutzzone: string (noise protection zone)
- hochwasserschutzzone: string (flood protection zone)
- grundwasserschutzzone: string (groundwater protection zone)
- parzelleBebaut: JaNein enum (is plot built)
- parzelleErschlossen: JaNein enum (is plot developed)
- parzelleHanglage: JaNein enum (is plot on slope)
**Important relationships:**
- Projekte contain Parzellen (projects have plots)
- Parzelle links to Gemeinde (via kontextGemeinde)
- Gemeinde links to Kanton (via id_kanton)
- Kanton links to Land (via id_land)
- Location queries (city, postal code) should use Parzelle.kontextGemeinde (municipality name will be resolved to ID)
- Projekt does NOT have location fields directly - location is stored in associated Parzellen
Return a JSON object with the following structure:
{
"intent": "CREATE|READ|UPDATE|DELETE|QUERY",
"entity": "Projekt|Parzelle|Dokument|Kanton|Gemeinde|null",
"parameters": {
// Extracted parameters from user input
// For CREATE/UPDATE: include all relevant fields using EXACT field names from above
// For READ: include filter criteria using EXACT field names (id, label, plz, kontextGemeinde, etc.)
// For DELETE: include entity ID if mentioned
// For QUERY: include queryText if SQL is detected
// IMPORTANT: Use only field names that exist in the entity definition above
},
"confidence": 0.0-1.0 // Confidence score for the analysis
}
Examples:
- Input: "Erstelle ein neues Projekt namens 'Hauptstrasse 42'"
Output: {"intent": "CREATE", "entity": "Projekt", "parameters": {"label": "Hauptstrasse 42"}, "confidence": 0.95}
- Input: "Zeige mir alle Projekte"
Output: {"intent": "READ", "entity": "Projekt", "parameters": {}, "confidence": 0.9}
- Input: "Zeige mir Projekte in Zürich" or "Wie viele Projekte in Zürich"
Output: {"intent": "READ", "entity": "Projekt", "parameters": {"location_filter": "Zürich"}, "confidence": 0.9}
Note: For project location queries, use Projekt entity with location_filter parameter
- Input: "Zeige mir Parzellen mit PLZ 8000"
Output: {"intent": "READ", "entity": "Parzelle", "parameters": {"plz": "8000"}, "confidence": 0.95}
- Input: "Aktualisiere Projekt XYZ mit Status 'Planung'"
Output: {"intent": "UPDATE", "entity": "Projekt", "parameters": {"id": "XYZ", "statusProzess": "Planung"}, "confidence": 0.85}
- Input: "SELECT * FROM Projekt WHERE label = 'Test'"
Output: {"intent": "QUERY", "entity": null, "parameters": {"queryText": "SELECT * FROM Projekt WHERE label = 'Test'", "queryType": "sql"}, "confidence": 1.0}
- Input: "Lösche Parzelle ABC"
Output: {"intent": "DELETE", "entity": "Parzelle", "parameters": {"id": "ABC"}, "confidence": 0.9}

View file

@ -1,17 +0,0 @@
```json
{
"intent": "READ",
"entity": "Projekt",
"parameters": {
"location_filter": "zürich"
},
"confidence": 0.9
}
```
**Analysis:**
- **Intent**: READ - The user wants to query/count existing projects ("wie viele Projekte ... gibt es")
- **Entity**: Projekt - The query is about projects ("Projekte")
- **Parameters**:
- `location_filter`: "zürich" - The user is asking about projects in Zürich. Since Projekt doesn't have direct location fields but location is stored in associated Parzellen (via kontextGemeinde), we use the `location_filter` parameter to indicate this geographic filter needs to be resolved through the Parzelle relationship.
- **Confidence**: 0.9 - High confidence. The intent is clear (counting/querying projects), the location is explicitly mentioned, and the temporal indicator "jetzt" (now) suggests current/active projects.

View file

@ -1,89 +0,0 @@
Analyze the following user command and extract the intent, entity, and parameters.
User Command: "wie viele parzellen in zürich gibt es?"
Available intents:
- CREATE: User wants to create a new entity
- READ: User wants to read/query entities
- UPDATE: User wants to update an existing entity
- DELETE: User wants to delete an entity
- QUERY: User wants to execute a database query (SQL statements)
Available entities and their fields:
**Projekt** (Real estate project):
- id: string (primary key)
- mandateId: string (mandate ID)
- label: string (project designation/name)
- statusProzess: string enum (Eingang, Analyse, Studie, Planung, Baurechtsverfahren, Umsetzung, Archiv)
- perimeter: GeoPolylinie (geographic boundary, JSONB)
- baulinie: GeoPolylinie (building line, JSONB)
- parzellen: List[Parzelle] (plots belonging to project, JSONB)
- dokumente: List[Dokument] (documents, JSONB)
- kontextInformationen: List[Kontext] (context info, JSONB)
**Parzelle** (Plot/parcel):
- id: string (primary key)
- mandateId: string (mandate ID)
- label: string (plot designation)
- strasseNr: string (street and house number)
- plz: string (postal code)
- kontextGemeinde: string (municipality ID, Foreign Key to Gemeinde table)
- bauzone: string (building zone, e.g. W3, WG2)
- az: float (Ausnützungsziffer)
- bz: float (Bebauungsziffer)
- vollgeschossZahl: int (number of allowed full floors)
- gebaeudehoeheMax: float (maximum building height in meters)
- laermschutzzone: string (noise protection zone)
- hochwasserschutzzone: string (flood protection zone)
- grundwasserschutzzone: string (groundwater protection zone)
- parzelleBebaut: JaNein enum (is plot built)
- parzelleErschlossen: JaNein enum (is plot developed)
- parzelleHanglage: JaNein enum (is plot on slope)
**Important relationships:**
- Projekte contain Parzellen (projects have plots)
- Parzelle links to Gemeinde (via kontextGemeinde)
- Gemeinde links to Kanton (via id_kanton)
- Kanton links to Land (via id_land)
- Location queries (city, postal code) should use Parzelle.kontextGemeinde (municipality name will be resolved to ID)
- Projekt does NOT have location fields directly - location is stored in associated Parzellen
Return a JSON object with the following structure:
{
"intent": "CREATE|READ|UPDATE|DELETE|QUERY",
"entity": "Projekt|Parzelle|Dokument|Kanton|Gemeinde|null",
"parameters": {
// Extracted parameters from user input
// For CREATE/UPDATE: include all relevant fields using EXACT field names from above
// For READ: include filter criteria using EXACT field names (id, label, plz, kontextGemeinde, etc.)
// For DELETE: include entity ID if mentioned
// For QUERY: include queryText if SQL is detected
// IMPORTANT: Use only field names that exist in the entity definition above
},
"confidence": 0.0-1.0 // Confidence score for the analysis
}
Examples:
- Input: "Erstelle ein neues Projekt namens 'Hauptstrasse 42'"
Output: {"intent": "CREATE", "entity": "Projekt", "parameters": {"label": "Hauptstrasse 42"}, "confidence": 0.95}
- Input: "Zeige mir alle Projekte"
Output: {"intent": "READ", "entity": "Projekt", "parameters": {}, "confidence": 0.9}
- Input: "Zeige mir Projekte in Zürich" or "Wie viele Projekte in Zürich"
Output: {"intent": "READ", "entity": "Projekt", "parameters": {"location_filter": "Zürich"}, "confidence": 0.9}
Note: For project location queries, use Projekt entity with location_filter parameter
- Input: "Zeige mir Parzellen mit PLZ 8000"
Output: {"intent": "READ", "entity": "Parzelle", "parameters": {"plz": "8000"}, "confidence": 0.95}
- Input: "Aktualisiere Projekt XYZ mit Status 'Planung'"
Output: {"intent": "UPDATE", "entity": "Projekt", "parameters": {"id": "XYZ", "statusProzess": "Planung"}, "confidence": 0.85}
- Input: "SELECT * FROM Projekt WHERE label = 'Test'"
Output: {"intent": "QUERY", "entity": null, "parameters": {"queryText": "SELECT * FROM Projekt WHERE label = 'Test'", "queryType": "sql"}, "confidence": 1.0}
- Input: "Lösche Parzelle ABC"
Output: {"intent": "DELETE", "entity": "Parzelle", "parameters": {"id": "ABC"}, "confidence": 0.9}

View file

@ -1,17 +0,0 @@
```json
{
"intent": "READ",
"entity": "Parzelle",
"parameters": {
"kontextGemeinde": "Zürich"
},
"confidence": 0.9
}
```
**Reasoning:**
- The user is asking "wie viele parzellen in zürich gibt es?" (how many plots are there in Zürich?)
- **Intent**: READ - The user wants to query/read information about existing entities
- **Entity**: Parzelle - The user is specifically asking about "parzellen" (plots/parcels)
- **Parameters**: The location "Zürich" refers to a municipality (Gemeinde). Since Parzelle has the field `kontextGemeinde` which links to the municipality, this is the appropriate field to use for filtering by location
- **Confidence**: 0.9 - High confidence as the intent and entity are clearly stated, though the exact count operation is implicit

View file

@ -1,89 +0,0 @@
Analyze the following user command and extract the intent, entity, and parameters.
User Command: "wie viele parzellen in zürich gibt es?"
Available intents:
- CREATE: User wants to create a new entity
- READ: User wants to read/query entities
- UPDATE: User wants to update an existing entity
- DELETE: User wants to delete an entity
- QUERY: User wants to execute a database query (SQL statements)
Available entities and their fields:
**Projekt** (Real estate project):
- id: string (primary key)
- mandateId: string (mandate ID)
- label: string (project designation/name)
- statusProzess: string enum (Eingang, Analyse, Studie, Planung, Baurechtsverfahren, Umsetzung, Archiv)
- perimeter: GeoPolylinie (geographic boundary, JSONB)
- baulinie: GeoPolylinie (building line, JSONB)
- parzellen: List[Parzelle] (plots belonging to project, JSONB)
- dokumente: List[Dokument] (documents, JSONB)
- kontextInformationen: List[Kontext] (context info, JSONB)
**Parzelle** (Plot/parcel):
- id: string (primary key)
- mandateId: string (mandate ID)
- label: string (plot designation)
- strasseNr: string (street and house number)
- plz: string (postal code)
- kontextGemeinde: string (municipality ID, Foreign Key to Gemeinde table)
- bauzone: string (building zone, e.g. W3, WG2)
- az: float (Ausnützungsziffer)
- bz: float (Bebauungsziffer)
- vollgeschossZahl: int (number of allowed full floors)
- gebaeudehoeheMax: float (maximum building height in meters)
- laermschutzzone: string (noise protection zone)
- hochwasserschutzzone: string (flood protection zone)
- grundwasserschutzzone: string (groundwater protection zone)
- parzelleBebaut: JaNein enum (is plot built)
- parzelleErschlossen: JaNein enum (is plot developed)
- parzelleHanglage: JaNein enum (is plot on slope)
**Important relationships:**
- Projekte contain Parzellen (projects have plots)
- Parzelle links to Gemeinde (via kontextGemeinde)
- Gemeinde links to Kanton (via id_kanton)
- Kanton links to Land (via id_land)
- Location queries (city, postal code) should use Parzelle.kontextGemeinde (municipality name will be resolved to ID)
- Projekt does NOT have location fields directly - location is stored in associated Parzellen
Return a JSON object with the following structure:
{
"intent": "CREATE|READ|UPDATE|DELETE|QUERY",
"entity": "Projekt|Parzelle|Dokument|Kanton|Gemeinde|null",
"parameters": {
// Extracted parameters from user input
// For CREATE/UPDATE: include all relevant fields using EXACT field names from above
// For READ: include filter criteria using EXACT field names (id, label, plz, kontextGemeinde, etc.)
// For DELETE: include entity ID if mentioned
// For QUERY: include queryText if SQL is detected
// IMPORTANT: Use only field names that exist in the entity definition above
},
"confidence": 0.0-1.0 // Confidence score for the analysis
}
Examples:
- Input: "Erstelle ein neues Projekt namens 'Hauptstrasse 42'"
Output: {"intent": "CREATE", "entity": "Projekt", "parameters": {"label": "Hauptstrasse 42"}, "confidence": 0.95}
- Input: "Zeige mir alle Projekte"
Output: {"intent": "READ", "entity": "Projekt", "parameters": {}, "confidence": 0.9}
- Input: "Zeige mir Projekte in Zürich" or "Wie viele Projekte in Zürich"
Output: {"intent": "READ", "entity": "Projekt", "parameters": {"location_filter": "Zürich"}, "confidence": 0.9}
Note: For project location queries, use Projekt entity with location_filter parameter
- Input: "Zeige mir Parzellen mit PLZ 8000"
Output: {"intent": "READ", "entity": "Parzelle", "parameters": {"plz": "8000"}, "confidence": 0.95}
- Input: "Aktualisiere Projekt XYZ mit Status 'Planung'"
Output: {"intent": "UPDATE", "entity": "Projekt", "parameters": {"id": "XYZ", "statusProzess": "Planung"}, "confidence": 0.85}
- Input: "SELECT * FROM Projekt WHERE label = 'Test'"
Output: {"intent": "QUERY", "entity": null, "parameters": {"queryText": "SELECT * FROM Projekt WHERE label = 'Test'", "queryType": "sql"}, "confidence": 1.0}
- Input: "Lösche Parzelle ABC"
Output: {"intent": "DELETE", "entity": "Parzelle", "parameters": {"id": "ABC"}, "confidence": 0.9}

View file

@ -1,17 +0,0 @@
```json
{
"intent": "READ",
"entity": "Parzelle",
"parameters": {
"kontextGemeinde": "Zürich"
},
"confidence": 0.9
}
```
**Reasoning:**
- The user is asking "wie viele parzellen in zürich gibt es?" (how many plots are there in Zürich?)
- **Intent**: READ - The user wants to query/read information about existing entities
- **Entity**: Parzelle - The user is specifically asking about "parzellen" (plots/parcels)
- **Parameters**: The location "Zürich" refers to a municipality (Gemeinde). Since Parzelle has the field `kontextGemeinde` which links to the municipality, this is the appropriate field to use for filtering by location
- **Confidence**: 0.9 - High confidence as the intent and entity are clearly stated, though the exact count operation is implicit

View file

@ -1,106 +0,0 @@
Analyze the following user command and extract the intent, entity, and parameters.
User Command: "add a new parzelle with these information into the database: Parzellen-Informationen
Ausgewählte Parzelle
ID:AA1704
Nummer:AA1704
Name:AA1704
EGRID:CH887199917793
IdentND:ZH0200000261
Kanton:ZH
Gemeinde:Zürich
Gemeinde-Code:261
Fläche:6514.99 m²
Zentrum (LV95):2682951.44, 1247622.91
Geoportal:
Link öffnen
Kartenansicht
Zentrum:2682951.44, 1247622.91
Bounds Min:2682914.00, 1247582.00
Bounds Max:2683024.30, 1247667.50"
Available intents:
- CREATE: User wants to create a new entity
- READ: User wants to read/query entities
- UPDATE: User wants to update an existing entity
- DELETE: User wants to delete an entity
- QUERY: User wants to execute a database query (SQL statements)
Available entities and their fields:
**Projekt** (Real estate project):
- id: string (primary key)
- mandateId: string (mandate ID)
- label: string (project designation/name)
- statusProzess: string enum (Eingang, Analyse, Studie, Planung, Baurechtsverfahren, Umsetzung, Archiv)
- perimeter: GeoPolylinie (geographic boundary, JSONB)
- baulinie: GeoPolylinie (building line, JSONB)
- parzellen: List[Parzelle] (plots belonging to project, JSONB)
- dokumente: List[Dokument] (documents, JSONB)
- kontextInformationen: List[Kontext] (context info, JSONB)
**Parzelle** (Plot/parcel):
- id: string (primary key)
- mandateId: string (mandate ID)
- label: string (plot designation)
- strasseNr: string (street and house number)
- plz: string (postal code)
- kontextGemeinde: string (municipality ID, Foreign Key to Gemeinde table)
- bauzone: string (building zone, e.g. W3, WG2)
- az: float (Ausnützungsziffer)
- bz: float (Bebauungsziffer)
- vollgeschossZahl: int (number of allowed full floors)
- gebaeudehoeheMax: float (maximum building height in meters)
- laermschutzzone: string (noise protection zone)
- hochwasserschutzzone: string (flood protection zone)
- grundwasserschutzzone: string (groundwater protection zone)
- parzelleBebaut: JaNein enum (is plot built)
- parzelleErschlossen: JaNein enum (is plot developed)
- parzelleHanglage: JaNein enum (is plot on slope)
**Important relationships:**
- Projekte contain Parzellen (projects have plots)
- Parzelle links to Gemeinde (via kontextGemeinde)
- Gemeinde links to Kanton (via id_kanton)
- Kanton links to Land (via id_land)
- Location queries (city, postal code) should use Parzelle.kontextGemeinde (municipality name will be resolved to ID)
- Projekt does NOT have location fields directly - location is stored in associated Parzellen
Return a JSON object with the following structure:
{
"intent": "CREATE|READ|UPDATE|DELETE|QUERY",
"entity": "Projekt|Parzelle|Dokument|Kanton|Gemeinde|null",
"parameters": {
// Extracted parameters from user input
// For CREATE/UPDATE: include all relevant fields using EXACT field names from above
// For READ: include filter criteria using EXACT field names (id, label, plz, kontextGemeinde, etc.)
// For DELETE: include entity ID if mentioned
// For QUERY: include queryText if SQL is detected
// IMPORTANT: Use only field names that exist in the entity definition above
},
"confidence": 0.0-1.0 // Confidence score for the analysis
}
Examples:
- Input: "Erstelle ein neues Projekt namens 'Hauptstrasse 42'"
Output: {"intent": "CREATE", "entity": "Projekt", "parameters": {"label": "Hauptstrasse 42"}, "confidence": 0.95}
- Input: "Zeige mir alle Projekte"
Output: {"intent": "READ", "entity": "Projekt", "parameters": {}, "confidence": 0.9}
- Input: "Zeige mir Projekte in Zürich" or "Wie viele Projekte in Zürich"
Output: {"intent": "READ", "entity": "Projekt", "parameters": {"location_filter": "Zürich"}, "confidence": 0.9}
Note: For project location queries, use Projekt entity with location_filter parameter
- Input: "Zeige mir Parzellen mit PLZ 8000"
Output: {"intent": "READ", "entity": "Parzelle", "parameters": {"plz": "8000"}, "confidence": 0.95}
- Input: "Aktualisiere Projekt XYZ mit Status 'Planung'"
Output: {"intent": "UPDATE", "entity": "Projekt", "parameters": {"id": "XYZ", "statusProzess": "Planung"}, "confidence": 0.85}
- Input: "SELECT * FROM Projekt WHERE label = 'Test'"
Output: {"intent": "QUERY", "entity": null, "parameters": {"queryText": "SELECT * FROM Projekt WHERE label = 'Test'", "queryType": "sql"}, "confidence": 1.0}
- Input: "Lösche Parzelle ABC"
Output: {"intent": "DELETE", "entity": "Parzelle", "parameters": {"id": "ABC"}, "confidence": 0.9}

View file

@ -1,37 +0,0 @@
```json
{
"intent": "CREATE",
"entity": "Parzelle",
"parameters": {
"id": "AA1704",
"label": "AA1704",
"kontextGemeinde": "Zürich"
},
"confidence": 0.75
}
```
**Analysis:**
The user wants to add a new "Parzelle" (plot/parcel) to the database. The command provides extensive information about the parcel, but only a subset can be mapped to the available fields in the **Parzelle** entity definition:
**Mapped fields:**
- `id`: "AA1704" (from ID/Nummer)
- `label`: "AA1704" (from Name)
- `kontextGemeinde`: "Zürich" (from Gemeinde - will need to be resolved to municipality ID)
**Unmapped information** (not available in the Parzelle entity schema):
- EGRID: CH887199917793
- IdentND: ZH0200000261
- Kanton: ZH
- Gemeinde-Code: 261
- Fläche: 6514.99 m²
- Zentrum coordinates (LV95): 2682951.44, 1247622.91
- Bounds coordinates
**Confidence reasoning:**
The confidence is set to 0.75 because:
- The intent (CREATE) is clear
- The entity (Parzelle) is explicitly mentioned
- However, most of the provided information cannot be stored in the current Parzelle schema
- The user may expect all this data to be stored, but the system can only capture id, label, and kontextGemeinde from the provided information

View file

@ -1,131 +0,0 @@
Analyze the following user command and extract the intent, entity, and parameters.
User Command: "erstelle einen neuen parzelleneintrag mit diesen informationen: ID:AA4198
Nummer:AA4198
Name:AA4198
EGRID:CH879177719964
IdentND:ZH0200000261
Adresse:Steinmühleplatz 3, 8001 Zürich
Kanton:ZH
Gemeinde:Zürich
Gemeinde-Code:261
Fläche:1972.83 m²
Zentrum (LV95):2682910.35, 1247566.80"
Available intents:
- CREATE: User wants to create a new entity
- READ: User wants to read/query entities
- UPDATE: User wants to update an existing entity
- DELETE: User wants to delete an entity
- QUERY: User wants to execute a database query (SQL statements)
Available entities and their fields:
**Projekt** (Real estate project):
- id: string (primary key)
- mandateId: string (mandate ID)
- label: string (project designation/name)
- statusProzess: string enum (Eingang, Analyse, Studie, Planung, Baurechtsverfahren, Umsetzung, Archiv)
- perimeter: GeoPolylinie (geographic boundary, JSONB)
- baulinie: GeoPolylinie (building line, JSONB)
- parzellen: List[Parzelle] (plots belonging to project, JSONB)
- dokumente: List[Dokument] (documents, JSONB)
- kontextInformationen: List[Kontext] (context info, JSONB)
**Parzelle** (Plot/parcel):
- id: string (primary key)
- mandateId: string (mandate ID)
- label: string (plot designation)
- strasseNr: string (street and house number)
- plz: string (postal code)
- kontextGemeinde: string (municipality ID, Foreign Key to Gemeinde table)
- bauzone: string (building zone, e.g. W3, WG2)
- az: float (Ausnützungsziffer)
- bz: float (Bebauungsziffer)
- vollgeschossZahl: int (number of allowed full floors)
- gebaeudehoeheMax: float (maximum building height in meters)
- laermschutzzone: string (noise protection zone)
- hochwasserschutzzone: string (flood protection zone)
- grundwasserschutzzone: string (groundwater protection zone)
- parzelleBebaut: JaNein enum (is plot built)
- parzelleErschlossen: JaNein enum (is plot developed)
- parzelleHanglage: JaNein enum (is plot on slope)
**Important relationships:**
- Projekte contain Parzellen (projects have plots)
- Parzelle links to Gemeinde (via kontextGemeinde)
- Gemeinde links to Kanton (via id_kanton)
- Kanton links to Land (via id_land)
- Location queries (city, postal code) should use Parzelle.kontextGemeinde (municipality name will be resolved to ID)
- Projekt does NOT have location fields directly - location is stored in associated Parzellen
Return a JSON object with the following structure:
{
"intent": "CREATE|READ|UPDATE|DELETE|QUERY",
"entity": "Projekt|Parzelle|Dokument|Kanton|Gemeinde|null",
"parameters": {
// Extracted parameters from user input
// For CREATE/UPDATE: include all relevant fields using EXACT field names from above
// For READ: include filter criteria using EXACT field names (id, label, plz, kontextGemeinde, etc.)
// For DELETE: include entity ID if mentioned
// For QUERY: include queryText if SQL is detected
// IMPORTANT: Use only field names that exist in the entity definition above
},
"confidence": 0.0-1.0 // Confidence score for the analysis
}
Examples:
- Input: "Erstelle ein neues Projekt namens 'Hauptstrasse 42'"
Output: {"intent": "CREATE", "entity": "Projekt", "parameters": {"label": "Hauptstrasse 42"}, "confidence": 0.95}
- Input: "Erstelle eine Parzelle mit Label 123, PLZ 8000, Gemeinde Zürich, Bauzone W3"
Output: {"intent": "CREATE", "entity": "Parzelle", "parameters": {"label": "123", "plz": "8000", "kontextGemeinde": "Zürich", "bauzone": "W3"}, "confidence": 0.95}
- Input: "Parzellen-Informationen: ID:AA1704, Nummer:AA1704, EGRID:CH887199917793, Kanton:ZH, Gemeinde:Zürich, Gemeinde-Code:261, Fläche:6514.99 m², Zentrum:2682951.44,1247622.91"
Output: {
"intent": "CREATE",
"entity": "Parzelle",
"parameters": {
"label": "AA1704",
"parzellenAliasTags": ["AA1704"],
"kontextGemeinde": "Zürich",
"kontextInformationen": [
{"kategorie": "Swiss Topo", "schluessel": "EGRID", "wert": "CH887199917793"},
{"kategorie": "Kanton", "schluessel": "Abkürzung", "wert": "ZH"},
{"kategorie": "Gemeinde", "schluessel": "BFS-Nummer", "wert": "261"},
{"kategorie": "Parzelle", "schluessel": "Fläche", "wert": "6514.99", "einheit": "m²"},
{"kategorie": "Parzelle", "schluessel": "Zentrum_X", "wert": "2682951.44", "crs": "EPSG:2056"},
{"kategorie": "Parzelle", "schluessel": "Zentrum_Y", "wert": "1247622.91", "crs": "EPSG:2056"}
]
},
"confidence": 0.9
}
Note: Extract structured data from detailed input. Use kontextInformationen for metadata like EGRID, coordinates, area, etc.
- Input: "Zeige mir alle Projekte"
Output: {"intent": "READ", "entity": "Projekt", "parameters": {}, "confidence": 0.9}
- Input: "Zeige mir Projekte in Zürich" or "Wie viele Projekte in Zürich"
Output: {"intent": "READ", "entity": "Projekt", "parameters": {"location_filter": "Zürich"}, "confidence": 0.9}
Note: For project location queries, use Projekt entity with location_filter parameter
- Input: "Zeige mir Parzellen mit PLZ 8000"
Output: {"intent": "READ", "entity": "Parzelle", "parameters": {"plz": "8000"}, "confidence": 0.95}
- Input: "Aktualisiere Projekt XYZ mit Status 'Planung'"
Output: {"intent": "UPDATE", "entity": "Projekt", "parameters": {"id": "XYZ", "statusProzess": "Planung"}, "confidence": 0.85}
- Input: "SELECT * FROM Projekt WHERE label = 'Test'"
Output: {"intent": "QUERY", "entity": null, "parameters": {"queryText": "SELECT * FROM Projekt WHERE label = 'Test'", "queryType": "sql"}, "confidence": 1.0}
- Input: "Lösche Parzelle ABC"
Output: {"intent": "DELETE", "entity": "Parzelle", "parameters": {"id": "ABC"}, "confidence": 0.9}
IMPORTANT EXTRACTION RULES:
1. For CREATE operations, extract ALL mentioned data fields from the user input
2. Use kontextInformationen array for metadata that doesn't have dedicated fields (EGRID, BFS numbers, area, coordinates, etc.)
3. Match field names EXACTLY to the entity definition above
4. Convert data types correctly (strings for text, numbers for numeric values)
5. Extract coordinates, areas, and other numeric values from text
6. When multiple values are mentioned for the same concept (ID, Nummer, Name), use the most relevant one for 'label' and put alternatives in parzellenAliasTags

View file

@ -1,63 +0,0 @@
```json
{
"intent": "CREATE",
"entity": "Parzelle",
"parameters": {
"label": "AA4198",
"strasseNr": "Steinmühleplatz 3",
"plz": "8001",
"kontextGemeinde": "Zürich",
"kontextInformationen": [
{
"kategorie": "Parzelle",
"schluessel": "ID",
"wert": "AA4198"
},
{
"kategorie": "Parzelle",
"schluessel": "Nummer",
"wert": "AA4198"
},
{
"kategorie": "Swiss Topo",
"schluessel": "EGRID",
"wert": "CH879177719964"
},
{
"kategorie": "Parzelle",
"schluessel": "IdentND",
"wert": "ZH0200000261"
},
{
"kategorie": "Kanton",
"schluessel": "Abkürzung",
"wert": "ZH"
},
{
"kategorie": "Gemeinde",
"schluessel": "BFS-Nummer",
"wert": "261"
},
{
"kategorie": "Parzelle",
"schluessel": "Fläche",
"wert": "1972.83",
"einheit": "m²"
},
{
"kategorie": "Parzelle",
"schluessel": "Zentrum_X",
"wert": "2682910.35",
"crs": "EPSG:2056"
},
{
"kategorie": "Parzelle",
"schluessel": "Zentrum_Y",
"wert": "1247566.80",
"crs": "EPSG:2056"
}
]
},
"confidence": 0.95
}
```

View file

@ -1,131 +0,0 @@
Analyze the following user command and extract the intent, entity, and parameters.
User Command: "erstelle einen neuen parzelleneintrag mit diesen informationen: ID:AA4198
Nummer:AA4198
Name:AA4198
EGRID:CH879177719964
IdentND:ZH0200000261
Adresse:Steinmühleplatz 3, 8001 Zürich
Kanton:ZH
Gemeinde:Zürich
Gemeinde-Code:261
Fläche:1972.83 m²
Zentrum (LV95):2682910.35, 1247566.80"
Available intents:
- CREATE: User wants to create a new entity
- READ: User wants to read/query entities
- UPDATE: User wants to update an existing entity
- DELETE: User wants to delete an entity
- QUERY: User wants to execute a database query (SQL statements)
Available entities and their fields:
**Projekt** (Real estate project):
- id: string (primary key)
- mandateId: string (mandate ID)
- label: string (project designation/name)
- statusProzess: string enum (Eingang, Analyse, Studie, Planung, Baurechtsverfahren, Umsetzung, Archiv)
- perimeter: GeoPolylinie (geographic boundary, JSONB)
- baulinie: GeoPolylinie (building line, JSONB)
- parzellen: List[Parzelle] (plots belonging to project, JSONB)
- dokumente: List[Dokument] (documents, JSONB)
- kontextInformationen: List[Kontext] (context info, JSONB)
**Parzelle** (Plot/parcel):
- id: string (primary key)
- mandateId: string (mandate ID)
- label: string (plot designation)
- strasseNr: string (street and house number)
- plz: string (postal code)
- kontextGemeinde: string (municipality ID, Foreign Key to Gemeinde table)
- bauzone: string (building zone, e.g. W3, WG2)
- az: float (Ausnützungsziffer)
- bz: float (Bebauungsziffer)
- vollgeschossZahl: int (number of allowed full floors)
- gebaeudehoeheMax: float (maximum building height in meters)
- laermschutzzone: string (noise protection zone)
- hochwasserschutzzone: string (flood protection zone)
- grundwasserschutzzone: string (groundwater protection zone)
- parzelleBebaut: JaNein enum (is plot built)
- parzelleErschlossen: JaNein enum (is plot developed)
- parzelleHanglage: JaNein enum (is plot on slope)
**Important relationships:**
- Projekte contain Parzellen (projects have plots)
- Parzelle links to Gemeinde (via kontextGemeinde)
- Gemeinde links to Kanton (via id_kanton)
- Kanton links to Land (via id_land)
- Location queries (city, postal code) should use Parzelle.kontextGemeinde (municipality name will be resolved to ID)
- Projekt does NOT have location fields directly - location is stored in associated Parzellen
Return a JSON object with the following structure:
{
"intent": "CREATE|READ|UPDATE|DELETE|QUERY",
"entity": "Projekt|Parzelle|Dokument|Kanton|Gemeinde|null",
"parameters": {
// Extracted parameters from user input
// For CREATE/UPDATE: include all relevant fields using EXACT field names from above
// For READ: include filter criteria using EXACT field names (id, label, plz, kontextGemeinde, etc.)
// For DELETE: include entity ID if mentioned
// For QUERY: include queryText if SQL is detected
// IMPORTANT: Use only field names that exist in the entity definition above
},
"confidence": 0.0-1.0 // Confidence score for the analysis
}
Examples:
- Input: "Erstelle ein neues Projekt namens 'Hauptstrasse 42'"
Output: {"intent": "CREATE", "entity": "Projekt", "parameters": {"label": "Hauptstrasse 42"}, "confidence": 0.95}
- Input: "Erstelle eine Parzelle mit Label 123, PLZ 8000, Gemeinde Zürich, Bauzone W3"
Output: {"intent": "CREATE", "entity": "Parzelle", "parameters": {"label": "123", "plz": "8000", "kontextGemeinde": "Zürich", "bauzone": "W3"}, "confidence": 0.95}
- Input: "Parzellen-Informationen: ID:AA1704, Nummer:AA1704, EGRID:CH887199917793, Kanton:ZH, Gemeinde:Zürich, Gemeinde-Code:261, Fläche:6514.99 m², Zentrum:2682951.44,1247622.91"
Output: {
"intent": "CREATE",
"entity": "Parzelle",
"parameters": {
"label": "AA1704",
"parzellenAliasTags": ["AA1704"],
"kontextGemeinde": "Zürich",
"kontextInformationen": [
{"kategorie": "Swiss Topo", "schluessel": "EGRID", "wert": "CH887199917793"},
{"kategorie": "Kanton", "schluessel": "Abkürzung", "wert": "ZH"},
{"kategorie": "Gemeinde", "schluessel": "BFS-Nummer", "wert": "261"},
{"kategorie": "Parzelle", "schluessel": "Fläche", "wert": "6514.99", "einheit": "m²"},
{"kategorie": "Parzelle", "schluessel": "Zentrum_X", "wert": "2682951.44", "crs": "EPSG:2056"},
{"kategorie": "Parzelle", "schluessel": "Zentrum_Y", "wert": "1247622.91", "crs": "EPSG:2056"}
]
},
"confidence": 0.9
}
Note: Extract structured data from detailed input. Use kontextInformationen for metadata like EGRID, coordinates, area, etc.
- Input: "Zeige mir alle Projekte"
Output: {"intent": "READ", "entity": "Projekt", "parameters": {}, "confidence": 0.9}
- Input: "Zeige mir Projekte in Zürich" or "Wie viele Projekte in Zürich"
Output: {"intent": "READ", "entity": "Projekt", "parameters": {"location_filter": "Zürich"}, "confidence": 0.9}
Note: For project location queries, use Projekt entity with location_filter parameter
- Input: "Zeige mir Parzellen mit PLZ 8000"
Output: {"intent": "READ", "entity": "Parzelle", "parameters": {"plz": "8000"}, "confidence": 0.95}
- Input: "Aktualisiere Projekt XYZ mit Status 'Planung'"
Output: {"intent": "UPDATE", "entity": "Projekt", "parameters": {"id": "XYZ", "statusProzess": "Planung"}, "confidence": 0.85}
- Input: "SELECT * FROM Projekt WHERE label = 'Test'"
Output: {"intent": "QUERY", "entity": null, "parameters": {"queryText": "SELECT * FROM Projekt WHERE label = 'Test'", "queryType": "sql"}, "confidence": 1.0}
- Input: "Lösche Parzelle ABC"
Output: {"intent": "DELETE", "entity": "Parzelle", "parameters": {"id": "ABC"}, "confidence": 0.9}
IMPORTANT EXTRACTION RULES:
1. For CREATE operations, extract ALL mentioned data fields from the user input
2. Use kontextInformationen array for metadata that doesn't have dedicated fields (EGRID, BFS numbers, area, coordinates, etc.)
3. Match field names EXACTLY to the entity definition above
4. Convert data types correctly (strings for text, numbers for numeric values)
5. Extract coordinates, areas, and other numeric values from text
6. When multiple values are mentioned for the same concept (ID, Nummer, Name), use the most relevant one for 'label' and put alternatives in parzellenAliasTags

View file

@ -1,63 +0,0 @@
```json
{
"intent": "CREATE",
"entity": "Parzelle",
"parameters": {
"label": "AA4198",
"strasseNr": "Steinmühleplatz 3",
"plz": "8001",
"kontextGemeinde": "Zürich",
"kontextInformationen": [
{
"kategorie": "Parzelle",
"schluessel": "ID",
"wert": "AA4198"
},
{
"kategorie": "Parzelle",
"schluessel": "Nummer",
"wert": "AA4198"
},
{
"kategorie": "Swiss Topo",
"schluessel": "EGRID",
"wert": "CH879177719964"
},
{
"kategorie": "Parzelle",
"schluessel": "IdentND",
"wert": "ZH0200000261"
},
{
"kategorie": "Kanton",
"schluessel": "Abkürzung",
"wert": "ZH"
},
{
"kategorie": "Gemeinde",
"schluessel": "BFS-Nummer",
"wert": "261"
},
{
"kategorie": "Parzelle",
"schluessel": "Fläche",
"wert": "1972.83",
"einheit": "m²"
},
{
"kategorie": "Parzelle",
"schluessel": "Zentrum_X",
"wert": "2682910.35",
"crs": "EPSG:2056"
},
{
"kategorie": "Parzelle",
"schluessel": "Zentrum_Y",
"wert": "1247566.80",
"crs": "EPSG:2056"
}
]
},
"confidence": 0.95
}
```

View file

@ -1,137 +0,0 @@
Analyze the following user command and extract the intent, entity, and parameters.
User Command: "erstelle einen neuen parzelleneintrag mit diesen informationen: ID:AA4198
Nummer:AA4198
Name:AA4198
EGRID:CH879177719964
IdentND:ZH0200000261
Adresse:Steinmühleplatz 3, 8001 Zürich
Kanton:ZH
Gemeinde:Zürich
Gemeinde-Code:261
Fläche:1972.83 m²
Zentrum (LV95):2682910.35, 1247566.80"
Available intents:
- CREATE: User wants to create a new entity
- READ: User wants to read/query entities
- UPDATE: User wants to update an existing entity
- DELETE: User wants to delete an entity
- QUERY: User wants to execute a database query (SQL statements)
Available entities and their fields:
**Projekt** (Real estate project):
- id: string (primary key)
- mandateId: string (mandate ID)
- label: string (project designation/name)
- statusProzess: string enum (Eingang, Analyse, Studie, Planung, Baurechtsverfahren, Umsetzung, Archiv)
- perimeter: GeoPolylinie (geographic boundary, JSONB)
- baulinie: GeoPolylinie (building line, JSONB)
- parzellen: List[Parzelle] (plots belonging to project, JSONB)
- dokumente: List[Dokument] (documents, JSONB)
- kontextInformationen: List[Kontext] (context info, JSONB)
**Parzelle** (Plot/parcel):
- id: string (primary key)
- mandateId: string (mandate ID)
- label: string (plot designation)
- strasseNr: string (street and house number)
- plz: string (postal code)
- kontextGemeinde: string (municipality ID, Foreign Key to Gemeinde table)
- bauzone: string (building zone, e.g. W3, WG2)
- az: float (Ausnützungsziffer)
- bz: float (Bebauungsziffer)
- vollgeschossZahl: int (number of allowed full floors)
- gebaeudehoeheMax: float (maximum building height in meters)
- laermschutzzone: string (noise protection zone)
- hochwasserschutzzone: string (flood protection zone)
- grundwasserschutzzone: string (groundwater protection zone)
- parzelleBebaut: JaNein enum (is plot built)
- parzelleErschlossen: JaNein enum (is plot developed)
- parzelleHanglage: JaNein enum (is plot on slope)
- kontextInformationen: List[Kontext] (metadata - each item has 'thema' and 'inhalt' fields only)
**Kontext** (Context information for metadata):
- thema: string (topic/subject, e.g. "EGRID", "Fläche", "Zentrum")
- inhalt: string (content as text, e.g. "CH887199917793", "6514.99 m²", "X: 123, Y: 456")
**Important relationships:**
- Projekte contain Parzellen (projects have plots)
- Parzelle links to Gemeinde (via kontextGemeinde)
- Gemeinde links to Kanton (via id_kanton)
- Kanton links to Land (via id_land)
- Location queries (city, postal code) should use Parzelle.kontextGemeinde (municipality name will be resolved to ID)
- Projekt does NOT have location fields directly - location is stored in associated Parzellen
Return a JSON object with the following structure:
{
"intent": "CREATE|READ|UPDATE|DELETE|QUERY",
"entity": "Projekt|Parzelle|Dokument|Kanton|Gemeinde|null",
"parameters": {
// Extracted parameters from user input
// For CREATE/UPDATE: include all relevant fields using EXACT field names from above
// For READ: include filter criteria using EXACT field names (id, label, plz, kontextGemeinde, etc.)
// For DELETE: include entity ID if mentioned
// For QUERY: include queryText if SQL is detected
// IMPORTANT: Use only field names that exist in the entity definition above
},
"confidence": 0.0-1.0 // Confidence score for the analysis
}
Examples:
- Input: "Erstelle ein neues Projekt namens 'Hauptstrasse 42'"
Output: {"intent": "CREATE", "entity": "Projekt", "parameters": {"label": "Hauptstrasse 42"}, "confidence": 0.95}
- Input: "Erstelle eine Parzelle mit Label 123, PLZ 8000, Gemeinde Zürich, Bauzone W3"
Output: {"intent": "CREATE", "entity": "Parzelle", "parameters": {"label": "123", "plz": "8000", "kontextGemeinde": "Zürich", "bauzone": "W3"}, "confidence": 0.95}
- Input: "Parzellen-Informationen: ID:AA1704, Nummer:AA1704, EGRID:CH887199917793, Kanton:ZH, Gemeinde:Zürich, Gemeinde-Code:261, Fläche:6514.99 m², Zentrum:2682951.44,1247622.91"
Output: {
"intent": "CREATE",
"entity": "Parzelle",
"parameters": {
"label": "AA1704",
"parzellenAliasTags": ["AA1704"],
"kontextGemeinde": "Zürich",
"kontextInformationen": [
{"thema": "EGRID", "inhalt": "CH887199917793"},
{"thema": "Kanton", "inhalt": "ZH"},
{"thema": "BFS-Nummer", "inhalt": "261"},
{"thema": "Fläche", "inhalt": "6514.99 m²"},
{"thema": "Zentrum (LV95)", "inhalt": "X: 2682951.44 m, Y: 1247622.91 m (EPSG:2056)"}
]
},
"confidence": 0.9
}
Note: Extract structured data from detailed input. Use kontextInformationen for metadata. Each item has 'thema' (topic) and 'inhalt' (content as text).
- Input: "Zeige mir alle Projekte"
Output: {"intent": "READ", "entity": "Projekt", "parameters": {}, "confidence": 0.9}
- Input: "Zeige mir Projekte in Zürich" or "Wie viele Projekte in Zürich"
Output: {"intent": "READ", "entity": "Projekt", "parameters": {"location_filter": "Zürich"}, "confidence": 0.9}
Note: For project location queries, use Projekt entity with location_filter parameter
- Input: "Zeige mir Parzellen mit PLZ 8000"
Output: {"intent": "READ", "entity": "Parzelle", "parameters": {"plz": "8000"}, "confidence": 0.95}
- Input: "Aktualisiere Projekt XYZ mit Status 'Planung'"
Output: {"intent": "UPDATE", "entity": "Projekt", "parameters": {"id": "XYZ", "statusProzess": "Planung"}, "confidence": 0.85}
- Input: "SELECT * FROM Projekt WHERE label = 'Test'"
Output: {"intent": "QUERY", "entity": null, "parameters": {"queryText": "SELECT * FROM Projekt WHERE label = 'Test'", "queryType": "sql"}, "confidence": 1.0}
- Input: "Lösche Parzelle ABC"
Output: {"intent": "DELETE", "entity": "Parzelle", "parameters": {"id": "ABC"}, "confidence": 0.9}
IMPORTANT EXTRACTION RULES:
1. For CREATE operations, extract ALL mentioned data fields from the user input
2. Use kontextInformationen array for metadata that doesn't have dedicated fields (EGRID, BFS numbers, area, coordinates, etc.)
3. Each kontextInformationen item MUST have exactly two fields: 'thema' (topic/subject) and 'inhalt' (content as text string)
4. Format kontextInformationen values as readable text strings, including units (e.g., "6514.99 m²", "X: 123, Y: 456")
5. Match field names EXACTLY to the entity definition above
6. Convert data types correctly (strings for text, numbers for numeric values)
7. Extract coordinates, areas, and other numeric values from text
8. When multiple values are mentioned for the same concept (ID, Nummer, Name), use the most relevant one for 'label' and put alternatives in parzellenAliasTags

View file

@ -1,47 +0,0 @@
```json
{
"intent": "CREATE",
"entity": "Parzelle",
"parameters": {
"label": "AA4198",
"strasseNr": "Steinmühleplatz 3",
"plz": "8001",
"kontextGemeinde": "Zürich",
"kontextInformationen": [
{
"thema": "ID",
"inhalt": "AA4198"
},
{
"thema": "Nummer",
"inhalt": "AA4198"
},
{
"thema": "EGRID",
"inhalt": "CH879177719964"
},
{
"thema": "IdentND",
"inhalt": "ZH0200000261"
},
{
"thema": "Kanton",
"inhalt": "ZH"
},
{
"thema": "BFS-Nummer",
"inhalt": "261"
},
{
"thema": "Fläche",
"inhalt": "1972.83 m²"
},
{
"thema": "Zentrum (LV95)",
"inhalt": "X: 2682910.35 m, Y: 1247566.80 m (EPSG:2056)"
}
]
},
"confidence": 0.95
}
```