SCRUM-200 — gateway_dev: admin-auth upstream, users route, viewer read gate¶
Plan ref: GWD-1 (docs/11-admin-plane-plan.md).
What changed¶
| Change | Where |
|---|---|
Upstream phpadmin → adminauth (env GATEWAY_DEV_UPSTREAM_ADMINAUTH_URL) |
services/gateway_dev/internal/router/dev.go, config, harnesses, .env.example, README |
/api/admin/config/ gate live_ops → viewer (Config re-checks writes per route). POST …/channels/live/releases stays admin |
dev.go |
New routes /api/admin/users and /api/admin/users/ → adminauth, admin minimum |
dev.go |
Compose: GATEWAY_DEV_UPSTREAM_ADMINAUTH_URL: ${ADMIN_AUTH_URL:-http://admin-auth:8080} |
deploy/compose.yaml, deploy/.env.example |
Docs: techspec route table; adminui router comment (UI config routes stay live_ops until SCRUM-252/253) |
docs/05-gateway-techspec.md, services/adminui/src/router/index.ts |
Why both users patterns: with only the subtree, Go 1.27's ServeMux answers
/api/admin/users with a 307 to /api/admin/users/ before auth runs, so an
anonymous caller would learn the route exists instead of getting a 401.
How to verify¶
1. Unit tests¶
Expected: all packages ok. The new table test is
internal/authn/middleware_test.go: TestRoutePolicyUnderRealMiddleware — the real
route table through the real middleware, 16 rows:
| Request | viewer | live_ops | admin |
|---|---|---|---|
GET /api/admin/config/namespaces |
200 → config | ||
PUT /api/admin/config/namespaces/x/draft |
200 → config (Config itself will 403) | ||
POST /api/admin/config/channels/live/releases |
403 | 403 | 200 → config |
POST /api/admin/config/channels/staging/releases |
200 → config | ||
GET /api/admin/users |
403 | 403 | 200 → adminauth |
POST /api/admin/users |
200 → adminauth | ||
PATCH /api/admin/users/{id} |
403 | 200 → adminauth | |
DELETE /api/admin/users/invites/42 |
200 → adminauth | ||
POST /admin-auth/login (no token) |
200 → adminauth | ||
GET /api/admin/dashboard/overview, GET /api/admin/session/players |
200 |
The test client refuses to follow redirects, so a 307 fails the row.
Mutation check (done during review): deleting the exact /api/admin/users
route made 4 rows fail with status = 307; lowering the users subtree to
RoleLiveOps failed the PATCH … as live_ops row. Both reverted.
2. Smoke test (real binaries, echo upstreams)¶
Every line prints -> <actual> [expect <expected>]; they should match. The ones
this ticket changed:
--- 13. the config prefix needs viewer ---
GET /api/admin/config/namespaces (viewer) -> 200 - upstream=config
--- 14b. staff account management is admin-only ... ---
GET /api/admin/users (viewer) -> 403 insufficient_role
GET /api/admin/users (live_ops) -> 403 insufficient_role
GET /api/admin/users (admin) -> 200 - upstream=adminauth [NOT 307]
POST /api/admin/users (admin) -> 200 - upstream=adminauth [NOT 307]
PATCH /api/admin/users/some-id (admin) -> 200 - upstream=adminauth
--- extra ---
GET /admin-auth/login -> 200 - upstream=adminauth
No line should start with FINDING.
3. By hand (optional)¶
Follow services/gateway_dev/testdata/manual/TESTING.md — the role table there now
includes the users row and the viewer config read.
Results at time of writing¶
go vet,go test -race: pass (gateway_dev, all packages).smoke.sh: all checks as expected, noFINDING.- adminui:
vue-tsc, eslint, prettier on the router file,guard.spec.ts(11 tests): pass. docker compose config: not run (no Docker on the dev box); YAML parses and the variable renders as written.
Deploy note¶
The host's stand-in auth container is named php-admin-auth. Before redeploying
gateway_dev there, set ADMIN_AUTH_URL=http://php-admin-auth:8080 in deploy/.env,
or /admin-auth/* returns 502 until admin-auth is in compose (SCRUM-240).