mitai-jinkendo/docs/issues/issue-51-prompt-page-assignment.md
Lars cd2609da7c
All checks were successful
Deploy Development / deploy (push) Successful in 48s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 14s
feat: Feature Request #49 - Prompt-Zuordnung zu Verlaufsseiten
UX Enhancement: Kontextbezogene KI-Analysen

Features:
- Prompts auf Verlaufsseiten verfügbar machen
- Mehrfachauswahl: Prompt auf mehreren Seiten
- Inline-Analyse via Modal
- Wiederverwendbare PagePrompts Komponente

Technisch:
- DB: available_on JSONB column
- API: GET /api/prompts/for-page/{page_slug}
- UI: Page-Auswahl im Prompt-Editor

Aufwand: 6-8h, Priority: Medium
Gitea: Issue #49
2026-03-26 15:12:39 +01:00

426 lines
14 KiB
Markdown

# Feature: Prompt-Zuordnung zu Verlaufsseiten
**Labels:** feature, ux, enhancement
**Priority:** Medium (Phase 1-2)
**Related:** Issue #28 (Unified Prompt System - Complete)
## Beschreibung
KI-Prompts sollen flexibel auf verschiedenen Verlaufsseiten verfügbar gemacht werden können. Jeder Prompt kann auf mehreren Seiten gleichzeitig angeboten werden (Mehrfachauswahl).
## Problem (aktueller Stand)
**Aktuell:**
- Prompts sind nur über die zentrale Analyse-Seite (📊 Analyse) verfügbar
- Kein kontextbezogener Zugriff auf relevante Analysen
- User muss immer zur Analyse-Seite navigieren
**Beispiel-Szenario:**
```
User ist auf: Gewicht → Verlauf
Will: Gewichtstrend analysieren
Muss: Zur Analyse-Seite → Prompt auswählen → Zurück
```
**Wünschenswert:**
```
User ist auf: Gewicht → Verlauf
Sieht: "🤖 KI-Analyse" Button mit relevanten Prompts
Kann: Direkt "Gewichtstrend-Analyse" starten
```
## Gewünschtes Verhalten
### 1. Prompt-Konfiguration erweitern
**Admin → KI-Prompts → Prompt bearbeiten:**
```
┌─────────────────────────────────────────────┐
│ Prompt bearbeiten: Gewichtstrend-Analyse │
├─────────────────────────────────────────────┤
│ Name: Gewichtstrend-Analyse │
│ Slug: weight_trend │
│ Type: Pipeline │
│ │
│ 📍 Verfügbar auf Seiten: │
│ ┌─────────────────────────────────────────┐ │
│ │ ☑ Analyse (Hauptseite) │ │
│ │ ☑ Gewicht → Verlauf │ │
│ │ ☐ Umfänge → Verlauf │ │
│ │ ☐ Caliper → Verlauf │ │
│ │ ☐ Aktivität → Verlauf │ │
│ │ ☐ Ernährung → Verlauf │ │
│ │ ☐ Schlaf → Verlauf │ │
│ │ ☐ Vitalwerte → Verlauf │ │
│ │ ☐ Dashboard │ │
│ └─────────────────────────────────────────┘ │
│ │
│ [Speichern] [Abbrechen] │
└─────────────────────────────────────────────┘
```
**Mehrfachauswahl:**
- Ein Prompt kann auf mehreren Seiten gleichzeitig verfügbar sein
- Mindestens eine Seite muss ausgewählt sein
- Default: "Analyse (Hauptseite)" ist immer vorausgewählt
### 2. UI auf Verlaufsseiten
**Gewicht → Verlauf:**
```
┌─────────────────────────────────────────────┐
│ 📊 Gewicht - Verlauf │
│ [Filter: 7d] [30d] [90d] [Alle] │
├─────────────────────────────────────────────┤
│ │
│ [Chart: Gewichtsverlauf] │
│ │
├─────────────────────────────────────────────┤
│ 🤖 KI-Analysen │
│ ┌─────────────────────────────────────────┐ │
│ │ Gewichtstrend-Analyse [▶ Starten]│ │
│ │ Körperkomposition-Check [▶ Starten]│ │
│ └─────────────────────────────────────────┘ │
│ │
│ [Einträge-Tabelle...] │
└─────────────────────────────────────────────┘
```
**Features:**
- Kompaktes Widget unterhalb des Charts
- Nur relevante Prompts werden angezeigt
- Button startet Analyse inline (Modal oder expandierend)
- Ergebnis wird direkt auf der Seite angezeigt
### 3. Inline-Analyse Anzeige
**Option A: Modal (empfohlen für MVP):**
```
Click auf [▶ Starten]
┌─────────────────────────────────────────────┐
│ ✕ Gewichtstrend-Analyse │
├─────────────────────────────────────────────┤
│ [Spinner] Analysiere Gewichtsdaten... │
│ │
│ [Nach Abschluss:] │
│ Analyse-Text... │
│ │
│ 📊 Verwendete Werte (12) [🔬 Experten] │
│ [Value Table...] │
│ │
│ [Schließen] [In Verlauf speichern] │
└─────────────────────────────────────────────┘
```
**Option B: Expandierend (später):**
```
Click auf [▶ Starten]
Widget expandiert nach unten
Zeigt Analyse-Ergebnis inline
[△ Einklappen] Button
```
## Technische Umsetzung
### 1. Datenbankschema erweitern
**Tabelle: `ai_prompts`**
```sql
ALTER TABLE ai_prompts ADD COLUMN available_on JSONB DEFAULT '["analysis"]';
COMMENT ON COLUMN ai_prompts.available_on IS
'Array of page slugs where prompt is available.
Values: analysis, weight_history, circ_history, caliper_history,
activity_history, nutrition_history, sleep_history, vitals_history, dashboard';
-- Migration 022
```
**Beispiel-Werte:**
```json
{
"slug": "weight_trend",
"name": "Gewichtstrend-Analyse",
"available_on": ["analysis", "weight_history"]
}
{
"slug": "pipeline_master",
"name": "Vollständige Analyse",
"available_on": ["analysis", "dashboard"]
}
{
"slug": "nutrition_check",
"name": "Ernährungs-Check",
"available_on": ["analysis", "nutrition_history", "activity_history"]
}
```
### 2. Backend API erweitern
**Neuer Endpoint: GET /api/prompts/for-page/{page_slug}**
```python
@router.get("/for-page/{page_slug}")
def get_prompts_for_page(page_slug: str, session: dict = Depends(require_auth)):
"""Get all prompts available for a specific page.
Args:
page_slug: Page identifier (e.g., 'weight_history', 'analysis')
Returns:
List of prompts with available_on containing page_slug
"""
with get_db() as conn:
cur = get_cursor(conn)
cur.execute(
"""SELECT id, name, slug, type, description, available_on
FROM ai_prompts
WHERE available_on @> %s
ORDER BY name""",
(json.dumps([page_slug]),)
)
return [r2d(row) for row in cur.fetchall()]
```
**Beispiel-Aufruf:**
```javascript
// In WeightPage.jsx
const prompts = await api.getPromptsForPage('weight_history')
// Returns: [{slug: 'weight_trend', name: 'Gewichtstrend-Analyse', ...}]
```
**Prompt CRUD erweitern:**
```python
@router.put("/unified/{id}")
def update_unified_prompt(id: str, p: UnifiedPromptCreate, session=Depends(require_admin)):
# ... existing code ...
cur.execute(
"""UPDATE ai_prompts
SET name=%s, slug=%s, template=%s, ..., available_on=%s
WHERE id=%s""",
(..., json.dumps(p.available_on), id)
)
```
### 3. Frontend: Prompt-Editor erweitern
**UnifiedPromptModal.jsx:**
```javascript
const PAGE_OPTIONS = [
{ value: 'analysis', label: '📊 Analyse (Hauptseite)', default: true },
{ value: 'weight_history', label: '⚖️ Gewicht → Verlauf' },
{ value: 'circ_history', label: '📏 Umfänge → Verlauf' },
{ value: 'caliper_history', label: '📐 Caliper → Verlauf' },
{ value: 'activity_history', label: '🏃 Aktivität → Verlauf' },
{ value: 'nutrition_history', label: '🍎 Ernährung → Verlauf' },
{ value: 'sleep_history', label: '😴 Schlaf → Verlauf' },
{ value: 'vitals_history', label: '❤️ Vitalwerte → Verlauf' },
{ value: 'dashboard', label: '🏠 Dashboard' },
]
// In form:
<div className="form-row">
<label>Verfügbar auf Seiten</label>
<div style={{display: 'flex', flexDirection: 'column', gap: 8}}>
{PAGE_OPTIONS.map(opt => (
<label key={opt.value} style={{display: 'flex', gap: 8, alignItems: 'center'}}>
<input
type="checkbox"
checked={availableOn.includes(opt.value)}
onChange={e => {
if (e.target.checked) {
setAvailableOn([...availableOn, opt.value])
} else {
// Don't allow unchecking all
if (availableOn.length > 1) {
setAvailableOn(availableOn.filter(v => v !== opt.value))
}
}
}}
/>
{opt.label}
</label>
))}
</div>
</div>
```
### 4. Frontend: Verlaufsseiten erweitern
**WeightPage.jsx (Beispiel):**
```javascript
function WeightPage() {
const [prompts, setPrompts] = useState([])
const [runningAnalysis, setRunningAnalysis] = useState(null)
const [analysisResult, setAnalysisResult] = useState(null)
useEffect(() => {
loadPrompts()
}, [])
const loadPrompts = async () => {
try {
const data = await api.getPromptsForPage('weight_history')
setPrompts(data)
} catch(e) {
console.error('Failed to load prompts:', e)
}
}
const runAnalysis = async (promptSlug) => {
setRunningAnalysis(promptSlug)
try {
const result = await api.executePrompt(promptSlug, {save: true})
setAnalysisResult(result)
} catch(e) {
setError(e.message)
} finally {
setRunningAnalysis(null)
}
}
return (
<div className="page">
<h1>Gewicht - Verlauf</h1>
{/* Chart */}
<WeightChart data={data} />
{/* AI Prompts Widget */}
{prompts.length > 0 && (
<div className="ai-prompts-widget">
<h3>🤖 KI-Analysen</h3>
{prompts.map(p => (
<button
key={p.slug}
onClick={() => runAnalysis(p.slug)}
disabled={runningAnalysis === p.slug}
>
{p.name} {runningAnalysis === p.slug ? '⏳' : '▶'}
</button>
))}
</div>
)}
{/* Analysis Result Modal */}
{analysisResult && (
<AnalysisResultModal
result={analysisResult}
onClose={() => setAnalysisResult(null)}
/>
)}
{/* Data Table */}
<DataTable entries={entries} />
</div>
)
}
```
**Wiederverwendbare Komponente:**
```javascript
// components/PagePrompts.jsx
export function PagePrompts({ pageSlug }) {
// ... logic ...
return (
<div className="page-prompts">
<h3>🤖 KI-Analysen</h3>
{prompts.map(p => (
<PromptButton key={p.slug} prompt={p} onRun={runAnalysis} />
))}
</div>
)
}
// Usage in any page:
<PagePrompts pageSlug="weight_history" />
```
## Akzeptanzkriterien
- [ ] DB-Migration: `available_on` JSONB column in ai_prompts
- [ ] Backend: `GET /api/prompts/for-page/{page_slug}` Endpoint
- [ ] Backend: CRUD operations unterstützen available_on
- [ ] Frontend: Prompt-Editor zeigt Page-Auswahl (Mehrfachauswahl)
- [ ] Frontend: Mindestens 1 Page muss ausgewählt sein
- [ ] Frontend: Wiederverwendbare PagePrompts Komponente
- [ ] Frontend: Integration in mind. 2 Verlaufsseiten (Weight, Nutrition)
- [ ] UI: Inline-Analyse via Modal mit Value Table
- [ ] UI: Loading-State während Analyse läuft
- [ ] Dokumentation: API-Dokumentation aktualisiert
## Abschätzung
**Aufwand:** 6-8 Stunden
- 1h: DB-Migration + Backend Endpoint
- 2h: Prompt-Editor erweitern (Page-Auswahl)
- 2h: PagePrompts Komponente + Modal
- 2h: Integration in Verlaufsseiten (2-3 Seiten)
- 1h: Testing + Feintuning
**Priorität:** Medium
- Verbessert UX erheblich (kontextbezogene Analysen)
- Nutzt bestehendes Prompt-System (Issue #28)
- Relativ einfach zu implementieren (kein neues Backend-System)
## Use Cases
### UC1: Gewichtstrend auf Gewicht-Seite
```
User: Navigiert zu "Gewicht → Verlauf"
System: Zeigt Gewichts-Chart + verfügbare Prompts
User: Click "Gewichtstrend-Analyse ▶"
System: Startet Analyse, zeigt Modal mit Ergebnis
User: Click "In Verlauf speichern"
System: Speichert in ai_insights, zeigt in Analyse-Verlauf
```
### UC2: Ernährungs-Check auf Ernährung-Seite
```
User: Navigiert zu "Ernährung → Verlauf"
System: Zeigt Ernährungs-Charts + verfügbare Prompts
User: Click "Ernährungs-Check ▶"
System: Analysiert Makros + Kalorien der letzten 7 Tage
User: Sieht Empfehlungen direkt auf Ernährungs-Seite
```
### UC3: Multi-Page Prompt (z.B. "Vollständige Analyse")
```
Admin: Konfiguriert "Vollständige Analyse"
- Verfügbar auf: [Analyse, Dashboard, Gewicht, Ernährung]
User: Sieht denselben Prompt auf 4 verschiedenen Seiten
User: Kann von überall die gleiche umfassende Analyse starten
```
## Notizen
- **Rückwärtskompatibilität:** Bestehende Prompts ohne `available_on` → Default `["analysis"]`
- **Migration:** Alle existierenden Prompts bekommen `["analysis"]` gesetzt
- **Permissions:** Prompts respektieren weiterhin Feature-Enforcement (ai_calls)
- **Caching:** Prompts könnten gecacht werden (selten geändert)
- **Mobile:** PagePrompts sollte auch auf Mobile gut aussehen (Stack-Layout)
- **Performance:** Lazy-Loading der Prompts (nur laden wenn Seite besucht)
## Erweiterungen (Future)
- **Conditional Display:** Prompts nur anzeigen wenn Daten vorhanden
- Beispiel: "Gewichtstrend" nur wenn min. 3 Gewichts-Einträge
- **Quick Actions:** Direkt-Buttons im Chart (ohne separates Widget)
- **Page-spezifische Variablen:** Automatisch aktuelle Filter übergeben
- Beispiel: Wenn "30d" Filter aktiv → `{{timeframe}}` = 30
- **Prompt-Templates pro Page:** Vordefinierte Vorlagen für jede Seite
- **Favoriten:** User kann Prompts auf Seiten favorisieren (User-spezifisch)
## Verwandte Issues
- #28: Unified Prompt System (Basis für dieses Feature)
- #45: KI Prompt-Optimierer (könnte Page-Kontext nutzen)
- #46: KI Prompt-Ersteller (sollte Page-Auswahl anbieten)