Files
agent-skills/content-ops/content-ops-agent/references/canvas-service-architecture.md
Hermes Agent ccc63d1e70 first commit
2026-05-10 13:52:46 +08:00

113 lines
3.7 KiB
Markdown

# 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 `<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:
```python
headers={
"X-Frame-Options": "SAMEORIGIN",
"Content-Security-Policy": "...frame-ancestors 'self'...",
}
```
## Source Files
- `canvas/src/routes/pages.py` — Public page routes
- `canvas/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 helpers
- `canvas/src/config.py` — Config (CONTENT_DIR, COOKIE_NAME, etc.)
- `shared/security_headers.py` — Shared security middleware