Commit 19a9ac

2026-03-13 19:48:35 Claude (MCP): [mcp] P2-4: Management API summary
/dev/null .. Dev/P2-4_Summary.md
@@ 0,0 1,73 @@
+ ---
+ category: reference
+ tags:
+ - phase-2
+ - management-api
+ last_updated: 2026-03-13
+ ---
+
+ # P2-4: Management API
+
+ **Branch:** `feat/P2-4-management-api` (from `phase-2`)
+ **Commit:** `1e80a07`
+ **Tests:** 30 passing
+
+ ## What was built
+
+ WSGI middleware (`ManagementMiddleware`) that intercepts `/admin/*` requests before they reach the otterwiki Flask app. All routes require platform JWT authentication.
+
+ ## Files
+
+ | File | Purpose |
+ |------|---------|
+ | `app/management/routes.py` | WSGI middleware with 8 API endpoints |
+ | `app/management/wiki_init.py` | Git repo init + bootstrap template writer |
+ | `app/management/token.py` | MCP bearer token generation (secrets + bcrypt) |
+ | `app/models/user.py` | Added `get_by_email()` scan method |
+ | `tests/test_management_api.py` | 30 unit tests (moto + tmpdir) |
+
+ ## API Endpoints
+
+ | Method | Path | Description |
+ |--------|------|-------------|
+ | POST | `/admin/wikis` | Create wiki (repo init, bootstrap, ACL, token) |
+ | GET | `/admin/wikis` | List user's wikis |
+ | GET | `/admin/wikis/{slug}` | Wiki details + MCP endpoint |
+ | DELETE | `/admin/wikis/{slug}` | Delete wiki (repo, DB records, ACLs) |
+ | POST | `/admin/wikis/{slug}/token` | Regenerate MCP bearer token |
+ | POST | `/admin/wikis/{slug}/acl` | Grant access (body: `{email, role}`) |
+ | DELETE | `/admin/wikis/{slug}/acl/{grantee_id}` | Revoke access |
+ | GET | `/admin/wikis/{slug}/acl` | List ACL entries |
+
+ ## Design decisions
+
+ - **WSGI middleware pattern** — wraps the otterwiki app; if `PATH_INFO` starts with `/admin`, handle it; otherwise pass through.
+ - **Plain JSON responses** — `json.dumps()` with `Content-Type: application/json`, not Flask.
+ - **Ownership enforcement** — delete, token regen, and ACL grant/revoke require `role=owner` in ACL table.
+ - **Tier limits** — `wiki_count >= wiki_limit` check on create; count incremented/decremented atomically.
+ - **Token shown once** — plaintext returned only on create and regenerate; only bcrypt hash stored.
+ - **Repo cleanup on create failure** — if `init_wiki_repo` fails, DB records are rolled back.
+ - **wiki_id format** — `{owner_id}:{wiki_slug}` (consistent with ACL model).
+ - **MCP endpoint** — returns `/{slug}/mcp` for now (no username mapping yet).
+
+ ## Integration notes
+
+ To wire into the Lambda handler, wrap the otterwiki WSGI app:
+
+ ```python
+ from app.management.routes import ManagementMiddleware
+ wrapped = ManagementMiddleware(
+ otterwiki_wsgi_app,
+ auth_middleware=auth_middleware,
+ user_model=users,
+ wiki_model=wikis,
+ acl_model=acls,
+ )
+ handler = make_lambda_handler(wrapped)
+ ```
+
+ ## Not included (future work)
+
+ - Lambda handler wiring (will be done when all Phase 2 components integrate)
+ - Username-to-subdomain mapping for MCP endpoint URLs
+ - Rate limiting on wiki creation
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