--- phase: 02-prompt-control-output-review plan: 01 subsystem: prompt-management tags: [fastapi, react, crud, prompt-editor, tanstack-query] dependency_graph: requires: - 01-02 (PromptService with load/save/list/variables/exists methods) - 01-04 (Web UI with stone/amber palette, Sidebar, Layout, routing) provides: - Prompt CRUD API (4 endpoints: list, read, write, reset) - Prompt Editor UI page with live variable extraction affects: - 02-02 (Output Review enhancement may reference prompt editing) - Future phases that add new prompt types tech_stack: added: [] patterns: - Lazy PromptService init for directory lifecycle sync - Default vs modified comparison for prompt versioning - Client-side regex for live variable extraction key_files: created: - backend/routers/prompts.py - frontend/src/pages/PromptEditor.tsx modified: - backend/main.py - frontend/src/types.ts - frontend/src/api/hooks.ts - frontend/src/App.tsx - frontend/src/components/Sidebar.tsx decisions: - id: prompt-lazy-init decision: "PromptService initialized lazily via _get_prompt_service() instead of module-level" reason: "PROMPTS_PATH directory is created during FastAPI lifespan, not at import time. Module-level init would fail with FileNotFoundError during import." date: 2026-03-08 metrics: duration: ~5 min completed: 2026-03-08 --- # Phase 02 Plan 01: Prompt CRUD + Prompt Editor UI Summary **PromptService CRUD completo con 4 endpoint FastAPI e pagina React Prompt Editor con lista, textarea monospace, variabili live, salva e reset al default.** ## What Was Done ### Task 1: Backend prompts router (4 CRUD endpoints) Created `backend/routers/prompts.py` with `APIRouter(prefix="/api/prompts", tags=["prompts"])`: - **GET /api/prompts** — Lists all `.txt` prompts with `modified` flag (compares runtime vs default in `backend/data/prompts/`) - **GET /api/prompts/{name}** — Returns content, required variables, and modified flag - **PUT /api/prompts/{name}** — Saves modified content with min_length=10 validation, returns updated variables - **POST /api/prompts/{name}/reset** — Restores default content from `backend/data/prompts/`, returns 404 if no default exists Key implementation detail: PromptService is lazily initialized via `_get_prompt_service()` because `PROMPTS_PATH` is created during FastAPI's lifespan event, not at module import time. Router registered in `main.py` before the SPA catch-all mount. ### Task 2: Frontend Prompt Editor (page, hooks, types, route, sidebar) - **Types**: Added `PromptInfo`, `PromptListResponse`, `PromptDetail` to `types.ts` - **Hooks**: Added `usePromptList`, `usePrompt`, `useSavePrompt`, `useResetPrompt` to `hooks.ts` with TanStack Query cache invalidation - **Page**: Created `PromptEditor.tsx` with two-column layout (1/3 list, 2/3 editor on lg, stacked on mobile) - Prompt list with amber "Modificato" / stone "Default" badges - Monospace textarea (min-height 400px, stone-900 bg) - Live client-side variable extraction via regex `{{nome}}` - Save button (amber, disabled when not dirty) - Reset to Default with inline confirmation dialog - Success/error feedback inline - **Route**: `/prompt-editor` added in `App.tsx` - **Sidebar**: "Prompt Editor" nav item with `Pencil` icon, positioned after "Genera Singolo Post" and before "Impostazioni" ## Deviations from Plan ### Auto-fixed Issues **1. [Rule 3 - Blocking] Lazy PromptService initialization** - **Found during:** Task 1 - **Issue:** Module-level `PromptService(PROMPTS_PATH)` raised `FileNotFoundError` because `PROMPTS_PATH` directory doesn't exist at import time — it's created in the FastAPI lifespan event. - **Fix:** Changed to lazy initialization via `_get_prompt_service()` function with `PROMPTS_PATH.mkdir(parents=True, exist_ok=True)` on first access. - **Files modified:** `backend/routers/prompts.py` - **Commit:** 05972fa ## Verification - [x] Backend imports without errors: `from backend.routers.prompts import router` OK - [x] 4 routes registered: `/api/prompts/`, `/api/prompts/{name}`, `/api/prompts/{name}`, `/api/prompts/{name}/reset` - [x] `main.py` includes `app.include_router(prompts.router)` before SPA catch-all - [x] TypeScript compiles with `npx tsc --noEmit` — zero errors - [x] Route `/prompt-editor` in App.tsx - [x] Sidebar contains "Prompt Editor" nav link - [x] Types and hooks exported correctly ## Next Phase Readiness Plan 02-01 is complete. The Prompt Editor is functional for CRUD operations on prompt files. Plan 02-02 can proceed independently (Output Review enhancements).