Blame

154727 Claude (Dev) 2026-03-13 02:04:02
[mcp] Clarify wiki documentation acceptance criteria
1
---
c8a262 Claude (Dev) 2026-03-13 01:50:52
[mcp] Port Phase 2 tasks to wiki
2
## How to read this document
3
4
- **Dependencies** list task IDs that must be complete before this task starts
5
- **Parallel group** identifies tasks that can run simultaneously within a phase
6
- **Target** identifies which repo and branch the work goes into
7
- Tasks are numbered `P{phase}-{sequence}` (e.g., P0-3)
8
- Acceptance criteria are binary — pass or fail, no judgment calls
9
10
---
11
12
## Phase 2: Multi-Tenancy and Auth
13
14
**Goal:** Multiple users, multiple wikis, ACL enforcement. Management API and CLI.
15
16
### P2-1: DynamoDB Tables
17
18
**Parallel group:** Phase 2 start (parallel with P2-6, P2-8)
19
**Dependencies:** P0-1 (VPC with DynamoDB gateway endpoint)
20
**Target:** `wikibot-io` repo, `feat/P2-1-dynamodb`
21
22
**Description:**
23
Create DynamoDB tables for Users, Wikis, and ACLs as specified in the PRD data model. Include GSIs for lookup patterns: user by OAuth provider+sub, wikis by owner, ACLs by wiki.
24
25
**Deliverables:**
26
- `infra/components/dynamodb.py` — table definitions with GSIs
27
- `app/models/user.py`, `app/models/wiki.py`, `app/models/acl.py` — data access layer
28
- Unit tests with moto: CRUD operations, GSI queries, conditional writes
29
30
**Acceptance criteria:**
31
- [ ] Users table: create, read, update by ID; lookup by (oauth_provider, oauth_provider_sub)
32
- [ ] Wikis table: create, read, update, delete by (owner_id, wiki_slug); list by owner
33
- [ ] ACLs table: create, read, delete by (wiki_id, grantee_id); list by wiki
34
- [ ] PITR enabled on all tables
35
- [ ] Unit tests pass with moto
36
- [ ] Integration test: CRUD against real DynamoDB
37
38
---
39
40
### P2-2: Auth Middleware
41
42
**Parallel group:** Phase 2 (parallel with P2-1)
43
**Dependencies:** P0-6 (WorkOS setup)
44
**Target:** `wikibot-io` repo, `feat/P2-2-auth-middleware`
45
46
**Description:**
47
Platform authentication middleware that handles two token flows:
48
49
1. **Browser/API — Platform JWT:** Validate JWTs signed with our RS256 key. Key stored in Pulumi config (dev) or Secrets Manager (prod). Middleware extracts user identity from JWT claims.
50
2. **MCP — WorkOS access token:** Validate against WorkOS JWKS. FastMCP integration handles this for MCP routes.
51
52
Both flows resolve to a User record in DynamoDB. The middleware sets a request-local user context for downstream handlers.
53
54
Also implement the platform JWT issuance: `/auth/token` endpoint that exchanges a WorkOS auth code for a platform JWT.
55
56
**Deliverables:**
57
- `app/auth/middleware.py` — JWT validation, user resolution
58
- `app/auth/jwt.py` — JWT creation and validation (RS256)
59
- `app/auth/workos.py` — WorkOS integration (auth code exchange, user profile retrieval, raw provider sub storage)
60
- Unit tests with mocked WorkOS and mocked JWT validation
61
- Integration test: full auth flow (WorkOS → platform JWT → authenticated request)
62
63
**Acceptance criteria:**
64
- [ ] Valid platform JWT → request proceeds with user context
65
- [ ] Expired/invalid JWT → 401
66
- [ ] WorkOS access token validated against JWKS
67
- [ ] Auth code exchange returns platform JWT with correct claims
68
- [ ] User record created in DynamoDB on first login (with oauth_provider, oauth_provider_sub)
69
- [ ] Subsequent logins resolve to existing user record
70
- [ ] Unit tests pass
71
72
---
73
74
### P2-3: ACL Enforcement Middleware
75
76
**Parallel group:** Phase 2
77
**Dependencies:** P2-1, P2-2
78
**Target:** `wikibot-io` repo, `feat/P2-3-acl-middleware`
79
80
**Description:**
81
Authorization middleware that checks whether the authenticated user can access the requested wiki with the requested permission level. Resolves wiki from URL path, looks up ACL in DynamoDB, maps ACL role to Otterwiki permission headers.
82
83
Handles public wikis: injects synthetic anonymous user with READ permission.
84
85
**Deliverables:**
86
- `app/auth/acl.py` — ACL lookup, role-to-permission mapping, public wiki handling
87
- `app/auth/permissions.py` — permission header injection for Otterwiki PROXY_HEADER mode
88
- Unit tests with moto: all role mappings, public wiki access, no-grant rejection
89
90
**Acceptance criteria:**
91
- [ ] Owner → READ, WRITE, UPLOAD, ADMIN headers
92
- [ ] Editor → READ, WRITE, UPLOAD headers
93
- [ ] Viewer → READ header
94
- [ ] No grant + private wiki → 403
95
- [ ] No grant + public wiki → READ (synthetic anonymous user)
96
- [ ] Invalid wiki slug → 404
97
- [ ] ACL lookup uses DynamoDB, not hardcoded
98
99
---
100
101
### P2-4: Management API
102
103
**Parallel group:** Phase 2
104
**Dependencies:** P2-1, P2-3
105
**Target:** `wikibot-io` repo, `feat/P2-4-management-api`
106
107
**Description:**
108
REST API for wiki lifecycle management. Authenticated via platform JWT. Endpoints as specified in the PRD's Management API section.
109
110
On wiki creation: initialize bare git repo on EFS, populate with bootstrap template, create DynamoDB records, generate MCP bearer token (bcrypt hash stored, plaintext returned once).
111
112
**Deliverables:**
113
- `app/management/routes.py` — all management endpoints
114
- `app/management/wiki_init.py` — repo initialization and template population
115
- `app/management/token.py` — bearer token generation and hashing
116
- Unit tests with moto + `/tmp` filesystem
117
- Integration test: create wiki, list wikis, delete wiki
118
119
**Acceptance criteria:**
120
- [ ] `POST /admin/wikis` creates wiki (EFS repo + DynamoDB records + bootstrap template)
121
- [ ] `GET /admin/wikis` lists caller's wikis
122
- [ ] `GET /admin/wikis/{slug}` returns wiki details with MCP endpoint URL
123
- [ ] `DELETE /admin/wikis/{slug}` removes repo and records
124
- [ ] `POST /admin/wikis/{slug}/token` regenerates bearer token
125
- [ ] `POST /admin/wikis/{slug}/acl` grants access (by email)
126
- [ ] `DELETE /admin/wikis/{slug}/acl/{user_id}` revokes access
127
- [ ] `GET /admin/wikis/{slug}/acl` lists grants
128
- [ ] Tier limits enforced (1 wiki free, 500 pages, 3 collaborators)
129
- [ ] Bearer token shown once on create, stored as bcrypt hash
130
131
---
132
133
### P2-5: Per-Wiki Routing
134
135
**Parallel group:** Phase 2
136
**Dependencies:** P1-7, P2-3
137
**Target:** `wikibot-io` repo, `feat/P2-5-wiki-routing`
138
139
**Description:**
140
Multi-tenant URL routing: `{username}.wikibot.io/{wiki}/` routes to the correct wiki instance. API Gateway with wildcard subdomain (`*.wikibot.io`). Lambda resolver extracts username and wiki slug from the request, loads wiki config from DynamoDB, sets up Otterwiki with the correct EFS repo path.
141
142
**Deliverables:**
143
- API Gateway wildcard domain configuration
144
- `app/routing/resolver.py` — extract user + wiki from hostname + path, load wiki config
145
- ACM wildcard certificate for `*.wikibot.io`
146
- Route 53 wildcard DNS record
147
- Integration test: requests to different subdomains resolve to different wikis
148
149
**Acceptance criteria:**
150
- [ ] `user1.wikibot.io/wiki1/` → user1's wiki1
151
- [ ] `user1.wikibot.io/wiki1/api/v1/health` → wiki1's API
152
- [ ] `user1.wikibot.io/wiki1/mcp` → wiki1's MCP endpoint
153
- [ ] `user2.wikibot.io/wiki2/` → user2's wiki2
154
- [ ] Nonexistent user/wiki → 404
155
- [ ] Wildcard TLS works
156
157
---
158
159
### P2-6: Wiki Bootstrap Template
160
161
**Parallel group:** Phase 2 start (independent, can start immediately)
162
**Dependencies:** None
163
**Target:** `wikibot-io` repo, `feat/P2-6-bootstrap-template`
164
165
**Description:**
166
Create the starter page set that new wikis are initialized with. Parameterized by wiki name, purpose, and category set. Reference the Third Gulf War `Meta/Wiki Usage Guide` (read via MCP) as the exemplar for structure and tone, but generalize for any research domain.
167
168
**Deliverables:**
169
- `app/templates/wiki/Home.md` — parameterized landing page
170
- `app/templates/wiki/Meta/Wiki Usage Guide.md` — tool reference, session protocol, conventions
171
- `app/templates/wiki/Meta/Page Template.md` — reference page showing frontmatter and structure
172
- `app/management/template.py` — template engine (string substitution for wiki name, purpose, categories)
173
- Unit tests: template rendering with various parameters
174
175
**Acceptance criteria:**
176
- [ ] Template renders correctly with wiki name and purpose substituted
177
- [ ] Wiki Usage Guide covers all MCP tools, session protocol, frontmatter schema, WikiLink syntax, page size guidance, gardening
178
- [ ] Page Template shows correct frontmatter format
179
- [ ] Default category set matches PRD (actor, event, trend, hypothesis, variable, reference, index)
180
- [ ] Template is generic — no Third Gulf War specific content
181
182
---
183
184
### P2-7: Otterwiki PROXY_HEADER Integration
185
186
**Parallel group:** Phase 2
187
**Dependencies:** P2-3
188
**Target:** `otterwiki` fork, PR to `main` (if changes needed); `wikibot-io` for config
189
190
**Description:**
191
Configure Otterwiki to run in `PROXY_HEADER` auth mode, reading user identity and permissions from headers set by the ACL middleware (P2-3). Verify that all permission levels work correctly: admin sees admin panel, editors can edit, viewers can only read.
192
193
**Deliverables:**
194
- Otterwiki configuration for PROXY_HEADER mode
195
- Verification that header-based auth works with all permission levels
196
- Any needed patches to Otterwiki's PROXY_HEADER handling (upstream PR if changes required)
197
198
**Acceptance criteria:**
199
- [ ] `x-otterwiki-email`, `x-otterwiki-name`, `x-otterwiki-permissions` headers → correct user context
200
- [ ] ADMIN permission → admin panel accessible
201
- [ ] WRITE permission → can edit pages
202
- [ ] READ permission → can view but not edit
203
- [ ] No permission headers → rejected (defense in depth)
204
205
---
206
207
### P2-8: Admin Panel Hiding
208
209
**Parallel group:** Phase 2 start (independent)
210
**Dependencies:** None
211
**Target:** `otterwiki` fork, `wikibot/prod` branch
212
213
**Description:**
214
Hide admin panel sections that conflict with platform-managed settings: Repository Management, Permissions and Registration, User Management, Mail Preferences. Keep Application Preferences, Sidebar Preferences, Content and Editing.
215
216
Override the admin navigation template to hide disabled sections. Return 404 from disabled routes in middleware.
217
218
**Deliverables:**
219
- Modified `templates/settings.html` — conditionally render nav items based on config flag
220
- Middleware/decorator on disabled routes returning 404
221
- Config flag: `PLATFORM_MODE=true` enables hiding (off by default — doesn't affect standalone Otterwiki)
222
- Tests: disabled routes return 404, enabled routes work normally
223
224
**Acceptance criteria:**
225
- [ ] With `PLATFORM_MODE=true`: disabled sections hidden from nav, routes return 404
226
- [ ] With `PLATFORM_MODE=false` (or unset): all sections visible (backward compatible)
227
- [ ] Enabled sections (Application Preferences, Sidebar Preferences, Content and Editing) work normally in both modes
228
- [ ] Existing test suite passes
229
230
---
231
232
### P2-9: CLI Tool
233
234
**Parallel group:** Phase 2
235
**Dependencies:** P2-4
236
**Target:** `wikibot-io` repo, `feat/P2-9-cli`
237
238
**Description:**
239
Command-line tool for wiki management. Calls the Management API. Used as the MVP frontend before the SPA is built.
240
241
**Deliverables:**
242
- `app/cli/wiki.py` — CLI commands using `click` or `typer`
243
- Commands: `wiki create`, `wiki list`, `wiki delete`, `wiki token`, `wiki grant`, `wiki revoke`
244
- Auth: stores platform JWT in `~/.wikibot/token` after login flow
245
- Unit tests with mocked HTTP
246
247
**Acceptance criteria:**
248
- [ ] `wiki create <slug> <name>` creates wiki, displays MCP token and connection instructions
249
- [ ] `wiki list` shows user's wikis with page counts
250
- [ ] `wiki delete <slug>` deletes wiki (with confirmation prompt)
251
- [ ] `wiki token <slug>` regenerates and displays MCP bearer token
252
- [ ] `wiki grant <slug> <email> <role>` grants access
253
- [ ] `wiki revoke <slug> <email>` revokes access
254
- [ ] Login flow works (opens browser for OAuth, receives callback)
255
256
---
257
258
### P2-10: Phase 2 E2E Test
259
260
**Parallel group:** Phase 2 (final)
261
**Dependencies:** All P2 tasks
262
**Target:** `wikibot-io` repo, `feat/P2-10-e2e`
263
264
**Description:**
265
End-to-end test: two users, two wikis, ACL enforcement. Verify complete isolation between tenants.
266
267
**Deliverables:**
268
- `tests/e2e/test_phase2.py`
154727 Claude (Dev) 2026-03-13 02:04:02
[mcp] Clarify wiki documentation acceptance criteria
269
- Results written to Dev/Phase 2 Summary per Agent Conventions documentation loop
c8a262 Claude (Dev) 2026-03-13 01:50:52
[mcp] Port Phase 2 tasks to wiki
270
271
**Acceptance criteria:**
272
- [ ] User A creates wiki, writes a page → User B cannot read it (403)
273
- [ ] User A grants User B editor access → User B can read and write
274
- [ ] User A revokes access → User B gets 403 again
275
- [ ] User A's wiki is completely invisible to User B (not in list, not in search)
276
- [ ] Public wiki toggle: User B can read (but not write) User A's public wiki without a grant
277
- [ ] MCP access respects same ACL rules
278
- [ ] Tier limits enforced: free user cannot create a second wiki