Properties
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_INFOstarts with/admin, handle it; otherwise pass through. - Plain JSON responses —
json.dumps()withContent-Type: application/json, not Flask. - Ownership enforcement — delete, token regen, and ACL grant/revoke require
role=ownerin ACL table. - Tier limits —
wiki_count >= wiki_limitcheck 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_repofails, DB records are rolled back. - wiki_id format —
{owner_id}:{wiki_slug}(consistent with ACL model). - MCP endpoint — returns
/{slug}/mcpfor now (no username mapping yet).
Integration notes
To wire into the Lambda handler, wrap the otterwiki WSGI app:
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