feat(admin): notification operations — resend activation, delivery status, RBAC-scoped views

- notification-routes.js: global list (owner/admin only), per-student list (scoped via
  requireStudentRelationshipAccess), resend-activation (mechanically the same as
  regenerate — Phase 5A's token model already guarantees only the latest is ever valid, so one
  action covers both), a dev-only preview route (unconditionally refuses when
  COOKIE_SECURE=1, mirroring student-auth-routes.js's existing dev_reset_token gate).
- NotificationsView.jsx: owner/admin global notification list, paginated, matching
  AuditView.jsx's exact convention.
- StudentsView.jsx: student detail gained a Resend activation control and a Notifications
  history card; Credentials card now explains the automatic-email behavior.
- AdminPortal.jsx: new Notifications nav entry (owner/admin only).
This commit is contained in:
2026-08-25 14:43:10 -05:00
parent 3c7f0ca59c
commit f25535027c
5 changed files with 211 additions and 3 deletions
+6
View File
@@ -128,4 +128,10 @@ export const adminApi = {
activateEnrollment: (id) => post(`/api/admin/enrollments/${id}/activate`),
cancelEnrollment: (id) => post(`/api/admin/enrollments/${id}/cancel`),
studentEnrollments: (studentId) => get(`/api/admin/students/${studentId}/enrollments`),
// ── Phase 5C §15/§16: enrollment operations & communications ────────────────────────────
notifications: (page = 1) => get(`/api/admin/notifications?page=${page}`),
studentNotifications: (studentId) => get(`/api/admin/students/${studentId}/notifications`),
resendActivation: (studentId) => post(`/api/admin/students/${studentId}/resend-activation`),
sendEnrollmentConfirmation: (studentId, enrollmentId) => post(`/api/admin/students/${studentId}/send-enrollment-confirmation`, enrollmentId ? { enrollment_id: enrollmentId } : undefined),
}