3.7 KiB
3.7 KiB
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.jsonstores all metadata in a single JSON file- No database involved
meta.json Format
{
"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)
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 categoryGET /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 onlyGET /api/service/canvas/{slug}— Get own draftPOST /api/service/canvas— Create draftPATCH /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 formPOST /admin/new— Create canvasGET /admin/edit/{slug}— Edit formPOST /admin/edit/{slug}— Save editsPOST /admin/toggle-draft— Toggle draft status (publish/unpublish)POST /admin/delete— Delete canvas
Auth Flow (Admin)
- Login at
auth.ephron.ren/api/loginwith form data (username+password) - Response sets
ephron_authcookie on.ephron.rendomain - Admin routes check cookie via
is_authenticated() - CSRF token required for all POST forms (generated per-request)
iframe Embedding Issue
The /view/{slug} page uses <iframe src="/raw/{slug}"> to display canvas content.
The shared security_headers.py middleware blocks iframe embedding with X-Frame-Options: DENY and frame-ancestors 'none'.
Solution: Override headers in the /raw/{slug} route handler:
headers={
"X-Frame-Options": "SAMEORIGIN",
"Content-Security-Policy": "...frame-ancestors 'self'...",
}
Source Files
canvas/src/routes/pages.py— Public page routescanvas/src/routes/service_api.py— Service API (Bearer Token)canvas/src/routes/admin.py— Admin routes (Cookie auth)canvas/src/services/canvas.py— Core service (storage, CRUD, categories)canvas/src/services/auth.py— Auth helperscanvas/src/config.py— Config (CONTENT_DIR, COOKIE_NAME, etc.)shared/security_headers.py— Shared security middleware