46ce8e64e43da48f386d5c175cf7095711294e89
Per-row highlight colors on the Executive Meetings daily schedule were
stored in each browser's localStorage, so a color set by the admin on
their laptop never reached the executive office or the big-screen
viewer. Move the color into a shared, server-stored field on the
meeting row so every viewer sees the same color in real time.
Schema
- Add nullable `row_color varchar(16)` to `executive_meetings`
(lib/db/src/schema/executive-meetings.ts). Migration applied via
`pnpm --filter @workspace/db push`.
API (artifacts/api-server/src/routes/executive-meetings.ts)
- Whitelist ROW_COLOR_KEYS = red/amber/green/blue/violet/gray.
- Extend meetingPatchSchema with optional `rowColor` (nullable enum).
- Existing PATCH /executive-meetings/:id picks it up, stamps
updatedBy, writes the standard audit-log entry, and fires
emitExecutiveMeetingsDaysChanged so other viewers' day query
invalidates and re-fetches.
- Permission gating unchanged: requireMutate → executive_viewer 403.
Frontend (artifacts/tx-os/src/pages/executive-meetings.tsx)
- `rowColors` is now derived from the meetings query via useMemo.
The localStorage write effect is removed.
- New async setRowColor() PATCHes the server and invalidates the day
query (key ["/api/executive-meetings", date]).
- Best-effort migration of legacy localStorage colors:
- drops invalid keys / unknown colors immediately,
- skips ids the server already colored (no overwrite),
- PATCHes ids in the currently loaded day,
- PRESERVES ids for dates the user hasn't visited yet so they
migrate when they do navigate there (architect review caught a
data-loss bug in the first cut where unvisited-day entries were
being deleted),
- keeps failed PATCHes for retry, removes the localStorage key
only once nothing is left,
- in-flight Set prevents double-PATCH if the effect re-fires.
Tests
- New artifacts/api-server/tests/executive-meetings-row-color.test.mjs
covers PATCH set / clear / invalid-key 400 / viewer 403 / audit
attribution. All 5 pass.
- E2E (runTest) verified two browser contexts share the color
without manual refresh.
Documentation
- replit.md: added "Task #288 — Shared row colours" section.
Drift / notes
- Pre-existing TS errors in admin.tsx and pre-existing isHighlighted /
font_settings scope errors in executive-meetings.ts are unrelated
to this change.
- Follow-up #293 proposed: add a DB-level CHECK constraint mirroring
the API whitelist for defense-in-depth.
Description
No description provided
Languages
TypeScript
69.4%
JavaScript
29%
CSS
0.6%
Shell
0.6%
Dockerfile
0.2%
Other
0.2%