Files
bookorbit/docs/whats-new-authoring-guide.md
T
neon c4ab4a9153 feat: add in-app release notes viewer
Introduces a new feature to fetch, parse, and display app release notes
and update highlights directly within the UI.

- Backend: Adds the `release-notes` module to fetch GitHub releases
  and parse markdown highlight sections.
- Frontend: Adds the `WhatsNew` dialog and view, including custom
  markdown rendering and an image lightbox for update media.
- Tools: Adds validation scripts (`whats-new-lint`, `whats-new-preview`)
  to ensure release content parses correctly before publication.
2026-06-18 03:37:53 +00:00

7.7 KiB

Authoring the "What's New" highlights

This is the end-to-end guide for writing the ## Highlights section of a GitHub release so it powers BookOrbit's in-app What's New popup and the /whats-new archive. It is the single source of truth for both the workflow and the format.

How it shows up in the app

  • Popup: when a user opens the app on a newer version than they last saw, a popup shows the highlights for the versions they missed (newest expanded, up to 4 versions cumulatively).
  • Archive: the /whats-new page lists every release (highlights + full changelog).
  • Caching: the server fetches and caches releases for about 10 minutes, so edits appear within a few minutes (immediately on a server restart). No redeploy is needed.
  • No highlights, no popup: a release with no ## Highlights section (or the scaffold left in place with no bullets) simply shows no popup. Its changelog still appears in the archive. That is fine for patch releases with nothing user-facing to call out.

Walkthrough (every release)

  1. Cut the release. Run the release workflow (Actions -> Release -> Run workflow on main). semantic-release creates the GitHub release as a draft and the Docker images (:latest and :<version>) are built and pushed. The draft is not visible in the app yet.
  2. Open the draft to edit. Go to the repo's Releases, click the draft (or open https://github.com/bookorbit/bookorbit/releases/edit/<tag>), and click the edit (pencil) icon.
  3. Review the candidate highlights. The ## Highlights scaffold contains a commented list of this release's feat commits as starting candidates. Curate them: keep the user-facing ones, reword them into friendly benefit-focused lines, and delete the rest.
  4. Write the bullets above the comment block, one per highlight (see the format below).
  5. Add an icon to a bullet by ending the line with <!-- icon: Name --> (optional).
  6. Add media by dragging an image or video into the editor (see the media rules below).
  7. Delete the scaffold comment block once you are done with it.
  8. Validate: from server/, run pnpm whats-new:check <tag> (lints, then previews exactly what the app will render and checks media reachability). Fix any warnings.
  9. Publish. Click Publish release. Within ~10 minutes the popup appears for users on this version. (Until you publish, the draft stays hidden in the app even though :latest is already live, so do not leave it unpublished.)

Copy-paste starter

## Highlights

- **Two-way Kobo highlight sync** - Your highlights now sync both ways with Kobo, so a note on the device shows up on the web and vice versa. <!-- icon: BookHeart -->
- **Instant library scroll** - The alphabet jump rail is now instant on libraries with thousands of books. <!-- icon: Zap -->
- **Audiobook chapters** - Chapter markers are extracted and shown in the player; jump straight to any chapter. <!-- icon: Headphones -->

  <img width="800" alt="chapters" src="https://github.com/user-attachments/assets/REPLACE-WITH-DROPPED-IMAGE" />

- **Smaller fixes** - A batch of polish across the reader and library grid.

Format reference

Heading

  • The section heading must be exactly ## Highlights.
  • Everything after the next heading (## / ###) or a --- rule is treated as the technical changelog, not a highlight.

Bullets

  • One highlight per line, starting with - .
  • Shape: - **Title** - one or two friendly sentences.
  • **Title** is the bold headline; the text after the - is the description.

Icons (optional)

  • End the bullet with an HTML comment GitHub renders as nothing: <!-- icon: Name -->. It can also sit on its own indented line right below the bullet.
  • Name is a PascalCase lucide icon name (e.g. BookHeart, Zap, ShieldCheck, Headphones, Film). Omit the comment for the default icon (Sparkles).
  • Unknown names fall back to the default; the lint warns so you can fix a typo.
  • The old - [Icon] **Title** ... prefix still parses but renders as literal [Icon] text on the GitHub page, so the lint warns against it. Use the comment form.

Media (optional)

  • Drag an image or video into the GitHub release editor. GitHub uploads it and inserts either an <img ... src="https://github.com/user-attachments/assets/..."> tag (images) or a bare https://github.com/user-attachments/assets/... URL (videos). Leave whatever it inserts as-is.
  • Only GitHub-hosted media renders: github.com/user-attachments/... or any *.githubusercontent.com host. Media from other hosts (imgur, etc.) is dropped (the text is kept) and the lint warns.
  • Image vs video is detected by file extension (.mp4, .webm, .mov, .m4v, .ogv, .ogg are video); GitHub's extension-less attachment URLs are probed for their content type.
  • You can attach several media to one bullet (put each on its own line under it). They render as a horizontal gallery; clicking an image opens a carousel. At most 6 media per highlight render; extras are dropped (the lint warns).

Soft limits (the app clamps and the lint warns; nothing breaks)

  • Title up to 120 characters, body up to 400 characters (visually line-clamped in the popup; the full text stays in the archive and search).
  • Up to 12 highlights per release.

Validate before publishing

Run from server/:

  • pnpm whats-new:check <tag> - the one-stop check: lints, then previews exactly what the app renders (including a media reachability probe). Exits non-zero if the lint fails.
  • pnpm whats-new:lint <file.md> / pnpm whats-new:lint --tag <tag> - static validation only. Add --strict to treat warnings as failures.
  • pnpm whats-new:preview [tag] - render preview only.

Point these at a different repo for testing with the GITHUB_RELEASES_REPO env var (and GITHUB_RELEASES_TOKEN for private repos / rate limits), or pass --repo owner/name to preview.

Pre-publish checklist

  • pnpm whats-new:check <tag> is clean (no errors; warnings addressed).
  • Each bullet is - **Title** - benefit., short and user-facing.
  • Icons are valid PascalCase lucide names (no typos), or omitted for the default.
  • Media was dragged in (GitHub-hosted), no more than 6 per highlight.
  • Titles <= 120 chars, bodies <= 400 chars.
  • The scaffold candidate/instruction comment block is deleted.
  • Clicked Publish release (the draft is not enough).

Common mistakes

Symptom Cause Fix
Highlight shows the default Sparkles icon Icon name typo / not a lucide name Correct the PascalCase name (lint says which)
[Icon] text shows on the GitHub page Legacy [Icon] prefix Move the icon into a <!-- icon: Name --> comment
Image/video does not appear Media not GitHub-hosted Drag the file into the editor (do not paste an external URL)
Only 6 of N images show Over the per-highlight media cap Keep the best 6
Title/body looks cut off in the popup Over the soft length cap Shorten it (full text stays in the archive)
No popup for the release No ## Highlights bullets, or release left as a draft Add bullets and click Publish