Commit 014939
2026-03-15 04:58:54 Claude (MCP): [mcp] Document V1-3 deployment deliverables| /dev/null .. Dev/V1-3_Deployment_Summary.md | |
| @@ 0,0 1,74 @@ | |
| + | --- |
| + | category: reference |
| + | tags: |
| + | - robot-wtf |
| + | - v1 |
| + | - deployment |
| + | last_updated: 2026-03-15 |
| + | --- |
| + | |
| + | # V1-3: Gunicorn Configuration, Systemd Units, and Deployment |
| + | |
| + | **Branch:** `feat/v1-3-gunicorn-systemd` in `robot.wtf` repo |
| + | **Commit:** `5eb51c6` |
| + | |
| + | ## Deliverables |
| + | |
| + | ### Entry Points (app/) |
| + | |
| + | | File | Service | Port | Server | Description | |
| + | |------|---------|------|--------|-------------| |
| + | | `wsgi.py` | Otterwiki | 8000 | Gunicorn | Wraps Flask app in TenantResolver + ManagementMiddleware. Stub when otterwiki not installed. | |
| + | | `api_server.py` | Platform API | 8002 | Gunicorn | ManagementMiddleware + `/api/internal/check-slug` for Caddy on-demand TLS + static file serving. | |
| + | | `auth_server.py` | Auth | 8003 | Gunicorn | ATProto OAuth stubs (501). Serves client-metadata.json, AS metadata, JWKS. | |
| + | | `mcp_entry.py` | MCP Sidecar | 8001 | Uvicorn | FastMCP stub (ASGI). Serves `/.well-known/oauth-protected-resource`. | |
| + | |
| + | ### Shared Configuration |
| + | |
| + | - `app/gunicorn.conf.py` — Bind from `GUNICORN_BIND` env var, workers = min(2*CPU+1, 4), timeout 30s, access log to stdout. |
| + | |
| + | ### Systemd Units (ansible/roles/deploy/files/) |
| + | |
| + | All services run as `robot` user, `WorkingDirectory=/srv/app/src`. |
| + | |
| + | - `robot-otterwiki.service` — Gunicorn, port 8000, MULTI_TENANT=true |
| + | - `robot-api.service` — Gunicorn, port 8002 |
| + | - `robot-auth.service` — Gunicorn, port 8003 |
| + | - `robot-mcp.service` — Uvicorn, port 8001 |
| + | |
| + | ### Ansible Deploy Role |
| + | |
| + | `ansible/roles/deploy/` with tasks + handlers: |
| + | - Syncs `app/` to `/srv/app/src/app/` via rsync |
| + | - Installs `requirements.txt` into `/srv/app/venv` |
| + | - Copies systemd units, enables and starts all four services |
| + | - Handlers restart services on code change |
| + | - **TODO:** otterwiki pip install from fork (placeholder comments) |
| + | |
| + | ### Requirements Added |
| + | |
| + | - `flask>=3.0.0` — needed by api_server, auth_server, wsgi stub |
| + | - `uvicorn>=0.29.0` — needed by MCP sidecar |
| + | |
| + | ## Environment Variables |
| + | |
| + | | Variable | Used By | Default | |
| + | |----------|---------|---------| |
| + | | MULTI_TENANT | wsgi.py | (unset = disabled) | |
| + | | ROBOT_DB_PATH | wsgi, api | /srv/data/robot.db | |
| + | | SIGNING_KEY_PATH | wsgi, api, auth | /srv/data/signing_key.pem | |
| + | | PLATFORM_DOMAIN | all | robot.wtf | |
| + | | WIKI_BASE | wsgi | /srv/data/wikis | |
| + | | GUNICORN_BIND | gunicorn.conf | 0.0.0.0:8000 | |
| + | | ROBOT_STATIC_DIR | api | /srv/static | |
| + | | MCP_PORT | mcp | 8001 | |
| + | |
| + | ## Testing |
| + | |
| + | - All 55 existing tests pass (no regressions) |
| + | - auth_server: stub routes return 501, metadata routes return 200 with valid JSON |
| + | - mcp_entry: ASGI stub serves oauth-protected-resource (200) and default (501) |
| + | - wsgi.py: loads stub Flask app when otterwiki not installed |
| + | - api_server: check-slug returns 404 for unknown domains/slugs |
| + | - Systemd units validated: correct User, WorkingDirectory, ExecStart, ports |
| + | - Ansible YAML validated: 7 tasks, 2 handlers |