Files

14 KiB
Raw Permalink Blame History

Change list for implementation (status after pass 2; SEO round drawn; cleanup round drawn)

Cleanup round

  1. Editor: site and authors, "Create author" states (4 states, desktop and mobile): the mobile dialog sat under the Details sheet (z-index 50 against 55) and was hidden. It now stacks above the sheet (z-index 60), as the SEO panel does. Full-width bottom sheet with grabber, same fields, Cancel left and "Create author" right (Cancel below on mobile, as the other mobile dialogs). Frame: DirectoryFrame.dc.html. The four states share the fix: dialog, "for me", slug taken, failed.
  2. Integration, "6. Errors": the 403 row gets the muted note "Site SEO defaults are owner only. Article SEO fields need only the right to edit the article." The row below shifts down by the wrapped note height (two 18 px lines desktop, three mobile, plus the 2 px row gap). The old inline parenthetical with the same sentence in the 403 cause text was removed, so it isn't said twice. Frame: IntegrationPage.dc.html.
  3. Integration, sitemap errors: 404 now shows the body site_not_found in code style (was "Site not found"); 400 now shows the generic body-mismatch text used by the other routes (was "Invalid page or size.").
  4. New groups on the Back-office board: "Sites: pagination" and "Authors: pagination", 10 states each (20 states, every one desktop and mobile; light and dark by the theme switch). Back-office total 409 → 429. Same pager as Articles and Media, sizes 5, 25, 50, 100, default 25 (no difference to report). One deviation: on a single page the page-size select is hidden and only "N sites" or "N authors" remains.
  5. Specs: screens/sites.md, screens/authors.md (pager states, URL rules, out-of-range fallback), screens/integration.md, states.md (pagination states, three HTTP rows), components.md (single-page variant, no new component), routes.md (Sites pagination in the URL).

Backend assumptions to confirm. GET /v1/site/ takes q, page, size and returns X-Total-Count (it returns every site today). GET /v1/author/ gets page, size and X-Total-Count (it has q).

Open points.

  • Sites has no search field. The two states that need one (empty after search, search resets to page 1) draw the Authors field on Sites with "Search by name or key". Drop those states if you don't want search on Sites.
  • Stale copy found, not changed: GET /v1/article/ on Integration still shows the 400 caption "Invalid page or size." while every other route, and now the sitemap, uses the body-mismatch text. The 404 row of the Errors table still lists only the four resource messages and doesn't mention site_not_found. The existing Sites and Authors "Default" frames don't draw the count line. README.md state counts and the "Pagination" notes were not updated (outside this round).

SEO round: decisions (frames drawn)

Placement. A "Search and sharing" section sits under "Site and authors" in the Editor sidebar and in the mobile Details sheet. It is collapsed by default, shows a one-line summary ("Ready", "2 suggestions" or "Hidden from search") and is remembered per browser like Site and authors. It holds only the slug, the full URL and three actions: "Edit search and sharing", "What the frontend gets" and the suggestion list. The fields and live previews open in a slide-over (desktop) or a 92% bottom sheet stacked over the Details sheet (mobile), because the 280 px sidebar is too narrow for previews and the slide-over rule already covers forms with a live preview. The API preview is a 720 px dialog (desktop) or a bottom sheet (mobile).

Principles. RenewCMS does not render pages or inject meta tags. Every field is optional and the UI shows its fallback. No scores. Suggestions never block saving or publishing; publishing is allowed regardless. Suggestions are dismissible per article.

Fallback chain (resolved server-side, shown in the UI).

Output Order
title seo_title, then article title; site title_template applied last
description seo_description, then excerpt, then first sentence of the body, then site default_description
image og_image_id, then cover_image_id, then site social image
canonical canonical_url, then site base_url + "/" + slug
robots noindex true gives "noindex, nofollow"; otherwise site default_robots
og/twitter title and description social_title, social_description, then the resolved values above

Soft ranges (counters, never blocks). Meta title 30–60 characters; description 70–160; slug "very long" above 75 characters. Counter turns neutral-warning (--ui-warning) outside the range, never red.

New article fields (PATCH /v1/article/{id}, all optional, snake_case). slug, excerpt (max 300), seo_title (max 120), seo_description (max 320), cover_image_id, cover_image_alt (max 200; the cover is "ready" only with alt text), social_title, social_description, social_image_id, canonical_url (absolute https URL), noindex (boolean; only sets a flag in the API, it doesn't change visibility), seo_dismissed (string[] of suggestion codes). Slug: lowercase letters, numbers, hyphens; unique per site; 409 slug_taken with suggestion ("-2"); auto-generated from the title until edited.

New site fields (PATCH /v1/site/{id}, owner only). site_name, title_template (default "%title% | %site%", must contain %title%), default_description (max 320), social_image_id (existing), default_robots ("index" | "noindex"; existing as robots).

New endpoints.

  • GET /v1/article/{id}/seo: resolved object, public for online articles, 404 for drafts to anonymous callers. Shape: { title, description, canonical_url, robots, og: { type, title, description, image, image_alt, url, site_name, locale }, twitter: { card, title, description, image, image_alt }, image: { url, alt, source }, authors: [{ name, url, same_as: [] }], published_at, modified_at, fallbacks: { title, description, image, canonical }, json_ld }. json_ld is a ready Article object (headline, description, image, author[] with name, url and sameAs from author profile URL and social links, datePublished, dateModified, mainEntityOfPage).
  • GET /v1/site/{key}/sitemap?page=&size=: published URLs only, total in X-Total-Count. Items: { url, modified_at, noindex }. Decision: yes, shown on Integration under "Search and sharing" with a copy button; noindex articles are included with the flag so the frontend can skip them.
  • GET /v1/article/?seo=ready|suggestions|hidden: filter behind "Needs attention" (suggestions) with seo_status and seo_suggestions (count) added to list items.

Articles list. Quiet indicator inside the Status cell (and under the title on mobile cards): nothing when ready, a lightbulb chip "N" for suggestions, an eye-off chip "Hidden" for noindex. Toolbar gets a "Needs attention" toggle next to search; tabs and counts are unchanged. It behaves the same on a single-site install (independent of the Site filter, which stays hidden).

Authors. No change to the Authors screen. Profile URL (website) and social links feed authors[].url and same_as, and JSON-LD author[].sameAs; the API preview shows them.

Permissions. Anyone who can edit an article edits its SEO fields. Only the owner edits site SEO defaults. 401 and 403 rows join the existing HTTP table: 403 owner_only on Site SEO fields, 401 on a missing session.

Left out on purpose. Keyword scoring and focus keywords, readability scores, redirects management, schema types beyond Article, hreflang, robots.txt and sitemap rendering (RenewCMS only provides data), automatic image generation for social cards.

Open questions.

  1. Is slug immutable after first publish, or can it change (and break URLs with no redirects)?
  2. Does the API return the SEO object for drafts to authenticated callers (for frontend previews)?
  3. Should noindex articles be excluded from the sitemap endpoint instead of flagged?
  4. Is title_template applied by the API (resolved title) or only returned for the frontend to apply?
  5. Backfill: generate slugs for existing articles from their titles at migration, with -2 suffixes on conflicts?
  6. Should excerpt be exposed in the list payload as the article teaser?

Status. Frames drawn on the Back-office board (groups: Articles: search status, Editor: search and sharing, Editor: what the frontend gets, Sites: SEO defaults), Integration page group added, specs updated. Placement rationale: the sidebar holds only the summary, address and suggestions because it is 280 px wide; previews and fields need a slide-over.

Ordered by implementation dependency: tokens and shell first, then shared components, then screens. "Frontend only" means no backend work is needed.

# Screen Change Done in design? Needs backend (yes/no, what) Needs new tokens or components Frontend only
1 All Add the --rc-* tokens (sand, on-sand, four soft grounds, overlay, two shadows) to the app CSS, light and dark (foundations.md) Yes No 9 new tokens Yes
2 All One sidebar, topbar and mobile drawer; Settings parent and child selected states; Activity sits between Users and Integration Yes No NavItem, NavGroup Yes
3 All Overlay pattern: dialog (desktop) and bottom sheet (mobile); slide-over only for the variant form and record details; footer secondary left, primary right Yes No Modal wrapper rules (components.md) Yes
4 All CodeSnippet is the only code block (Integration, Images, API keys, base URL, image URL) Yes No CodeSnippet Yes
5 All Copy glossary pass (Delete vs Remove, Save vs Update, toast phrasing) Yes, by search; not every line re-read No None Yes
6 Settings "Media" card with "Manage image variants" and "Cache usage" Yes No MediaLinksCard Yes
7 Media, picker Variant count badge on grid, list and mobile rows Yes No (variant counts already come with GET /v1/media?variants=) Badge "N variants" Yes
8 Media "With variants / Without" filter and "Largest total size" sort in the Media toolbar Drawn on the Variants board only, not folded into the Media screen No (GET /v1/media?variants=&sort=total_size exists) None Yes
9 Image variants Variant form as slide-over (desktop) and tall sheet (mobile) Yes No None Yes
10 New article Title only. Body removed from the modal; the editor opens straight away Yes Maybe: confirm POST /v1/article/ accepts an empty body (it is "required" today); otherwise the frontend sends an empty string NewArticleModal Yes if empty body is accepted
11 Editor Remove the 10,000 character limit, counter, limit and over-limit states; neutral count Yes Yes: remove the body length validation on POST /v1/article/ and PATCH /v1/article/{id} EditorStatusBar No
12 Editor Insert-link button (default, hover, active, disabled), tooltip, LinkModal, link popover and touch sheet, rendered link, toolbar scrolling at 390 px Yes No (editor only) LinkModal, LinkPopover, ToolbarButton Yes
13 Articles Pagination with page and size (5, 25, 50, 100; default 25), URL state, loading, error, out of range Yes Yes: page, size on GET /v1/article/ (same convention and 400 as Activity); total in X-Total-Count, array body unchanged; Integration reference updated Paginator, PageSizeSelect No
13b Media Pagination under the grid and list, same Paginator and PageSizeSelect as Articles; page and size in the URL; saved size preference Yes (9 states in the Media group) Yes: page, size on GET /v1/media/ (replaces cursor and limit); total in X-Total-Count, array body unchanged; Integration reference None (reuses Paginator, PageSizeSelect) No
14 Activity Failed-action and security cards as toggles, synced chip and segment Yes No FilterCardToggle Yes
15 Activity Export menu and dialog, CSV: current view (active filters) and all activity (no filters, optional from/to). Preparing, started, failed, nothing to export, 403 Yes No: GET /v1/activity/export is implemented (CSV, synchronous, owner and admin, same filters as the list) ExportMenu, ExportDialog Yes
16 Activity JSON export (format control CSV or JSON) Yes, one state, labelled proposed Yes (proposed): format=json on GET /v1/activity/export Segmented format control No
17 Integration Images and variants section, URL builder, response bodies unknown_variant and unsupported_parameter Yes No UrlBuilder Yes
18 All States matrix for controls (hover, focus-visible, active, disabled) Yes (board "States matrix: controls") No None Yes
19 All Contrast fixes: paginator current page border, no muted text on sand Yes No None Yes
20 All Spacing, type and icon sizes made consistent (foundations.md, "One value per role") Yes in the frames listed there No None Yes
21 Settings, sidebar Sites screen under Settings → Sites ("Publishing" group); "Publishing" card on Settings. Owner only: hidden for other roles, 403 page on a direct link. Key immutable after creation Yes Yes: site table, GET/POST/PATCH/DELETE /v1/site/ (writes owner only; PATCH rejects a changed key), reassign_to, seed from PUBLIC_URL SitesTable, SiteForm, SlugField (locked variant), ReassignDialog No
22 Sidebar Authors entry between Media and Users, all roles. Owner and admin manage; other roles read-only list and detail Yes Yes: author table, GET /v1/author/ (any role), POST/PATCH/DELETE (owner and admin; a user may PATCH their own linked author), POST /v1/author/me (any role) AuthorsTable, AuthorForm, SocialLinksRepeater, MediaField No
23 Editor "Site and authors" section in every Editor frame (collapsed by default): Site select (any role that can edit the article), reorderable authors, inline create (owner and admin), hint Yes Yes: site_id, author_ids[] on PATCH /v1/article/{id} MetaSection, AuthorList, AuthorSelect, SiteSelect, CreateAuthorHint No
24 Articles Authors column; Site column and filter when more than one site Yes Yes: site filter, site and authors in the list payload AuthorStack No
25 Profile "Author profile" card in every Profile frame, one-click create, edit own author (user link locked) Yes Yes: POST /v1/author/me AuthorProfileCard No
26 Backfill Existing articles get the default site; authors start empty n/a Yes: migration None No