docs: release notes for v3.3.0-beta

This commit is contained in:
Florian Sylvain committed 2026-10-19 04:10:29 +02:00
1 parent 23e88190d9
commit ed67b7e70d
2 files changed
+87 -37

No files matched your search

+1 -37
View File
@@ -15,43 +15,6 @@ Body, in this order. Omit a section only when it would be empty, except Upgradin
Rules: bullets are full sentences ending with a period; user-facing wording, no commit prefixes; sentence-case headings; no horizontal rules, no metadata block, no "Pre-1.0" boilerplate (the prerelease flag says it); every release ships all 6 binaries from `task release`. Rules: bullets are full sentences ending with a period; user-facing wording, no commit prefixes; sentence-case headings; no horizontal rules, no metadata block, no "Pre-1.0" boilerplate (the prerelease flag says it); every release ships all 6 binaries from `task release`.
## Next release (draft)
Articles and sites now store the data a website needs for search and sharing, and every article gets an address that is unique on its site.
### New
**Article SEO fields**
- An article has a slug, an excerpt, a search title and description, a cover image with its alt text, a social title, description and image, a canonical address, a noindex flag and a list of dismissed suggestions.
- The slug is generated from the title, is unique per site and can be changed at any time; an empty slug regenerates it from the title.
- A site has a site name, a title template and a default description.
### API
- `PATCH /v1/article/{id}` also takes the SEO fields. `cover_image_id` and `social_image_id` accept `null`. A slug already used on the target site answers `409` `slug_taken` with the header `X-Slug-Suggestion` holding the first free slug.
- `GET /v1/article/{id}`, `POST /v1/article/`, `PATCH /v1/article/{id}`, `PATCH /v1/article/{id}/publish` and `PATCH /v1/article/{id}/unpublish` return the twelve SEO fields; the items of `GET /v1/article/` return `slug` and `excerpt`.
- `POST /v1/site/` and `PATCH /v1/site/{id}` take `site_name`, `title_template` and `default_description`; a template without `%title%` is `400` `invalid_title_template`.
- Changed: `GET /v1/media/{id}/usage` stays an array, and every item gains `type` and `fields` without losing `id`, `title` and `published`. Authors and sites that use the image are now listed, without a `published` key.
- Changed: a cover image, a social image, an author avatar and a site default social image all count in `used_in` and in the `unused` filter. Deleting an image clears the covers and social images that use it, and merging or purging repoints them.
### New: SEO output
- `GET /v1/article/{id}/seo` returns the resolved search and sharing data of an article (title with the site template, description, canonical address, robots, Open Graph, Twitter, image, authors and ready JSON-LD), so a frontend can render its meta tags without reimplementing the fallback chain. Drafts answer verified callers only.
- `POST /v1/article/{id}/seo/check` evaluates an article without saving, with optional overrides, and reports the suggestions, the status and whether the slug is free.
- `GET /v1/article/` items carry `seo_status` and `seo_suggestions`, and the new `seo` parameter filters on the status.
- `GET /v1/site/{key}/sitemap` lists the published URLs of a site, paged, with the total in `X-Total-Count`, which is now exposed to browsers through CORS.
- `GET /v1/article/` counts gain `suggestions`, the number of visible articles that still have SEO suggestions.
- `GET /v1/site/` takes `q`, `page` and `size` and sends the number of matching sites in `X-Total-Count`; without `page` and `size` every site is still returned, as a JSON array.
- `GET /v1/author/` also sends its total in `X-Total-Count`.
- `GET /v1/media/{id}` reads one image, with the fields of a media list item; a missing image answers `404` and a malformed id `400`.
### Upgrading
- The first start after the upgrade adds the new columns, gives every existing article a slug generated from its title (in id order within each site, with `-2`, `-3` on conflicts) and creates the unique `(site_id, slug)` index. Nothing else changes, and a second start changes nothing.
- A deleted article now frees its slug.
- The slug backfill writes in batches of 500 rows, so a large database is migrated without one long transaction, and a start that was interrupted resumes where it stopped.
## Published releases ## Published releases
Each body lives in `docs/releases/<tag>.md`. Publish with `tea releases create --tag <tag> --title "<tag> - <theme>" --note-file docs/releases/<tag>.md --prerelease --asset <file>` after `task release`, with one `--asset` per file: the six binaries, `bin/checksums.txt` and `bin/checksums.txt.sig`. `task release` produces all eight and fails before building when the signing key is missing or wrong (see [deployment.md](deployment.md#release-signing-key-maintainers-once)). Never publish a release without the two checksum files. Each body lives in `docs/releases/<tag>.md`. Publish with `tea releases create --tag <tag> --title "<tag> - <theme>" --note-file docs/releases/<tag>.md --prerelease --asset <file>` after `task release`, with one `--asset` per file: the six binaries, `bin/checksums.txt` and `bin/checksums.txt.sig`. `task release` produces all eight and fails before building when the signing key is missing or wrong (see [deployment.md](deployment.md#release-signing-key-maintainers-once)). Never publish a release without the two checksum files.
@@ -76,3 +39,4 @@ Each body lives in `docs/releases/<tag>.md`. Publish with `tea releases create -
| `v3.1.0-beta` | Image variants | | `v3.1.0-beta` | Image variants |
| `v3.2.0-beta` | Article lists, editor links and activity export | | `v3.2.0-beta` | Article lists, editor links and activity export |
| `v3.2.1-beta` | Paged media library and remembered page sizes | | `v3.2.1-beta` | Paged media library and remembered page sizes |
| `v3.3.0-beta` | Sites, authors and search and sharing |
+86
View File
@@ -0,0 +1,86 @@
This release adds sites, authors and search and sharing data (SEO) to articles: every article now belongs to a site, can credit authors, and carries what a website needs to be found and shared. Several API shapes change, so read the upgrading notes if you call the API.
## New
**Sites**
- Every article belongs to exactly one site, and exactly one site is the default. Existing articles are moved to the default site, which is created from `PUBLIC_URL` on the first start.
- The new Sites screen under Settings lets the owner add, edit, delete and set the default site, with a name, a key, a base address, a default robots setting, a locale and a default social image. Deleting a site with articles asks where to move them.
- The editor and the articles list let you choose an article's site, and the articles list can be filtered by site.
- A site also holds site-wide search defaults: a site name, a title template (it must contain `%title%`) and a default description, with a live example while you type.
**Authors**
- The new Authors screen manages public bylines, with or without an account: name, slug, bio, avatar, website and up to five social links. Owners and admins manage every author, and anyone can edit the author linked to their own account.
- Articles credit an ordered list of authors, and the first is the primary byline. The editor offers a search box with keyboard and pointer reordering, and a "Create author" shortcut for owners and admins.
- Users without an author profile are offered to create their own from the editor, and a new article is credited to its creator's author when there is one.
- Deleting an author that is credited on articles asks who takes over the credits, or whether to remove them.
**Search and sharing**
- An article has a slug, an excerpt, a search title and description, a cover image with its alt text, a social title, description and image, a canonical address, a noindex flag and a list of dismissed suggestions.
- The slug is generated from the title, is unique per site and can be changed at any time; an empty slug regenerates it from the title.
- The editor has a new Search and sharing section with soft length counters, fallback chips that show where each value comes from, search and social previews, and a "What the frontend gets" view of the resolved data.
- The editor checks the article as you type, without saving, and shows at most three suggestions with links to the field to fix. Any suggestion can be dismissed for an article.
- Articles list items show a search status chip, and a "Needs attention" toggle keeps only the articles that still have suggestions.
- `GET /v1/article/{id}/seo` returns the resolved search and sharing data (title with the site template, description, canonical address, robots, Open Graph, Twitter, image, authors and ready JSON-LD), so a frontend can render its meta tags without reimplementing the fallback chain. RenewCMS itself renders no page.
- `GET /v1/site/{key}/sitemap` lists the published URLs of a site.
- The Integration page documents the new search and sharing routes.
**Lists**
- The Sites and Authors lists are paged, with a page size of 5, 25, 50 or 100, a server-side search, and a page, size and search kept in the address so a reload or a shared link opens the same view. A page past the end goes to the last page with a notice.
## Improvements and fixes
- An image used as a cover, a social image, an author avatar or a site default social image now counts as used. It shows in the media library usage list, stays out of the unused filter, and is repointed by a merge or a purge.
- Deleting an image never fails because of its uses: the covers, social images, avatars and site images that point at it are cleared.
- The image picker names the selected image even when it is outside the first 100 media items, without requesting the whole list.
- Author profile pictures now show everywhere in the app.
- Every toggle switch in the app now uses one shared component, so they all have the same, correct geometry.
- Identical SEO checks are answered from a bounded cache, and a failed check is never cached.
- The activity log has two new filters, Sites and Authors, and records site, author and SEO field edits. Free-text fields record a size change and never their text.
- The Create author dialog and the Integration screens match the design on mobile.
## API
- `GET /v1/site/` lists the sites, the default first. It takes `q`, `page` and `size` and sends the matching total in `X-Total-Count`; without `page` and `size` every site is still returned, as a JSON array. Read access needs a verified session or an API key.
- `POST /v1/site/`, `PATCH /v1/site/{id}`, `PATCH /v1/site/{id}/default` and `DELETE /v1/site/{id}?reassign_to={id}` are for the owner and accept a session only. Errors are plain text tokens: `site_key_taken` (409), `site_has_articles` (409), `default_site` (403), `key_immutable`, `invalid_site_url`, `invalid_locale`, `invalid_title_template`, `image_not_found`, `use_set_default` and `invalid_reassign` (400), and `site_not_found` (404).
- `GET /v1/site/{key}/sitemap` is public and returns `[{ url, modified_at, noindex }]` for the online articles of a site, paged with `page` and `size` and with the total in `X-Total-Count`.
- `GET /v1/author/` lists authors, newest first, with `q`, `page` and `size`, as `{ items, total, page, size }` and the total in `X-Total-Count`.
- `POST /v1/author/` and `DELETE /v1/author/{id}?reassign_to={id|none}` are for owners and admins, `POST /v1/author/me` creates the caller's own author and answers `slug_adjusted`, and `PATCH /v1/author/{id}` is open to owners, admins and the linked account. All of them accept a session only. Errors include `author_not_found`, `user_not_found`, `author_slug_taken`, `author_has_articles`, `user_already_linked`, `author_already_linked`, `invalid_slug`, `invalid_reassign`, `image_not_found`, `bio_too_long`, `invalid_url`, `too_many_links` and `author_rights`.
- `GET /v1/article/` takes `site=<key>` and `seo=ready|suggestions|hidden`. Items gain `site_id`, `slug`, `excerpt`, `authors`, `seo_status` and `seo_suggestions`, and `counts` gain `suggestions`.
- `PATCH /v1/article/{id}` takes `body`, `site_id`, `author_ids` and the twelve SEO fields. `cover_image_id` and `social_image_id` accept `null`. A slug already used on the target site answers `409` `slug_taken` with the header `X-Slug-Suggestion` holding the first free slug.
- `GET /v1/article/{id}`, `POST /v1/article/`, `PATCH /v1/article/{id}`, `PATCH /v1/article/{id}/publish` and `PATCH /v1/article/{id}/unpublish` return `site_id`, `authors` and the twelve SEO fields.
- `GET /v1/article/{id}/seo` returns the resolved search and sharing data. It is public for online articles, and a verified session or API key also reads drafts.
- `POST /v1/article/{id}/seo/check` evaluates an article without saving, with optional overrides, and returns the status, the suggestions and whether the slug is free.
- `GET /v1/auth/me` also returns `author`, the linked author of the caller or `null`.
- `GET /v1/media/{id}` reads one image with the fields of a media list item. A missing image answers `404` and a malformed id `400`.
- `GET /v1/activity` accepts the new `sites` and `authors` categories, with the events `site.create`, `site.edit`, `site.set_default`, `site.delete`, `author.create`, `author.edit` and `author.delete`.
- Changed: `PATCH /v1/article/{id}` no longer accepts `title`, and `{}`, `{"body": null}` or any object without an accepted field now answers `400` instead of setting an empty body. `{"body": ""}` still empties the body.
- Changed: `GET /v1/media/{id}/usage` stays an array, and every item gains `type` (`article`, `author` or `site`) and `fields` without losing `id`, `title` and `published`. Authors and sites that use the image are now listed, without a `published` key.
- Changed: `POST /v1/media/merge` and `POST /v1/media/purge` also report `sites_updated` and `authors_updated`.
- Changed: `X-Total-Count` is now exposed to browsers through CORS.
## Under the hood
- Add the site, author and article SEO domains, repositories, mappers and use cases behind the existing layers, with a resolver and a checker for the search and sharing data.
- Upgrade `jwtauth` to v5.4.0 and `lestrrat-go/jwx` to v3, and refresh the related indirect dependencies.
- Look up authors, sites and credits in batches that work on SQLite, MySQL, MariaDB and PostgreSQL.
- Document the routes in `docs/api.md` and `docs/api/articles.md`, the measured cost of the `?seo=` filter in `docs/performance.md`, and the layering in `docs/architecture.md`.
- Add the specifications, design checks and Go and Vitest suites for sites, authors, search and sharing, and list pagination.
## Upgrading
- Replace the binary, or pull the new image. Back up the database first: the migration changes existing rows.
- The first start after the upgrade creates the sites and authors tables, seeds the default site (name "Default", key "default") from the scheme and host of `PUBLIC_URL` and moves every article to it. An unparseable `PUBLIC_URL` stops the migration, so check it before upgrading. `PUBLIC_URL` is never read for sites afterwards.
- The same start adds the new columns, gives every existing article a slug generated from its title (in id order within each site, with `-2`, `-3` on conflicts) and creates the unique `(site_id, slug)` index. A deleted article now frees its slug. The backfill writes in batches of 500 rows, a start that was interrupted resumes where it stopped, and a second start changes nothing.
- Existing sites get the default title template `%title% | %site%`, an empty site name and an empty default description.
- No new environment variable is needed.
- Any script that sends `PATCH /v1/article/{id}` with a `title`, an empty object or a null body must change, as described in the API section.
- Reading `GET /v1/media/{id}/usage` as an array of articles still works, but now also yields authors and sites. Filter on `type` if you only want articles.
## Known limitations
- The `?seo=` filter and `counts.suggestions` assess every visible article in memory, so their cost grows with the number of articles. On the development machine, 5,000 articles of about 5 KB each answer in roughly 300 ms.
- Only the owner can manage sites, and an API key cannot write sites or authors.