feat: a public notes page per release, for clients

On the releases page, «Página pública» (owners and admins) opens a
secret link to a page with the release's notes, readable without an
account, also for private projects: the notes written, or the draft
from its finished tickets while there are none (without repeating the
title the page already shows). The link can be copied, renewed (the old
one stops working) or withdrawn. Stored in Mongo (`release_note_shares`).

API: shareReleaseNotes / unshareReleaseNotes / releaseNotesShare,
publicReleaseNotes(token); GET/PUT/DELETE /api/releases/{id}/public-notes,
GET /api/shared/release-notes/{token}. Web: /notes/:token.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-20 20:57:40 +02:00
parent 3a46a236e4
commit 8ed16f133e
27 changed files with 2158 additions and 6 deletions

View File

@@ -317,6 +317,12 @@ stateDiagram-v2
uno pasa por los comandos normales (permisos, flujo, sprints y releases abiertos) y puede negarse sin parar al resto;
la respuesta dice cuáles. La web parte selecciones mayores (la Lista enseña hasta 200) en tandas de 100, una tras
otra, y suma el resultado.
- **Notas públicas de una release**: quien gestiona el proyecto abre un enlace secreto con las notas de una release,
para clientes y sin cuenta (también en proyectos privados): `shareReleaseNotes(releaseId, renew)`,
`unshareReleaseNotes`, `releaseNotesShare`; `GET/PUT/DELETE /api/releases/{id}/public-notes`. La página
(`publicReleaseNotes(token)`, `GET /api/shared/release-notes/{token}`, la web en `/notes/{token}`) enseña las notas
escritas o, mientras no las haya, el borrador de sus tickets terminados (`written: false`). Renovar hace un enlace
nuevo; retirarlo, o borrar la release, lo deja sin efecto. Vive en MongoDB (`release_note_shares`).
- **Archivar una release**: `archiveRelease(releaseId, moveTo)` / `POST /api/releases/{id}/archive` (`{ moveTo }`).
Sus tickets sin terminar pasan a `moveTo` (otra release abierta del mismo proyecto) o, sin él, se quedan sin release;
los terminados se quedan, como registro de lo que salió. Igual que al cerrar un sprint con `carryOverTo`.