diff --git a/CLAUDE.md b/CLAUDE.md index 164a5a8..2ea8319 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -56,7 +56,7 @@ frontend/src/ └── technical/ # MEMBERSHIP_SYSTEM.md ``` -## Aktuelle Version: v9c (komplett) 🚀 Production seit 21.03.2026 +## Aktuelle Version: v9d + Issue #28 🚀 Development seit 25.03.2026 ### Implementiert ✅ - Login (E-Mail + bcrypt), Auth-Middleware alle Endpoints, Rate Limiting @@ -188,6 +188,53 @@ frontend/src/ 📚 Details: `.claude/docs/technical/MEMBERSHIP_SYSTEM.md` · `.claude/docs/architecture/FEATURE_ENFORCEMENT.md` +### Issue #28: Unified Prompt System ✅ (Development 25.03.2026) + +**AI-Prompts Flexibilisierung - Komplett überarbeitet:** + +- ✅ **Unified Prompt System (4 Phasen):** + - **Phase 1:** DB-Migration - Schema erweitert + - `ai_prompts` um `type`, `stages`, `output_format`, `output_schema` erweitert + - Alle Prompts zu 1-stage Pipelines migriert + - Pipeline-Configs in `ai_prompts` konsolidiert + - **Phase 2:** Backend Executor + - `prompt_executor.py` - universeller Executor für base + pipeline + - Dynamische Placeholder-Auflösung (`{{stage_N_key}}`) + - JSON-Output-Validierung + - Multi-stage parallele Ausführung + - Reference (Basis-Prompts) + Inline (Templates) Support + - **Phase 3:** Frontend UI Consolidation + - `UnifiedPromptModal` - ein Editor für beide Typen + - `AdminPromptsPage` - Tab-Switcher entfernt, Type-Filter hinzugefügt + - Stage-Editor mit Add/Remove/Reorder + - Mobile-ready Design + - **Phase 4:** Cleanup & Docs + - Deprecated Komponenten entfernt (PipelineConfigModal, PromptEditModal) + - Old endpoints behalten für Backward-Compatibility + +**Features:** +- Unbegrenzte dynamische Stages (keine 3-Stage Limitierung mehr) +- Mehrere Prompts pro Stage (parallel) +- Zwei Prompt-Typen: `base` (wiederverwendbar) + `pipeline` (Workflows) +- Inline-Templates oder Referenzen zu Basis-Prompts +- JSON-Output erzwingbar pro Prompt +- Cross-Module Korrelationen möglich + +**Migrations:** +- Migration 020: Unified Prompt System Schema + +**Backend Endpoints:** +- `POST /api/prompts/execute` - Universeller Executor +- `POST /api/prompts/unified` - Create unified prompt +- `PUT /api/prompts/unified/{id}` - Update unified prompt + +**UI:** +- Admin → KI-Prompts: Type-Filter (Alle/Basis/Pipeline) +- Neuer Prompt-Editor mit dynamischem Stage-Builder +- Inline editing von Stages + Prompts + +📚 Details: `.claude/docs/functional/AI_PROMPTS.md` + ## Feature-Roadmap > 📋 **Detaillierte Roadmap:** `.claude/docs/ROADMAP.md` (Phasen 0-3, Timeline, Abhängigkeiten) diff --git a/frontend/src/components/PipelineConfigModal.jsx b/frontend/src/components/PipelineConfigModal.jsx deleted file mode 100644 index 888b16e..0000000 --- a/frontend/src/components/PipelineConfigModal.jsx +++ /dev/null @@ -1,386 +0,0 @@ -import { useState, useEffect } from 'react' -import { api } from '../utils/api' -import { X } from 'lucide-react' - -const MODULES = [ - { id: 'körper', label: 'Körper', defaultDays: 30 }, - { id: 'ernährung', label: 'Ernährung', defaultDays: 30 }, - { id: 'training', label: 'Training', defaultDays: 14 }, - { id: 'schlaf', label: 'Schlaf', defaultDays: 14 }, - { id: 'vitalwerte', label: 'Vitalwerte', defaultDays: 7 }, - { id: 'mentales', label: 'Mentales', defaultDays: 7 }, - { id: 'ziele', label: 'Ziele', defaultDays: null }, // No timeframe for goals -] - -export default function PipelineConfigModal({ config, onSave, onClose }) { - const [name, setName] = useState('') - const [description, setDescription] = useState('') - const [isDefault, setIsDefault] = useState(false) - const [active, setActive] = useState(true) - - // Modules state: {körper: true, ernährung: false, ...} - const [modules, setModules] = useState({}) - - // Timeframes state: {körper: 30, ernährung: 30, ...} - const [timeframes, setTimeframes] = useState({}) - - // Stage prompts - const [stage1Prompts, setStage1Prompts] = useState([]) - const [stage2Prompt, setStage2Prompt] = useState('') - const [stage3Prompt, setStage3Prompt] = useState('') - - // Available prompts (for dropdowns) - const [availablePrompts, setAvailablePrompts] = useState([]) - - const [loading, setLoading] = useState(false) - const [error, setError] = useState(null) - - useEffect(() => { - loadAvailablePrompts() - - if (config) { - // Edit mode - setName(config.name || '') - setDescription(config.description || '') - setIsDefault(config.is_default || false) - setActive(config.active ?? true) - setModules(config.modules || {}) - setTimeframes(config.timeframes || {}) - setStage1Prompts(config.stage1_prompts || []) - setStage2Prompt(config.stage2_prompt || '') - setStage3Prompt(config.stage3_prompt || '') - } else { - // New mode - set defaults - const defaultModules = {} - const defaultTimeframes = {} - MODULES.forEach(m => { - defaultModules[m.id] = false - if (m.defaultDays) defaultTimeframes[m.id] = m.defaultDays - }) - setModules(defaultModules) - setTimeframes(defaultTimeframes) - } - }, [config]) - - const loadAvailablePrompts = async () => { - try { - const prompts = await api.listAdminPrompts() - setAvailablePrompts(prompts) - } catch (e) { - setError('Fehler beim Laden der Prompts: ' + e.message) - } - } - - const toggleModule = (moduleId) => { - setModules(prev => ({ ...prev, [moduleId]: !prev[moduleId] })) - } - - const updateTimeframe = (moduleId, days) => { - setTimeframes(prev => ({ ...prev, [moduleId]: parseInt(days) || 0 })) - } - - const handleSave = async () => { - // Validation - if (!name.trim()) { - setError('Bitte Namen eingeben') - return - } - - const activeModules = Object.entries(modules).filter(([_, active]) => active).map(([id]) => id) - if (activeModules.length === 0) { - setError('Mindestens ein Modul muss aktiviert sein') - return - } - - if (stage1Prompts.length === 0) { - setError('Mindestens ein Stage-1-Prompt erforderlich') - return - } - - if (!stage2Prompt) { - setError('Stage-2-Prompt (Synthese) erforderlich') - return - } - - setLoading(true) - setError(null) - - try { - const data = { - name, - description, - is_default: isDefault, - active, - modules, - timeframes, - stage1_prompts: stage1Prompts, - stage2_prompt: stage2Prompt, - stage3_prompt: stage3Prompt || null - } - - if (config?.id) { - await api.updatePipelineConfig(config.id, data) - } else { - await api.createPipelineConfig(data) - } - - onSave() - } catch (e) { - setError(e.message) - } finally { - setLoading(false) - } - } - - const addStage1Prompt = (slug) => { - if (slug && !stage1Prompts.includes(slug)) { - setStage1Prompts(prev => [...prev, slug]) - } - } - - const removeStage1Prompt = (slug) => { - setStage1Prompts(prev => prev.filter(s => s !== slug)) - } - - // Filter prompts: only pipeline-type prompts - const pipelinePrompts = availablePrompts.filter(p => - p.slug && p.slug.startsWith('pipeline_') && p.slug !== 'pipeline_synthesis' && p.slug !== 'pipeline_goals' - ) - - const synthesisPrompts = availablePrompts.filter(p => - p.slug && (p.slug === 'pipeline_synthesis' || p.slug.includes('synthesis')) - ) - - const goalsPrompts = availablePrompts.filter(p => - p.slug && (p.slug === 'pipeline_goals' || p.slug.includes('goals') || p.slug.includes('ziele')) - ) - - return ( -
-
-
-

- {config ? 'Pipeline-Konfiguration bearbeiten' : 'Neue Pipeline-Konfiguration'} -

- -
- - {error && ( -
- {error} -
- )} - - {/* Basic Info */} -
-
- - setName(e.target.value)} - placeholder="z.B. Alltags-Check" - style={{width:'100%', textAlign:'left'}} - /> -
- -
- -