docs(auth,users,devices,progress,matching): Beam batch 8 — WO5 backfill complete

14 endpoints backfilled: devices pending/approve/reject; users
password/profile/profile-delete self-service (admin variants in prose);
admin list_users + update_user_max_devices; progress history; book
matching; new password-rules doc.

Gate fix: authLabel missed JWT middleware written inline as
createJWTMiddleware(cfg) (uppercase 'JWT') — reported auth 'none' for
/api/auth self-service routes and would have for any wrapper-inlined
group. Labeled 'JWTMiddleware' + fallthrough 'jwt' case.

Claude registry: 12 entries. Drift fixed by gate: list_users on-device —
handler returns raw []database.Users (bare array, full model incl.
password_hash — real leak the API emits; pinned + documented; earlier
draft had invented {users,total,limit,offset} wrapper). max-devices
response is {message} only. books/match is GET /api/books/match
{matches, action}. progress history sessions = ReadingHistory rows
(pgtype fields). make test 9/9.
This commit is contained in:
John O'Keefe committed 2026-10-24 17:33:32 -04:00
1 parent 2c56ae4b9d
commit cc5677eb17
13 files changed
+233 -75

No files matched your search

+34 -21
View File
@@ -1,3 +1,11 @@
---
method: GET
path: /api/auth/users
auth: jwt+admin
area: authentication
---
<!-- source: internal/handlers/auth.go:734 AuthHandler.ListUsers -->
# List Users
List all users in the system (admin only).
@@ -28,29 +36,34 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
## Response (200 OK)
```json
{
"users": [
{
"id": "uuid",
"email": "user@example.com",
"username": "johndoe",
"first_name": "John",
"last_name": "Doe",
"role": "user",
"theme": "tokyo-night",
"max_devices": 10,
"device_count": 3,
"created_at": "2026-02-08T10:00:00Z",
"updated_at": "2026-02-08T10:00:00Z"
}
],
"total": 25,
"limit": 10,
"offset": 0
}
```json example-response
[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "user@example.com",
"username": "johndoe",
"password_hash": "$2a$04$REDACTED",
"first_name": "John",
"last_name": "Doe",
"role": "user",
"theme": "tokyo-night",
"max_devices": 10,
"created_at": "2026-02-08T10:00:00Z",
"timezone": "America/New_York",
"updated_at": "2026-02-08T10:00:00Z",
"default_audio_speed": 1
}
]
```
Response is a bare JSON array of full user rows — no pagination wrapper
and no `device_count` (those were invented in an earlier draft).
**Leak note:** the user model json-marshals `password_hash` verbatim —
the list-users response exposes password hashes to any admin caller.
Known defect, tracked separately (doc mirrors the real field set; do not
implement against a redacted shape).
### Response Fields
| Field | Type | Description |