Blame

bb6858 Claude (MCP) 2026-03-15 04:46:05
[mcp] Document V1-1/V1-2 SQLite port summary
1
---
2
category: reference
3
tags:
4
- robot.wtf
5
- v1
6
- sqlite
7
- data-access
8
last_updated: 2026-03-15
9
confidence: high
10
---
11
12
# V1-1/V1-2: SQLite Data Access Layer & TenantResolver Port
13
14
## Summary
15
16
Ported the DynamoDB-backed data models, auth middleware, TenantResolver, and ManagementMiddleware from wikibot-io to robot.wtf using SQLite as the storage backend. Identity model changed from OAuth provider sub to ATProto DID.
17
18
**Branch:** `feat/v1-sqlite-port` in the robot.wtf repo
19
**Commit:** `9861a0b`
20
**Tests:** 55/55 passing
21
22
## Files Created (21 total)
23
24
### Data Access Layer
25
| File | Description |
26
|------|-------------|
27
| `app/db.py` | SQLite connection factory (WAL mode, foreign keys, configurable via `ROBOT_DB_PATH`) |
28
| `app/models/user.py` | UserModel: CRUD by DID, get_by_username, set_username with validation |
29
| `app/models/wiki.py` | WikiModel: CRUD by slug, list_by_owner, scan_by_token (bcrypt) |
30
| `app/models/acl.py` | AclModel: CRUD by (wiki_slug, grantee_did), list_by_wiki, upsert semantics |
31
32
### Auth
33
| File | Description |
34
|------|-------------|
35
| `app/auth/jwt.py` | PlatformJWT: RS256 sign/verify, issuer/audience = "robot.wtf" |
36
| `app/auth/permissions.py` | Role-to-permission mapping (owner/editor/viewer) |
37
| `app/auth/headers.py` | Proxy header construction for otterwiki |
38
| `app/auth/acl.py` | AclEnforcer: check_access, check_public_access, check_bearer_token |
39
| `app/auth/middleware.py` | AuthMiddleware: JWT from header or cookie, user resolution |
40
41
### WSGI Middleware
42
| File | Description |
43
|------|-------------|
44
| `app/resolver.py` | TenantResolver: Host header → wiki slug, auth, ACL, storage swap (otterwiki stubbed) |
45
| `app/management/routes.py` | ManagementMiddleware: `/api/*` routes for wiki CRUD, ACL, token management |
46
| `app/management/token.py` | MCP bearer token generation (secrets + bcrypt) |
47
48
### Tests
49
| File | Tests |
50
|------|-------|
51
| `tests/conftest.py` | Shared fixtures: in-memory SQLite, model instances, sample data |
52
| `tests/test_models.py` | 35 tests: all CRUD ops, constraints, FK enforcement, bcrypt token scan |
53
| `tests/test_auth.py` | 20 tests: JWT round-trip, expiry, wrong key, permissions, ACL enforcer, auth middleware |
54
55
## Key Schema Differences from wikibot-io
56
57
| Aspect | wikibot-io | robot.wtf |
58
|--------|-----------|-----------|
59
| User PK | UUID | ATProto DID (text) |
60
| Wiki PK | (owner_id, wiki_slug) composite | slug only |
61
| ACL PK | (wiki_id, grantee_id) where wiki_id = "owner:slug" | (wiki_slug, grantee_did) |
62
| Identity | OAuth provider + sub | ATProto DID + handle |
63
| Storage | DynamoDB + boto3 | SQLite + sqlite3 stdlib |
64
| API prefix | `/admin/*` | `/api/*` |
65
| JWT issuer | wikibot.io | robot.wtf |
66
| Tier/billing | Yes | No |
67
68
## Architecture Notes
69
70
- **No boto3/DynamoDB references** anywhere in the codebase
71
- **otterwiki imports are conditional** in resolver.py — uses try/except ImportError with stubs
72
- **ManagementMiddleware** auth callback returns 501 (ATProto OAuth not yet implemented)
73
- **TenantResolver** extracts wiki slug from subdomain directly (not username+path like wikibot-io)
74
- **Foreign keys enforced** — wiki requires valid owner_did, ACL requires valid wiki_slug and grantee_did