docs: scope the "What's New" in-app announcement feature
Extends ChangelogEntry with an optional highlights field (editorial, per-version, plain language -- most versions won't have one) instead of forking a second content source. One new users column (lastSeenChangelogVersion, backfilled to current APP_VERSION on migration so existing users aren't flooded with history), two routes, one component mirroring NotificationBell's existing bell/badge/dropdown shape.
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
# "What's New" Plan
|
||||
|
||||
## Status: planning only — nothing in this doc is implemented yet
|
||||
|
||||
The problem this solves: `apps/web/lib/changelog.ts`'s `CHANGELOG` array is
|
||||
a dev log — migration reminders, bug-fix jargon, internal notes ("not
|
||||
applied in sandbox") mixed in with real feature announcements. Correctly
|
||||
not public (per `VITRINE_PLAN.md` §6, which flagged this gap). Users have
|
||||
no clean way to see what's new since they last looked.
|
||||
|
||||
**Existing precedent to mirror, not reinvent**: `apps/web/components/social/notification-bell.tsx`
|
||||
is exactly this UI shape already — bell icon, unread badge, dropdown list,
|
||||
polling `GET` on an interval, a "mark read" POST. Same skeleton, new data
|
||||
source.
|
||||
|
||||
---
|
||||
|
||||
## 1. Content — extend `ChangelogEntry`, don't fork a second data source
|
||||
|
||||
Add one optional field to the existing type in `apps/web/lib/changelog.ts`:
|
||||
|
||||
```ts
|
||||
export type ChangelogEntry = {
|
||||
version: string;
|
||||
date: string;
|
||||
added?: string[];
|
||||
fixed?: string[];
|
||||
security?: string[];
|
||||
notes?: string;
|
||||
highlights?: string[]; // user-facing, plain language — only set on entries worth telling users about
|
||||
};
|
||||
```
|
||||
|
||||
Only versions with `highlights` populated ever show up in the "What's New"
|
||||
panel — everything else in `CHANGELOG` stays exactly as dev-facing as it is
|
||||
today. This is a deliberate editorial step, not automatic: when a version
|
||||
ships something a real user would care about, someone (you) writes one or
|
||||
two `highlights` lines in plain language, same commit as the `added`/`fixed`
|
||||
entries. Retroactively, only add `highlights` to past entries actually worth
|
||||
surfacing — no need to backfill all 47+ versions, most were internal
|
||||
fixes/refactors nobody needs a notification about.
|
||||
|
||||
---
|
||||
|
||||
## 2. Schema
|
||||
|
||||
One column, `apps/web/packages/db/src/schema/users.ts`:
|
||||
```ts
|
||||
lastSeenChangelogVersion: text("last_seen_changelog_version"),
|
||||
```
|
||||
Nullable. On the migration, backfill existing users to the current
|
||||
`APP_VERSION` at migration time (not `null`) — otherwise every existing
|
||||
user sees the entire history of `highlights` entries as "new" the moment
|
||||
this ships, which is noise, not a useful announcement. New signups after
|
||||
this ships get set to `APP_VERSION` at account-creation time for the same
|
||||
reason — someone who just joined doesn't need to be told about features
|
||||
that existed before they showed up.
|
||||
|
||||
---
|
||||
|
||||
## 3. API
|
||||
|
||||
- **`GET /api/v1/whats-new`** — compares the user's `lastSeenChangelogVersion`
|
||||
against `CHANGELOG` (imported directly, no DB query needed for the content
|
||||
itself — it's a static in-code array), returns every entry with
|
||||
`highlights` whose version is newer (semver comparison, not string
|
||||
comparison — `"0.9.0" < "0.10.0"` is false under plain string compare).
|
||||
A tiny local semver-compare helper is enough; no need for a package for
|
||||
a 3-segment version string this app already controls end to end.
|
||||
- **`POST /api/v1/whats-new/seen`** — sets `lastSeenChangelogVersion` to the
|
||||
current `APP_VERSION` for the calling user. Called when the panel opens
|
||||
(or on explicit dismiss — same UX choice `NotificationBell`'s `markAllRead`
|
||||
already made for regular notifications, mirror whichever this app's
|
||||
notifications settled on).
|
||||
|
||||
Both gated by `requireSessionOrApiKey`, same as every other authenticated
|
||||
route — no new auth pattern needed.
|
||||
|
||||
---
|
||||
|
||||
## 4. UI
|
||||
|
||||
New component `apps/web/components/layout/whats-new-bell.tsx`, structurally
|
||||
identical to `NotificationBell`: bell/gift icon, badge showing count of
|
||||
unseen highlighted versions, dropdown listing them (version, date, bullet
|
||||
list of that version's `highlights`), placed in `apps/web/components/layout/nav.tsx`
|
||||
next to the existing `NotificationBell`/`MessagesNavLink` icons in the
|
||||
authenticated header.
|
||||
|
||||
Not a public/vitrine concern — this lives entirely inside the authenticated
|
||||
app shell, unrelated to `VITRINE_PLAN.md`'s route group.
|
||||
|
||||
---
|
||||
|
||||
## 5. Rollout order
|
||||
|
||||
1. Schema migration (backfill existing users to current `APP_VERSION`) — no visible change yet.
|
||||
2. `highlights` field on `ChangelogEntry` + write it for the next few versions going forward, so there's something to show once the UI ships.
|
||||
3. API routes.
|
||||
4. `WhatsNewBell` component wired into `nav.tsx`.
|
||||
5. Retroactively add `highlights` to a handful of past standout versions (the tier system, the cooking-assistant tools, followers-only visibility) if you want new/returning users to see a bit of history on first exposure, not just what ships after this point.
|
||||
Reference in New Issue
Block a user