Release
v3.14.0
Added
- Added `changes/*.md` fragment workflow that merges per-issue changelog entries into `CHANGELOG.md` under `[Unreleased]` before each release, grouped by heading; fragments are deleted after merge so the manual changelog stays conflict-free across parallel tickets.
- Added `devenv` `doctor` script that proxies to `bun run doctor` for a single local health gate.
Changed
- Made the product clear at a glance in README and marketing with refreshed hero, product screenshots, and copy that shows the Publication and Rendition workspace without hiding provider truth.
- Documented the single backend runtime location for `OPENPOST_PADDLE_*` (`backend/.env` for devenv, container environment for Docker) and clarified that bare `PADDLE_*` is never read; Cloud mode now warns at startup with the exact ignored names without printing values.
- Refreshed product screenshots as trustworthy, exact renders of the current app and documented the fragment workflow with granular check guidance (`check:frontend:types`, `check:contracts`, `test:file`, `test:backend:pkg`) and an `.rgignore` to keep searches fast.
- Staged provider, security, and scheduling flows with progressive disclosure: available providers stay primary while setup-required providers move behind a collapsed section, failed provider errors stay dominant with a retry beside the message, authenticator setup is staged one primary action at a time, quick schedule paths are primary while calendar and randomization are behind disclosure, and Workspace Preferences and Security panels collapse media lifecycle, danger zone, and identity sections.
Fixed
- Instance admin plan overrides now work end to end. Assigning an override previously failed with a 500 because the generated subscription row carried an empty `workspace_id` that violated the Postgres foreign key; the model now stores a NULL workspace, and the override grants plan entitlements exactly like a paid Paddle subscription across billing status, entitlement checks, setup state, and public profiles.
- Removing an override from the plan dialog previously returned 422 because the empty `plan_id` was rejected by request validation; empty `plan_id` now reaches the removal path as documented.
- Resolved configured Mastodon adapter by canonical `instance_url` before dynamic registration so OAuth callbacks find the correct provider key.
- Loaded `SSL_CERT_FILE` into the Go root pool on macOS so local E2E Mastodon CA is trusted without `InsecureSkipVerify`.
- Ignored aborted fetch errors after component teardown and pagehide so stale composer requests do not pollute console telemetry.
7 more entries in the full changelog.