Skip to content

UC-21 Staff send a reminder that reaches a student's in-app feed

Primary actor SHS Staff (Admin)
Supporting actors Student; the scheduler (a CronJob on the demo tier, EventBridge Scheduler in production)
Priority Should
Satisfies FR-B7, FR-C8
Precondition Students are enrolled in a published challenge with notifications enabled.
Trigger The scheduler proposes a reminder, or an admin composes one.

Main success scenario

  1. On its cadence, the scheduler proposes draft reminders from challenge data: a week opening, a challenge ending soon. Each proposal is made once.
  2. An admin works the queue: send, edit then send, or skip each draft, or compose a broadcast to the whole challenge or only to students whose current week is incomplete. The queue shows the audience size.
  3. Approving publishes the reminder. A scheduled row is terminal and appears in every targeted enrolled student's in-app banner at once, for 14 days.
  4. Every decision is audited: who approved, edited or skipped, and when.

Extensions

  • 2a. The challenge is muted (notifications_enabled false). Approval is refused with 409 and the challenge's reminders leave the feed.
  • 3a. A student dismisses a reminder. It stays dismissed for that student.
  • Direct calls to the staff queue by a student are rejected as unauthorised.
  • Push, device registration and opt-in preferences were retired (ADR 0002). In-app is the only channel.

Acceptance criteria (Gherkin)

Feature file Test module
notification_scheduling.feature test_notification_scheduling_bdd.py
staff_notification_queue.feature test_staff_notification_queue_bdd.py
single_channel_notification_lifecycle.feature test_single_channel_notification_lifecycle_bdd.py
in_app_reminder_banner.feature test_in_app_reminder_banner_bdd.py

Plain pytest: test_notification_scheduling.py, test_staff_notification_queue.py, test_single_channel_notification_lifecycle.py, test_in_app_reminder_banner.py. Frontend: NotificationQueue.test.tsx, ReminderBanner.test.tsx.

Views

Code: backend/app/services/notification_scheduling.py, notification_queue.py, notification_feed.py, notification_content.py, backend/app/routers/notifications_queue.py, backend/app/routers/notifications.py, frontend/src/components/admin/NotificationQueue/, frontend/src/components/ReminderBanner/. ADR 0002 records the channel decision.