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
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9