4ef36ac794
Made every executive-meetings write surface broadcast a realtime
`executive_meetings_changed` event so all open schedule tabs refetch
the affected day(s) within ~1s instead of waiting for a manual refresh.
What changed
- `artifacts/api-server/src/lib/realtime.ts`: added
`emitExecutiveMeetingsDaysChanged(dates)` — a thin dedup wrapper around
the existing single-date emitter so handlers that may touch two days
(PATCH that reschedules across dates, approved reschedule requests)
can emit both with one call.
- `artifacts/api-server/src/routes/executive-meetings.ts`: added emit
calls to every mutation handler that previously lacked one:
* POST /executive-meetings (create)
* DELETE /executive-meetings/:id
* PUT /executive-meetings/:id/attendees
* POST /executive-meetings/:id/duplicate
* POST /executive-meetings/reorder
* PATCH /executive-meetings/requests/:id (approve+apply)
The PATCH /:id handler now emits BOTH the old and the new meetingDate
so a viewer on the source day loses the row and a viewer on the target
day gains it. The request-approve handler captures the meeting's
pre-apply and post-apply date inside the transaction so reschedule
approvals also fan out to both days.
Frontend
- No frontend changes were needed. `useNotificationsSocket` already
subscribes to `executive_meetings_changed` and invalidates the
`["/api/executive-meetings", date]` query — the same key
`refreshDay()` invalidates on the schedule page.
Verification
- API server build + boot: clean.
- Ran the api-server executive-meetings test suites
(`executive-meetings.test.mjs`, `executive-meetings-merge.test.mjs`,
`executive-meetings-visibility.test.mjs`) — all 38 tests pass when
run sequentially. (Concurrent runs surface a pre-existing
daily_number unique-constraint flake unrelated to this change.)
- Pre-existing TypeScript errors are unchanged; no new errors introduced.
Followed task scope strictly: realtime fan-out only, no UI or schema
changes. Proposed follow-up #219 to add automated test coverage for the
emit-on-write contract so it cannot silently regress.