Files
RenewCMS/docs/design/routes.md
T

6.3 KiB

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
/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
/settings/sites Sites (owner only; other roles get a 403 page and no sidebar entry): list, add and edit slide-over, delete with reassignment. The key is read-only after creation none GET/POST /v1/site/, PATCH/DELETE /v1/site/{id} (DELETE takes reassign_to)
/authors Authors, all roles. Owner and admin: list, search, add and edit slide-over, delete with reassignment. Other roles: read-only list and detail q, page, size GET/POST /v1/author/, PATCH/DELETE /v1/author/{id}, POST /v1/author/me
/articles Articles list gains Authors column; Site column and filter when more than one site site GET /v1/article/?site={key}
/article/:id/edit Editor gains the "Site and authors" section (Site select and authors, any role that can edit the article) none PATCH /v1/article/{id} {site_id, author_ids[]}
/profile Profile gains the "Author profile" card, all roles none POST /v1/author/me
/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=<variant-name>. Unknown or disabled variant: 400 { "status": 400, "error": "unknown_variant", "message": "Unknown variant", "detail": "<name>" }. Any other query parameter: 400 { "status": 400, "error": "unsupported_parameter", "message": "Unsupported parameter", "detail": "<parameter>" }. Missing source image: 404.

Sites and authors in the URL

/articles?site=journal filters by site key; it combines with page, size, tab and q, and resets page to 1 when it changes. An unknown key is dropped from the URL with no error. /authors?q=camille&page=2&size=25 follows the same pagination rules as Articles. Deep links: /authors?edit={slug} and /settings/sites?edit={key} open the slide-over for owner and admin (authors) and the owner (sites); an unknown value shows the info toast "That author no longer exists" or "That site no longer exists". For other roles /authors?edit={slug} opens the read-only detail, and /settings/sites and its ?edit= link show the 403 page "You don't have access to Sites".

Sites pagination: /settings/sites?q=&page=&size= with the same rules as Articles (sizes 5, 25, 50, 100; default 25; defaults omitted; search and size changes reset to page 1; a page past the end falls back to the last page). API: GET /v1/site/?q=&page=&size=, total in X-Total-Count (design assumption). Authors: /authors?q=&page=&size= as above.

SEO

No new page routes. The panel and dialog are overlays on /article/:id/edit: ?panel=seo (optionally &field=seo_title|seo_description|slug|cover|authors|body for the suggestion jump) and ?dialog=seo-api. /articles?seo=suggestions is the Needs attention filter. API: GET /v1/article/{id}/seo, GET /v1/site/{key}/sitemap?page=&size=, PATCH /v1/article/{id} (new fields), PATCH /v1/site/{id} {site_name, title_template, default_description, social_image_id, default_robots}, GET /v1/article/?seo=ready|suggestions|hidden. 401 without a session; 403 owner_only on site SEO fields; 409 slug_taken {suggestion} on PATCH slug; 400 on invalid canonical_url or title_template.