docs: consolidate design change logs and refresh stale docs
This commit is contained in:
1 parent
c050db78d2
commit
c92d8740ed
40 files changed
+185
-604
No files matched your search
@@ -6,7 +6,7 @@ Feature: Authors backend, public bylines that articles credit in order
|
||||
So that readers see who wrote an article, whether or not the writer has an account
|
||||
|
||||
Background:
|
||||
Given the spec of record is docs/design/screens/authors.md, docs/design/screens/editor.md (site and authors), docs/design/screens/profile.md, docs/design/states.md (author rows), docs/design/routes.md and docs/design/sites-authors-slices.md
|
||||
Given the spec of record is docs/design/screens/authors.md, docs/design/screens/editor.md (site and authors), docs/design/screens/profile.md, docs/design/states.md (author rows), docs/design/routes.md and docs/design/decisions.md
|
||||
And this slice is backend only: no SPA, no change to docs/design
|
||||
And an Author has id (uint32), name, slug, bio, avatar_id (nullable media id), website (nullable), social_links, user_id (nullable and unique), is_linked and article_count, in snake_case JSON
|
||||
And an article has zero or more authors in a stored order through an ordered article_authors join; the first is the primary byline
|
||||
|
||||
@@ -6,7 +6,7 @@ Feature: Editor: search and sharing, suggestions and "What the frontend gets"
|
||||
|
||||
Background:
|
||||
Given the screen is EditorView (/article/:id/edit) inside DashboardShell, per docs/design/routes.md
|
||||
And the visual spec of record is docs/design/screens/editor.md (groups "Editor: search and sharing" with 24 states and "Editor: what the frontend gets" with 6 states), docs/design/seo-slices.md, docs/design/components.md (SearchSharingSection, SeoPanel, SoftCounter, SearchPreview, SocialCardPreview, SuggestionList, ApiPreviewDialog, SlugField, MediaField) and docs/design/states.md ("SEO round"). Exact copy is read from those files and is not repeated here unless a scenario needs it
|
||||
And the visual spec of record is docs/design/screens/editor.md (groups "Editor: search and sharing" with 24 states and "Editor: what the frontend gets" with 6 states), docs/design/decisions.md, docs/design/components.md (SearchSharingSection, SeoPanel, SoftCounter, SearchPreview, SocialCardPreview, SuggestionList, ApiPreviewDialog, SlugField, MediaField) and docs/design/states.md ("SEO round"). Exact copy is read from those files and is not repeated here unless a scenario needs it
|
||||
And the board frames of docs/design/source/RenewCMS Screens Back-office.dc.html, AppFrame.dc.html and DirectoryFrame.dc.html are the layout tiebreaker
|
||||
And this slice is SPA only and reuses the API of features/seo_data_backend.feature and features/seo_output_backend.feature without change
|
||||
And the SPA calls, with relative URLs through useApi only: GET /v1/article/{id} and PATCH /v1/article/{id} (SEO fields slug, excerpt, seo_title, seo_description, cover_image_id, cover_image_alt, social_title, social_description, social_image_id, canonical_url, noindex), POST /v1/article/{id}/seo/check, GET /v1/article/{id}/seo, GET /v1/site/ and the media routes of the shared picker
|
||||
|
||||
@@ -7,7 +7,7 @@ Feature: Media field usage in the Media library
|
||||
Given the SPA calls the API with relative URLs under /v1 and the "jwt" HttpOnly cookie
|
||||
And API errors are plain text
|
||||
And this slice changes only web/ (and web/visual); the backend of features/media_field_type.feature is done and not touched
|
||||
And the design is docs/design/media-field-changes.md section 3.8 and section 4, with the board group "11 Media library: usage" (4 states) of "RenewCMS Screens Schema.dc.html", which draws MediaFrame.dc.html with entries counted as uses
|
||||
And the design is docs/design/media-field.md section 3.8 and section 4, with the board group "11 Media library: usage" (4 states) of "RenewCMS Screens Schema.dc.html", which draws MediaFrame.dc.html with entries counted as uses
|
||||
And GET /v1/media/ items carry "used_in", which counts articles, authors, sites and entries together, and no split
|
||||
And GET /v1/media/{id}/usage answers an array ordered articles, authors, sites, then entries by content type name then entry id, with no total and no "first few" wrapper
|
||||
And an article item is {"type":"article","id","title","published","fields"}
|
||||
|
||||
@@ -7,7 +7,7 @@ Feature: Media field type in the SPA
|
||||
Given the SPA calls the API with relative URLs under /v1 and the "jwt" HttpOnly cookie
|
||||
And API errors are plain text
|
||||
And this slice changes only web/ (and web/visual); the backend of features/media_field_type.feature is done
|
||||
And the design is docs/design/media-field-changes.md sections 1, 2, 3.2 to 3.7, 4, 6 and 7, with the board groups 2 Schema builder, 3 Review and delete, 4 Field types, 5 Content and entry list, 6 Entry editor and 10 Media picker for fields of "RenewCMS Screens Schema.dc.html"
|
||||
And the design is docs/design/media-field.md sections 1, 2, 3.2 to 3.7, 4 and 6, with the board groups 2 Schema builder, 3 Review and delete, 4 Field types, 5 Content and entry list, 6 Entry editor and 10 Media picker for fields of "RenewCMS Screens Schema.dc.html"
|
||||
And the registry is lib/fieldTypes with lib/entryEditors, the single source for the builder, the list cells and the entry form; no screen branches on the type name "media" where a registry property can say it
|
||||
And a media value is the id of a library image (a uint32 of at least 1) or null
|
||||
And every entry answer (POST 201, PUT 200, GET one, each list item) carries a top-level "media" object keyed by media field key: {"id","filename","width","height","size","thumbnail_url"} for an existing image, or {"id","missing":true} when the image is gone; a null value has no key
|
||||
@@ -476,7 +476,7 @@ Feature: Media field type in the SPA
|
||||
Given the card or a title needs the text of a media cell
|
||||
Then it reads "–" for none and never the numeric id
|
||||
|
||||
# ---------- Accessibility (media-field-changes.md section 6)
|
||||
# ---------- Accessibility (media-field.md section 6)
|
||||
|
||||
Scenario: Accessibility of the control
|
||||
Then the control is role="group" labelled by the field label
|
||||
|
||||
@@ -27,7 +27,7 @@ Helper: decode into {items []map, total, page, size int, counts {all, unused, du
|
||||
- `docs/api.md` lines 99-103: replace `cursor` and `limit` with `page` (default 1) and `size` (5, 25, 50, 100; default 25); state the envelope (`items`, `total`, `page`, `size`, `counts`), that `counts` stays library-wide, that invalid values answer 400 "The media query is invalid.", and a "Breaking change" note: `next_cursor` is gone, `cursor` and `limit` are ignored.
|
||||
- `docs/api/*.md`: grep for `/v1/media/` and `cursor`; update the media listing section if one exists.
|
||||
- `web/src/data/apiCatalogue.ts` `med-list`: add `page`, `size`, `q`, `filter`, `sort`, `variants`, `hash` query entries, the 400 error, and a paged example (`total`, `page`, `size`, no `next_cursor`). Remove the `next_cursor` rule (line ~129, with its French entry in `web/src/i18n/messages.ts` line ~1606) if it is only used by media. Integration specs asserting the catalogue are amended.
|
||||
- Flag for the user (read-only to agents): `docs/design/screens/integration.md` and `docs/design/source/IntegrationPage.dc.html` (med-list with no params), `docs/design/screens/media.md`, `routes.md`, `change-list.md` item 13b, `README.md` line 92 and `screens/media-picker.md`: all still say "array body" and "X-Total-Count".
|
||||
- Flag for the user (read-only to agents): `docs/design/screens/integration.md` and `docs/design/source/IntegrationPage.dc.html` (med-list with no params), `docs/design/screens/media.md`, `routes.md`, `README.md` line 92 and `screens/media-picker.md`: all still say "array body" and "X-Total-Count".
|
||||
- A release note under `docs/releases/` is the maintainer's call: flag it.
|
||||
|
||||
## Manual verification
|
||||
|
||||
@@ -5,7 +5,7 @@ Feature: Relation picker "loading more" state
|
||||
So that pressing "Load more" never loses focus or shows a blank list
|
||||
|
||||
Background:
|
||||
Given the spec of record is docs/design/screens/schema-later.md group 7 states 2 and 3, and docs/design/change-log-roles-sync.md "Relation picker"
|
||||
Given the spec of record is docs/design/screens/schema-later.md group 7 states 2 and 3
|
||||
And the picker is RelationField.vue over useRelationSearch.ts, which already requests GET /v1/content-type/{key}/entry?page=N&size=25 and has loading, loadingMore, hasMore and total
|
||||
And the sample is 25 venues loaded of 62 for "rue", footer "Showing 25 of 62" with "Load more"
|
||||
And the design marks the group "Later" but the picker exists in the app; this file specifies the missing state only
|
||||
|
||||
@@ -13,7 +13,7 @@ Do not copy the old `Role ==` checks into new code.
|
||||
## Design notes for the user
|
||||
|
||||
- docs/design/screens/roles.md "Owner-only items" disables View roles and Manage roles for an admin. This slice follows the user's decision (Admin has 29 keys). The design needs a fix by the user.
|
||||
- docs/design/change-list.md item 21 ("Sites: owner only, hidden for other roles") and its SEO "Permissions" paragraph ("only the owner edits site SEO defaults", 403 `owner_only`), plus the `owner_only` clause in routes.md "SEO", disagree with this slice. Admin has `settings.manage_sites`, so an admin can now edit sites and their SEO defaults.
|
||||
- the removed change-list.md item 21 ("Sites: owner only, hidden for other roles") and its SEO "Permissions" paragraph ("only the owner edits site SEO defaults", 403 `owner_only`), plus the `owner_only` clause in routes.md "SEO", disagree with this slice. Admin has `settings.manage_sites`, so an admin can now edit sites and their SEO defaults.
|
||||
- roles.md is inconsistent about Writer and Schema. The "Writer: Articles list" state hides Schema from the sidebar, while the catalogue, the built-in table and change-list ("Schema read-only for view-only roles") give Writer `schema.view`.
|
||||
- change-list line 100 mentions a "restricted `user` role" that does not exist.
|
||||
- The docs name `GET /v1/me`. The implemented route is `GET /v1/auth/me` (resolved in slice 1).
|
||||
|
||||
@@ -5,7 +5,7 @@ Feature: Roles sync pass 6: final copy, neutral wording and role activity events
|
||||
So that every message names what happened, says what was kept and says what to do next
|
||||
|
||||
Background:
|
||||
Given the spec of record is docs/design/screens/roles.md groups 8, 12 and 13, the tables "Activity events: sentences", "Activity events: failed sentences", "Activity filter: category names" and "Final copy: toasts and errors, EN and FR", docs/design/states.md "Roles sync (pass 6)", docs/design/screens/activity.md "Roles sync (pass 6)" and docs/design/change-log-roles-sync.md section 1
|
||||
Given the spec of record is docs/design/screens/roles.md groups 8, 12 and 13, the tables "Activity events: sentences", "Activity events: failed sentences", "Activity filter: category names" and "Final copy: toasts and errors, EN and FR", docs/design/states.md "Roles sync (pass 6)", docs/design/screens/activity.md "Roles sync (pass 6)"
|
||||
And the stale-state toasts, banners and dialog alerts of group 15 are in features/roles_sync_conflicts.feature, not here
|
||||
And the removal of a user (route, dialog, toast, user.remove event) is in features/roles_sync_remove_user.feature
|
||||
And the audit actions are role.create, role.edit, role.delete, role.reassign, user.change_role and user.transfer_ownership (internal/domain/audit/auditDomain.go), the outcome is a field and a failed event keeps its name
|
||||
|
||||
@@ -5,7 +5,7 @@ Feature: Integration page: permission-gated routes and role-aware copy
|
||||
So that a key's owner knows which permission a route needs
|
||||
|
||||
Background:
|
||||
Given the spec of record is docs/design/screens/integration.md (Page copy, EndpointCard states, Error messages) and docs/design/change-log-roles-sync.md "Integration page"
|
||||
Given the spec of record is docs/design/screens/integration.md (Page copy, EndpointCard states, Error messages)
|
||||
And the catalogue is web/src/data/apiCatalogue.ts and its search index; routes are gated in api/router.go by container.require(...) with the permission keys of internal/domain/role
|
||||
And the real gating is:
|
||||
| route | permission label (lib/permissionNames.ts) |
|
||||
|
||||
@@ -5,7 +5,7 @@ Feature: Profile role card of the roles-sync design (group 9)
|
||||
So that I can understand my access without reading who assigned it
|
||||
|
||||
Background:
|
||||
Given the spec of record is docs/design/screens/roles.md group 9 and docs/design/change-log-roles-sync.md section 2
|
||||
Given the spec of record is docs/design/screens/roles.md group 9
|
||||
And features/roles_spa_users.feature "Profile, your role" is amended by this file: the summary line and "Assigned by" are removed
|
||||
And GET /v1/auth/me answers access.role {id, name, built_in, locked} and access.permissions; the design says GET /v1/me, the real route is /v1/auth/me
|
||||
And the card layout, top to bottom, inside the existing card with a gap of 12: the title, one row of badges, the link row with the list-checks icon, the muted key line
|
||||
|
||||
@@ -6,7 +6,7 @@ Feature: Read = Own surfaces of the roles-sync design (group 14)
|
||||
|
||||
Background:
|
||||
Given the backend contract of features/roles_permissions_content_scope.feature: a caller with content.read=own gets online articles plus their own drafts, and only the entries they created, with counts, total, page and size computed over the visible set
|
||||
And the spec of record is docs/design/screens/roles.md group 14, its table "Read = Own: what each surface returns", and docs/design/change-log-roles-sync.md section 4
|
||||
And the spec of record is docs/design/screens/roles.md group 14, its table "Read = Own: what each surface returns"
|
||||
And the SPA never computes visibility: every count, total and pager value shown comes from the API (GET /v1/article counts and total, GET /v1/content-type/{key}/entry total)
|
||||
And the SPA knows a person reads Own through scopeOf("content.read", type) of stores/permissions.ts
|
||||
And Update or Delete set to Own keep the "View only" rows of slice 5; only Read = Own hides rows
|
||||
|
||||
@@ -7,7 +7,7 @@ Feature: SEO data backend, article and site search fields, unique slugs and medi
|
||||
So that a frontend can later resolve titles, descriptions, images and addresses from RenewCMS
|
||||
|
||||
Background:
|
||||
Given the spec of record is docs/design/seo-slices.md (slice 1), docs/design/change-list.md ("SEO round"), docs/design/screens/editor.md, docs/design/screens/sites.md and docs/design/states.md
|
||||
Given the spec of record is docs/design/decisions.md (Search and sharing), docs/design/screens/editor.md, docs/design/screens/sites.md and docs/design/states.md
|
||||
And this slice is backend only: no SPA, no change to docs/design, and no resolver, check endpoint, sitemap or list seo filter
|
||||
And an article gains these snake_case fields: slug, excerpt, seo_title, seo_description, cover_image_id, cover_image_alt, social_title, social_description, social_image_id, canonical_url, noindex, seo_dismissed
|
||||
And in article JSON the text fields are "" when empty, cover_image_id and social_image_id are null when unset, noindex is false by default and seo_dismissed is [] by default
|
||||
|
||||
@@ -12,7 +12,7 @@ Spec: `features/seo_data_backend.feature`. Go tests only, in `test/` (package `t
|
||||
|
||||
- **Site image and robots names:** the API uses `default_social_image_id` and `default_robots` (existing site contract). The design writes `social_image_id` for the site and, in places, `robots`. The SPA uses the code names.
|
||||
- **Non-owner site writes:** the API answers 403 with the existing text "Only the owner can do this." (`apperr.MissingPermissionErrorMessage`). The design mentions a 403 `owner_only` token, which does not exist.
|
||||
- **Empty-slug fallback:** one rule everywhere. A title with no letter or digit becomes `article`, then `article-2`, `article-3` on conflict, in the API and in the migration. `docs/design/seo-slices.md` (decision 5) says `article-<id>` for the migration; that wording is not followed.
|
||||
- **Empty-slug fallback:** one rule everywhere. A title with no letter or digit becomes `article`, then `article-2`, `article-3` on conflict, in the API and in the migration. `docs/design/decisions.md` (decision 5) says `article-<id>` for the migration; that wording is not followed.
|
||||
- **Slug conflict transport:** the conflict follows the authors slug conflict (plain text `slug_taken`, 409); the suggestion travels in the `X-Slug-Suggestion` response header, not in a JSON body. The `slug.suggestion` of the slice 2 check endpoint is separate.
|
||||
- **Empty slug:** `slug: ""` regenerates the slug from the title (the SPA "Reset to match the title" sends `""`); 409 only if the regenerated slug belongs to another article on the site.
|
||||
- **Status codes:** `invalid_url` is 422 (authors); `invalid_slug`, `invalid_title_template` and `image_not_found` are 400.
|
||||
|
||||
@@ -7,7 +7,7 @@ Feature: SEO output backend, resolved SEO object, non-persisting check, list sta
|
||||
So that a frontend can render meta tags and a sitemap without reimplementing the fallback chain
|
||||
|
||||
Background:
|
||||
Given the spec of record is docs/design/seo-slices.md (slice 2), docs/design/change-list.md ("SEO round"), docs/design/screens/editor.md, docs/design/screens/articles.md and docs/design/screens/integration.md
|
||||
Given the spec of record is docs/design/decisions.md (Search and sharing), docs/design/screens/editor.md, docs/design/screens/articles.md and docs/design/screens/integration.md
|
||||
And this slice is backend only: no SPA screen and no change to docs/design
|
||||
And it reuses the article and site SEO fields of features/seo_data_backend.feature and adds no column and no migration
|
||||
And RenewCMS renders no page and injects no meta tag: it only returns data
|
||||
|
||||
@@ -8,7 +8,7 @@ Feature: SEO round, slice 4: Sites defaults, Articles search status, Integration
|
||||
|
||||
Background:
|
||||
Given the screens are SitesView (/settings/sites), ArticleView (/article, also reached as /articles), IntegrationView (/integration) and the Editor SEO panel (/article/:id/edit), inside DashboardShell, per docs/design/routes.md
|
||||
And the visual spec of record is docs/design/screens/sites.md ("Sites: SEO defaults", 5 states), articles.md ("Articles: search status", 3 states), integration.md ("Search and sharing"), editor.md (SuggestionList), docs/design/components.md (SeoStatusChip, SuggestionList), docs/design/seo-slices.md and docs/design/states.md ("SEO round"). Exact copy is read from those files and is not repeated here unless a scenario needs it
|
||||
And the visual spec of record is docs/design/screens/sites.md ("Sites: SEO defaults", 5 states), articles.md ("Articles: search status", 3 states), integration.md ("Search and sharing"), editor.md (SuggestionList), docs/design/components.md (SeoStatusChip, SuggestionList), docs/design/decisions.md and docs/design/states.md ("SEO round"). Exact copy is read from those files and is not repeated here unless a scenario needs it
|
||||
And the board frames of docs/design/source/DirectoryFrame.dc.html (Sites form, SuggestionList), AppFrame.dc.html (Articles rows, cards and toolbar) and IntegrationPage.dc.html (group and index) are the layout tiebreaker
|
||||
And this slice is SPA only and uses the API of features/seo_data_backend.feature and features/seo_output_backend.feature, plus counts.suggestions added by features/articles_pagination_api.feature. No other Go file changes
|
||||
And the SPA calls, with relative URLs through useApi only: GET /v1/site/, POST /v1/site/ and PATCH /v1/site/{id} (site_name, title_template, default_description), GET /v1/article/ with the optional seo=suggestions parameter, whose response also carries counts.suggestions, and PATCH /v1/article/{id} with seo_dismissed. The Integration page makes no request
|
||||
|
||||
@@ -6,7 +6,7 @@ Feature: Sites backend, the owner manages sites and every article belongs to exa
|
||||
So that a single back-office can hold the content of more than one website
|
||||
|
||||
Background:
|
||||
Given the spec of record is docs/design/screens/sites.md, docs/design/states.md (site rows), docs/design/routes.md and docs/design/sites-authors-slices.md
|
||||
Given the spec of record is docs/design/screens/sites.md, docs/design/states.md (site rows), docs/design/routes.md and docs/design/decisions.md
|
||||
And this slice is backend only: no SPA, no change to docs/design
|
||||
And a Site has id (uint32), name, key, base_url, default_social_image_id (nullable), default_robots ("index" or "noindex"), locale (nullable), is_default and article_count, in snake_case JSON
|
||||
And exactly one site is the default at any time, enforced by the use case inside a transaction and not by a partial index
|
||||
|
||||
Reference in new issue
Block a user