Add curator roles/permissions with Users admin, and fix lineage branch joins.
Staff accounts use admin/curator roles and fine-grained flags; transitions connect source-to-target with color gradients and stream cutout masks so overlaps stay seamless. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
bfa21989c9
commit
0466b77328
+57
-24
@@ -30,7 +30,7 @@ curl.exe -sk https://devgallery.mysuperlab.netcraze.pro/api/bounds
|
||||
|
||||
## Authentication
|
||||
|
||||
Anonymous visitors have implicit role **`user`** (browse only). **Curator** accounts unlock debug mode, the Checkup page, and all mutating audit routes.
|
||||
Anonymous visitors have implicit role **`user`** (browse only). Staff accounts in `users` are **`admin`** or **`curator`** with fine-grained **permissions**. Admins have all tools; curators only the flags assigned to them. Mutations are logged in `curator_audit_log` with `user_id`.
|
||||
|
||||
Sessions use an HTTP-only cookie (`gallery.sid`). The client sends `credentials: 'include'` on API requests.
|
||||
|
||||
@@ -42,19 +42,25 @@ Sessions use an HTTP-only cookie (`gallery.sid`). The client sends `credentials:
|
||||
{ "role": "user" }
|
||||
```
|
||||
|
||||
**Response (curator session)**
|
||||
**Response (staff session)**
|
||||
|
||||
```json
|
||||
{ "role": "curator", "username": "curator" }
|
||||
{
|
||||
"role": "admin",
|
||||
"username": "curator",
|
||||
"permissions": ["images", "checkup", "curator_notes", "translations", "influences", "tours", "users"]
|
||||
}
|
||||
```
|
||||
|
||||
`permissions` is the effective set (admins always receive the full list).
|
||||
|
||||
### `POST /api/auth/login`
|
||||
|
||||
**Body:** `{ "username": "curator", "password": "…" }`
|
||||
|
||||
**Response:** `{ "role": "curator", "username": "curator" }`
|
||||
**Response:** same shape as `/me` for staff (`role`, `username`, `permissions`).
|
||||
|
||||
**Errors:** `401` invalid credentials, `400` missing fields.
|
||||
**Errors:** `401` invalid credentials or disabled account, `400` missing fields.
|
||||
|
||||
### `POST /api/auth/logout`
|
||||
|
||||
@@ -62,30 +68,57 @@ Destroys the session cookie.
|
||||
|
||||
**Response:** `{ "ok": true }`
|
||||
|
||||
### Curator-only routes
|
||||
### Permission flags
|
||||
|
||||
These return **`401`** with `{ "error": "Curator login required" }` without a valid curator session:
|
||||
| Permission | Gates |
|
||||
|------------|--------|
|
||||
| `images` | Debug image/portrait fix/clear/upload/delete, debug search/proxy |
|
||||
| `checkup` | Checkup page + checkup flag patches |
|
||||
| `curator_notes` | `PATCH …/curator-notes` |
|
||||
| `translations` | `/api/translations/*` |
|
||||
| `influences` | `/api/influences/*` |
|
||||
| `tours` | Tour admin CRUD |
|
||||
| `users` | `/api/users/*` (Users page) |
|
||||
|
||||
| Route | Audit action (mutations only) |
|
||||
|-------|-------------------------------|
|
||||
| `GET /api/paintings/checkup` | — (read) |
|
||||
| `GET /api/paintings/:id/debug-image-search` (+ `/more`) | — |
|
||||
| `GET /api/artists/:id/debug-portrait-search` (+ `/more`) | — |
|
||||
| `GET /api/debug/image-proxy` | — |
|
||||
| `PATCH /api/paintings/:id/checkup-flags` | `painting.checkup_flags` |
|
||||
| `PATCH /api/paintings/:id/curator-notes` | `painting.update_curator_notes` |
|
||||
| `PATCH /api/artists/:id/checkup-flags` | `artist.checkup_flags` |
|
||||
| `POST /api/paintings/:id/fix-image` | `painting.fix_image` |
|
||||
| `POST /api/paintings/:id/clear-image` | `painting.clear_image` |
|
||||
| `POST /api/paintings/:id/upload-image` | `painting.upload_image` |
|
||||
| `DELETE /api/paintings/:id` | `painting.delete` |
|
||||
| `POST /api/artists/:id/fix-portrait` | `artist.fix_portrait` |
|
||||
| `POST /api/artists/:id/clear-portrait` | `artist.clear_portrait` |
|
||||
| `POST /api/artists/:id/upload-portrait` | `artist.upload_portrait` |
|
||||
Missing session → **`401`** `{ "error": "Curator login required" }`. Missing permission → **`403`** `{ "error": "Permission denied" }`.
|
||||
|
||||
### Users (admin / `users` permission)
|
||||
|
||||
| Method | Path | Notes |
|
||||
|--------|------|-------|
|
||||
| `GET` | `/api/users` | List users + known permission keys |
|
||||
| `POST` | `/api/users` | Create `{ username, password, role, permissions }` |
|
||||
| `PATCH` | `/api/users/:id` | Update `role`, `permissions`, `is_active` |
|
||||
| `POST` | `/api/users/:id/password` | Set new password; clears that user’s sessions |
|
||||
|
||||
Only **admins** can create or promote **admin** accounts. Cannot deactivate/demote the last active admin. Audit: `user.create`, `user.update`, `user.reset_password`.
|
||||
|
||||
### Staff-gated routes
|
||||
|
||||
| Route | Permission | Audit action (mutations only) |
|
||||
|-------|------------|-------------------------------|
|
||||
| `GET /api/paintings/checkup` | `checkup` | — (read) |
|
||||
| `GET /api/paintings/:id/debug-image-search` (+ `/more`) | `images` | — |
|
||||
| `GET /api/artists/:id/debug-portrait-search` (+ `/more`) | `images` | — |
|
||||
| `GET /api/debug/image-proxy` | `images` | — |
|
||||
| `PATCH /api/paintings/:id/checkup-flags` | `checkup` | `painting.checkup_flags` |
|
||||
| `PATCH /api/paintings/:id/curator-notes` | `curator_notes` | `painting.update_curator_notes` |
|
||||
| `PATCH /api/artists/:id/checkup-flags` | `checkup` | `artist.checkup_flags` |
|
||||
| `POST /api/paintings/:id/fix-image` | `images` | `painting.fix_image` |
|
||||
| `POST /api/paintings/:id/clear-image` | `images` | `painting.clear_image` |
|
||||
| `POST /api/paintings/:id/upload-image` | `images` | `painting.upload_image` |
|
||||
| `DELETE /api/paintings/:id` | `images` | `painting.delete` |
|
||||
| `POST /api/artists/:id/fix-portrait` | `images` | `artist.fix_portrait` |
|
||||
| `POST /api/artists/:id/clear-portrait` | `images` | `artist.clear_portrait` |
|
||||
| `POST /api/artists/:id/upload-portrait` | `images` | `artist.upload_portrait` |
|
||||
| `/api/translations/*` | `translations` | `translation.*` |
|
||||
| `/api/influences/*` | `influences` | `influence.*` |
|
||||
| Tour admin (`/api/tours/admin`, POST/PATCH/DELETE, stops) | `tours` | `tour.*` |
|
||||
| `/api/users/*` | `users` | `user.*` |
|
||||
|
||||
**Public** (no login): all catalog `GET` routes, `POST /api/artists/:id/preload-images` (local file linking for 3D halls), `/images`, SPA static.
|
||||
|
||||
Curator mutations are recorded in `curator_audit_log` (see [DB_structure.md](DB_structure.md)).
|
||||
Staff mutations are recorded in `curator_audit_log` with `user_id` (see [DB_structure.md](DB_structure.md)).
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user