# Canvas Service Architecture ## Overview Canvas is an HTML tool showcase platform at `canvas.ephron.ren`. Unlike Blog (markdown files) and Prompt (SQLite), Canvas uses a **file-based storage** system. ## Storage Structure ``` content/pages/ ├── meta.json # Metadata for all pages ├── slug-1.html # HTML content files ├── slug-2.html └── .gitkeep ``` - Each canvas is a standalone HTML file (filename = slug) - `meta.json` stores all metadata in a single JSON file - No database involved ## meta.json Format ```json { "pages": { "hermes-agent-ai": { "title": "Hermes Agent — 自我进化的 AI 智能体", "description": "介绍页", "source": "other", "category": "tool", "tags": ["AI", "Agent"], "draft": false, "created_at": "2026-05-06T00:00:00", "updated_at": "2026-05-06T00:00:00", "created_by": "svc_xxx", "updated_by": "svc_xxx", "ownership_type": "service", "handoff_to_human": false, "views": 42 } } } ``` ## Valid Categories (hardcoded) ```python CANVAS_CATEGORIES = [ ("tool", "🔧 实用工具"), ("game", "🎮 小游戏"), ("visual", "🎨 可视化"), ("learning", "📚 学习教育"), ("productivity", "⚡ 效率提升"), ("fun", "🎉 趣味娱乐"), ("other", "📦 其他"), ] ``` Source: `canvas/src/services/canvas.py` lines 624-632. ## Route Structure | Route file | Auth | Purpose | |------------|------|---------| | `pages.py` | None (public) | Homepage list, view page, raw HTML | | `service_api.py` | Bearer Token | Draft CRUD only | | `admin.py` | Cookie (ephron_auth) | Full CRUD + publish toggle | ## Key Endpoints ### Public (no auth) - `GET /` — Homepage, shows non-draft canvases grouped by category - `GET /view/{slug}` — View page with iframe embedding `/raw/{slug}` - `GET /raw/{slug}` — Raw HTML content (iframe src target) ### Service API (Bearer Token) - `GET /api/service/canvas` — List own drafts only - `GET /api/service/canvas/{slug}` — Get own draft - `POST /api/service/canvas` — Create draft - `PATCH /api/service/canvas/{slug}` — Update own draft (fails if published) - `DELETE /api/service/canvas/{slug}` — Delete own draft ### Admin (Cookie auth) - `GET /admin` — Admin dashboard with all canvases (incl. drafts) - `GET /admin/new` — New canvas form - `POST /admin/new` — Create canvas - `GET /admin/edit/{slug}` — Edit form - `POST /admin/edit/{slug}` — Save edits - `POST /admin/toggle-draft` — Toggle draft status (publish/unpublish) - `POST /admin/delete` — Delete canvas ## Auth Flow (Admin) 1. Login at `auth.ephron.ren/api/login` with form data (`username` + `password`) 2. Response sets `ephron_auth` cookie on `.ephron.ren` domain 3. Admin routes check cookie via `is_authenticated()` 4. CSRF token required for all POST forms (generated per-request) ## iframe Embedding Issue The `/view/{slug}` page uses `