Repository navigation
fix(meetings): add an auth guard to the past-meeting admin route #3265
Description
Requirements: FR-054 in
specs/011-meeting-details-redesign/requirements.md. State model:state-matrix.mdin the same directory.
Branch: PRs for this issue target the integration branchfeat/meeting-details-v2, notmain. Nothing in this epic reaches production until the release PR #3249 merges.
Security change (R06): ships in its own PR, into the integration branchfeat/meeting-details-v2. Decided 2026-10-05 by the project owner: it does not go tomainfirst. It ships with the rest of V2 through #3249.
Prototype settings panel: time / viewer / privacy / rsvpTracking / pastAccess / myRsvp / recur / via / pageStatus. Its look and feel differs from the current app on purpose — follow it.
Epic: #1765 · Meetings v2 epic: #1451 · Plan ID: N-03 · Size: S · Depends on: E0-03
Delivery: this ships as part of meeting details V2, side by side with the existing page, behind
MEETING_V2_ENABLED_FLAG. Do not modify, refactor or delete the existing meeting details page. V1 stays fully functional and is what untargeted users see. Parent: Meetings v2 epic #1451. Full rules in #1765.
Components: follow the prototype for design, but build it from the existinglfx-*components inapp/shared/components/. Extend a wrapper before forking it; create a new component only when the design can't be expressed otherwise, and say so in the PR.
Problem. /meetings/:id/details has no canActivate. It was tolerable while the route was an unreachable read-only orphan. It is not tolerable now: it hosts organizer-only write actions (attendance reconciliation, participant create / update / delete), and per GH #2251 it is becoming the surface Manage-role users are deliberately routed to. Protection today is only the Express catch-all, which authenticates but does not authorize.
Scope. Add an explicit guard aligned to the Manage-vs-View role model that #2251 establishes. Decide and implement what a View-role or anonymous user hitting the URL directly sees — redirect to the public page is the likely answer, not a 404.
Acceptance criteria
- Route carries an explicit
canActivate; server-side authorization is not weakened in exchange. - View-role and anonymous users get a defined outcome, documented in the ADR.
- Cross-references GH fix(meetings): route past-meeting details by Manage vs View role, surface Reconcile Attendance #2251 and PR fix(meetings): route past-meeting details by role, surface reconcile action #2252 so the two efforts do not collide.
- Own PR — CONTRIBUTING forbids mixing security changes with feature work.
Added 2026-10-05: E0-03 decision (meeting-surface-boundary.md, merged in #3268), § Who sees what on /details:
- The guard resolves
organizerthrough the detail path (GET /api/past-meetings/:uid,isPastMeetingOrganizer), not the list's. - Organizer → the admin page. Signed-in non-organizer → redirect to
/meetings/:id. Anonymous → the existing login redirect. - 400/403/404 →
/meetings/not-found. Any other failure → a load-error state with retry; the admin page stays closed. - Manage role = organizers only, pending @MRashad26's confirmation on docs(meetings): record the public and admin meeting surface boundary #3268.
Filed from meeting-details-redesign-implementation-plan.md (revised 2026-09-23).
Activity
docs(meetings): add the v2 rollout and retirement plan (#3267)
docs(meetings): add the v2 rollout and retirement plan (#3267)