# Feature: Release Communications ## Status Draft ## Goal Give users a clear, curated view of product changes they have not seen yet, and give developers a back-office workflow for reconciling shipped commits with human-readable update entries. The user-facing experience answers: "What changed since I last paid attention?" The developer-facing experience answers: "Which shipped commits have been communicated, grouped, or intentionally marked internal-only?" This feature is especially important during alpha and beta, where continuous delivery makes exact public version numbers less useful than a readable change history. ## User Stories - As an authenticated user, I want to see new features, improvements, and fixes since my last visit so that product changes do not surprise me. - As an organization owner, I want important updates surfaced clearly so that I can understand changes that may affect my team. - As a developer, I want to create curated update entries so that users receive meaningful communication instead of raw commit logs. - As a developer, I want to see shipped commits and attach them to update entries so that I can verify all relevant work has been communicated. - As a developer, I want to mark commits as internal-only so that refactors, chores, and infrastructure work do not pollute the user-facing update feed. - As a developer, I want optional email digests for inactive users so that alpha/beta users who do not log in still learn about important changes. - As a developer, I want to manually send an email announcement for a published update so that I can deliberately announce important alpha/beta changes. ## Product Model ### Release Update A release update is a curated, user-facing communication entry. Fields: - title - summary - body - category - importance - audience - status - published timestamp - optional deployment label, build version, or commit range Categories: - `Feature` - `Improvement` - `Fix` - `BreakingChange` Importance: - `Normal` - `Important` Audiences: - `Everyone` - `OrganizationOwners` - `Developers` Statuses: - `Draft` - `Published` - `Archived` Only `Published` entries appear to normal users. ### Release Commit A release commit is a developer-facing record of a Git commit that may need to be matched to a release update. Fields: - commit SHA - short SHA - subject - author name/email - authored timestamp - committed timestamp - source branch or deployment label when available - optional pull request or external URL when available - communication status - optional linked release update id Communication statuses: - `Unreviewed` - `Linked` - `InternalOnly` - `Ignored` `Linked` commits are attached to one release update. `InternalOnly` commits represent real shipped work that should not be visible to users, such as refactors, dependency updates, infrastructure maintenance, or test-only work. `Ignored` is reserved for commits that should be excluded from the reconciliation view, such as merge noise or accidental imports. ### Read State Read state is tracked per user and release update. The system should not rely only on the user's last login timestamp. Login is one opportunity to surface unread updates, but the durable behavior is: a user has unread published release updates until those updates are marked read. ## Frontend Areas - What’s New badge or entry in the authenticated app shell - `/app/updates` - Optional login-time What’s New panel for unread important/recent entries - Developer-only release communication back office: - `/app/developer/updates` - `/app/developer/updates/:id` - `/app/developer/release-commits` Feature-owned frontend code belongs under: ```txt frontend/src/features/release-communications/ ``` ## Backend Module Backend feature code should live under: ```txt backend/src/Socialize.Api/Modules/ReleaseCommunications/ ``` Release communications are global SaaS operator data. They are not workspace-owned workflow data. ## Access Rules - Authenticated users can list and read published release updates visible to their audience. - Only users with the `Developer` role can create, edit, publish, archive, or delete draft release updates. - Only users with the `Developer` role can view release commits and commit communication status. - Developer-only entries are visible only to users with the `Developer` role. - Organization-owner entries are visible only to users who are owners of at least one organization. - Archived published entries remain visible in the full update history unless a future retention task changes that behavior. ## User-Facing Behavior - The app shell shows an unread count for visible published release updates the current user has not read. - `/app/updates` lists visible published updates sorted by newest first. - Users can mark one update as read. - Users can mark all visible updates as read. - Opening an update from the unread surface should mark that update as read. - Login may show a non-blocking What’s New panel when unread updates exist. - Important unread updates should be easier to notice than normal unread updates. - The update feed should not expose raw commit subjects, commit SHAs, branch names, or internal-only work. ## Developer Back Office Developers need a reconciliation workflow that connects the real shipped commit history to curated communication entries. The back office should support: - create draft update entries - edit draft entries - publish entries - archive published entries - list imported commits - filter commits by communication status - search commits by subject, SHA, author, or linked update - link one or more commits to an update entry - unlink a commit from an update entry - mark commits as internal-only - mark commits as ignored - show an "unreviewed commits" count - show linked commits on update detail pages The first implementation can import commits through an explicit submitted payload. Repository-backed import must use configured repository connection settings; the application must not assume the deployed filesystem contains a `.git` directory. ## Commit Import Rules - Commit import should be idempotent by commit SHA. - Imported commits should not create user-facing update entries automatically. - Commit subjects should remain visible only in the developer back office. - A commit can be linked to at most one release update in v1. - A release update can link many commits. - Imported commits default to `Unreviewed`. - Merge commits may be imported but can be marked `Ignored`. - Commit import should support a bounded range, such as `sinceSha..untilSha` or `sinceDate..untilDate`. - Repository URL and access credentials belong in configuration/secrets, not hard-coded docs or code. ## Email Digest Email is useful during alpha/beta but should be digest-based and rate-limited. Initial email behavior: - disabled unless explicitly enabled by configuration - sends at most once per user per day - sends only when the user has unread visible published updates - sends only when the user has not logged in or opened the app in at least 24 hours - initially targets organization owners - includes concise summaries and a link back to the app Developer-initiated push email behavior: - available only to users with the `Developer` role - sends from a published release update - uses the release update audience to determine eligible recipients - supports a confirmation step before sending - supports an optional "send to me only" test mode - records when the update was manually emailed, who sent it, and how many recipients were queued or sent - should prevent accidental duplicate sends for the same update unless the developer explicitly confirms a resend - should use the same concise email template as digest emails, focused on the selected update Email delivery should use the existing email infrastructure. Do not introduce a new provider. Email preferences are out of scope for the first email task. A later task can add user or organization notification preferences. ## API Expectations Initial user-facing API: ```txt GET /api/release-updates GET /api/release-updates/unread POST /api/release-updates/{id}/read POST /api/release-updates/read-all ``` Initial developer API: ```txt GET /api/developer/release-updates POST /api/developer/release-updates GET /api/developer/release-updates/{id} PUT /api/developer/release-updates/{id} POST /api/developer/release-updates/{id}/publish POST /api/developer/release-updates/{id}/archive POST /api/developer/release-updates/{id}/send-email GET /api/developer/release-commits POST /api/developer/release-commits/import POST /api/developer/release-commits/{sha}/link POST /api/developer/release-commits/{sha}/unlink POST /api/developer/release-commits/{sha}/internal-only POST /api/developer/release-commits/{sha}/ignore ``` Backend contract changes require OpenAPI regeneration while the backend is running. ## Localization User-facing release communication UI must be available in English and French. Developer-only back-office labels should also be localized when they appear in the app shell. ## Out Of Scope For V1 - Fully automatic update generation from Git commits - Reading commits from the deployed app filesystem - Public release notes pages - Per-user or per-organization email preferences - Scheduled publishing - Targeting individual users or individual organizations - Rich content blocks beyond plain text or basic markdown-style text - Attachments or screenshots - Multiple release streams - Requiring semantic version numbers - Linking one commit to multiple update entries ## Done When - [ ] Developers can create and publish curated release updates. - [ ] Authenticated users can see visible published updates. - [ ] Users can tell which updates are unread. - [ ] Users can mark updates read individually and in bulk. - [ ] The app shell surfaces unread update counts. - [ ] Developers can import commits into a reconciliation list. - [ ] Developers can link commits to update entries. - [ ] Developers can mark commits internal-only or ignored. - [ ] User-facing update views do not expose internal commit details. - [ ] Optional email digest and manual push-email behavior are documented and implemented in a separate task. - [ ] Backend build and tests pass. - [ ] Frontend build passes. - [ ] OpenAPI is updated after backend contracts are implemented.