# Routes | Route | Screen | Query | API | |---|---|---|---| | /settings | Settings (Version, Media card, Media cleanup, Retention) | none | GET/PATCH /v1/media/purge-settings, GET/PATCH /v1/settings | | /settings/media/variants | Image variants (admin) | none | GET/PATCH/DELETE /v1/image-variants, POST /v1/image-variants/{name}/purge | | /settings/media/cache | Cache (admin) | none | GET /v1/image-variants/cache, POST /v1/image-variants/cache/purge {scope: all|unused|variant|image} | | /media | Media library | page, size, q, filter, sort, view | GET /v1/media/?page=&size=&q=&filter=&variants=&sort= (page, size; total in the `X-Total-Count` header) | | /media (detail) | Variants tab | none | GET /v1/media/{id}/variants, POST and DELETE /v1/media/{id}/variants/{name} | | /articles | Articles list | page, size, tab, q | GET /v1/article/?page=&size=&q=&status= (page, size; total in the `X-Total-Count` header; array body unchanged) | | /activity | Activity | q, actor, category, outcome, security, range, from, to, page, size | GET /v1/activity (page, size), GET /v1/activity/export (shipped, CSV) | | /integration | Integration | none | none | | /integration/api-keys | API keys | none | GET/POST /v1/api-key, DELETE /v1/api-key/{id} | ## Pagination in the URL (Articles, Media) `/articles?page=2&size=50` and `/media?page=7&size=50`. Parameter names follow the repo (activity already uses `page` and `size`). Allowed sizes 5, 25, 50, 100. Defaults `page=1`, `size=25`, omitted from the URL when default. Changing search, tab, filter or size resets `page` to 1. `page` above the last page redirects (replace) to the last page and shows "That page doesn't exist. Showing the last page." An invalid `size` falls back to 25. **API:** `GET /v1/article/` accepts `page` (default 1) and `size` (5, 25, 50, 100; default 25), as `GET /v1/activity` does. The body stays a JSON array so existing consumers keep working; the total comes back in `X-Total-Count` (the response shape is to be confirmed with the specifier). Anonymous callers only see online articles, and the total counts only those. Invalid `page` or `size` answers 400, the same as Activity. **Media API:** `GET /v1/media/` takes the same `page` and `size`, with the same 400 and the total in `X-Total-Count`; the array body stays. The earlier `cursor` and `limit` parameters are replaced by them. **Page size memory:** the size chosen on Articles, Activity or Media is remembered for the user and used when the URL has no `size`; an explicit `size` in the URL wins. **SPA:** never shows that 400. A `size` outside 5, 25, 50, 100 or a `page` that is not a positive integer is replaced in the URL by the default (`history.replace`), silently. A `page` past the last page is replaced by the last page and the notice "That page doesn't exist. Showing the last page." appears. ## Activity pagination `page` and `size`, allowed sizes 5, 25, 50, 100, default 25 (as implemented). ## Activity export `GET /v1/activity/export`: implemented. CSV only, synchronous (one streamed download, no job, no progress, no later notification). Accepts the list filters q, actor, category, outcome, security, range, from, to. Owner and admin only; others get 403. "Export current view" calls it with the active filters. "Export all activity" calls it with no filters and an optional `from`/`to` range. JSON (`format=json`) is **proposed**: new backend feature. ## Public image request `/media/photo.png?v=`. Unknown or disabled variant: 400 `{ "status": 400, "error": "unknown_variant", "message": "Unknown variant", "detail": "" }`. Any other query parameter: 400 `{ "status": 400, "error": "unsupported_parameter", "message": "Unsupported parameter", "detail": "" }`. Missing source image: 404.