v2 Admin Spec — Communication (New 9th Domain)

Communication

Domain 9 of the v2 navigation structure (NEW domain — IA shifts from 8+1 to 9+1 domains). Contains: Automation Emails (absorbed, enhanced), Blast Emails (NEW), Push Notifications (absorbed, enhanced), Announcement Board (NEW), Private Messages (NEW), Communication Logs (NEW). This domain is entirely new. It consolidates outbound communication previously scattered across Semester Management (Email Management) and Admin & System (Notifications), and introduces four net-new channels. Primary workflows served: WF1 (Semester Setup — welcome and onboarding emails), WF2 (Student Support — 1:1 messaging, pre-drafted TA communication), WF4 (Daily Monitoring — announcement board, urgent push notifications)


1. Domain Overview

Communication is a new top-level domain introduced in v2 (ADR-003). It unifies all outbound communication — automated emails, blast email campaigns, push notifications, announcements, and 1:1 messaging — into a single sidebar section with a consistent compose/preview/send pattern, shared recipient filtering, and a unified delivery log.

Two categories of communication live here:

The Communication Logs screen provides a unified audit trail across all six channels.

1.1 Domain Boundary: Issue Queue Stays in Admin & System

ADR-003 explicitly preserves Issue Queue (10-admin-system.md §6) in Admin & System. Issue Queue is ticketed support — students report app problems, admins triage and resolve them with a state machine (Under Review / In Progress / Resolved). It is not messaging: there is no freeform thread, no inbox paradigm, no TA routing.

Private Messages (this domain §6) is the messaging channel. If a student opens an issue ticket and then needs a conversational follow-up, the admin can initiate a Private Message from the issue detail view (Admin & System > Issue Queue > Issue Detail > "Start Message" action, deep-linking to Communication > Private Messages with prefilled recipient).

1.2 Identity Model: No Impersonation, Pre-draft Instead (ADR-004)

Admins cannot send communications "as" a TA. The original "Send as TA" proposal was rejected because it would have required dual-identity records (composed_by, sent_as), reply-routing logic, and TA-awareness notifications across every communication screen.

Instead, the domain uses a pre-draft pattern:

  1. Admin composes a message and selects "Draft for TA" → picks a TA from dropdown → saves draft.
  2. The draft is assigned to that TA's outbox.
  3. The TA reviews the draft in their own account (TA-facing queue is production-only; the mockup shows the admin's "Draft for TA" action but not the TA queue).
  4. The TA edits if desired and hits Send. The message genuinely comes from the TA: authentic sender, correct reply-to, no audit ambiguity.

Communication Logs records a single sender identity per message (the TA who actually sent it, or the admin who sent it directly). There is no composed_by / sent_as split.

Screens supporting the pre-draft pattern (per ADR-004): Private Messages, Blast Emails. Push Notifications and Announcement Board are broadcast channels that don't benefit from personal-sender framing — they always go out under the "QuranFlow" system identity or the posting admin's name.

TA permissions on Announcement Board (per STAKEHOLDER-ANSWERS 2026-04-21, default #6 CHANGED): TAs can post and manage their own announcements on the Announcement Board (edit/delete their own posts, set audience, set expiry). Moderation of other authors' posts remains admin-only. See §5 for full role visibility.

1.3 Workarounds Eliminated

ID Workaround Current Tool Replaced By
C1 No blast email capability External mail merge / manual per-recipient sends Blast Emails screen (Section 3)
C2 Push notifications broadcast to all users only Settings > Notifications (no filtering) Push Notifications with recipient filtering (Section 4)
C3 No in-app announcement channel distinct from push Ad-hoc push spam for non-urgent updates Announcement Board (Section 5)
C4 No admin↔student private messaging WhatsApp / personal email Private Messages (Section 6)
C5 TAs needed impersonation to send "personal" reminders Stakeholder ask during interview Pre-draft pattern per ADR-004 (Section 6, Section 3)
C6 No unified communication audit trail Scattered logs across Stripe, app, email provider Communication Logs (Section 7)
C7 Email Management co-located with semester config (hard to find) Semester Management > Email Management Automation Emails in dedicated Communication domain (Section 2)
C8 Sequence visibility — admin cannot see "what will this student receive next" Manual trace through trigger conditions Automation Emails Sequence View (Section 2.5)

1.4 Data Architecture

Existing tables (preserved from v1):

New tables (v2 additions — to be validated during implementation):

1.5 Shared Recipient Filter (used by Sections 3, 4, 5)

Blast Emails, Push Notifications, and Announcement Board use the same recipient filter pattern. This is specified once here and referenced from each screen.

Filter dimensions (all AND-combined):

Dimension Source Input
Audience Type Hardcoded Multi-select: Students, Teachers, Both
Gender user_profile.gender Multi-select: Male / Female / Unspecified
Level user_link_level_tag (current semester enrollment) Multi-select: 0, 1, 2, 3, 4, Year 2
Mastery Course user_profile.mastery_course or equivalent Multi-select dropdown of active mastery courses
Tags tags via user_tags join Multi-select dropdown of active tags
Semester semesters Dropdown: current semester (default) / any past semester / all

Manual selection (alternative to filters, per stakeholder Apr 15 decision — transcript lines 274–283):

Preview bar (below filter or manual list):

1.6 Cross-Cutting Conventions


2. Screen: Automation Emails

2.1 Purpose

Configure automated email templates that fire on student-lifecycle triggers (registration, week start, semester end, promotion, failure, custom date). Absorbed from v1 Semester Management > Email Management and enhanced with a Sequence View that lets an admin search a student and see every email that student will receive in the future, in order.

The semester-scoped template model is preserved exactly — each template belongs to one semester. The semester selector (previously the page's primary layout element) becomes a filter.

Transition hint: "Formerly under Semester Management > Email Management" — shown for first 30 days.

2.2 Entry Points

2.3 Layout

Two views, toggled at top of screen: Templates (default) | Sequence View.

Templates view: Filter bar + data table (standard Data Table pattern, 01-global-patterns.md §4.1).

Sequence View: Student search box at top + vertical timeline of upcoming emails for the selected student.

2.4 Templates View

2.4.1 Filter Bar

Filter Type Options
Search Text input Filters by template name or subject
Semester Dropdown All active semesters + "All semesters". Defaults to current active semester.
Trigger Dropdown All / On Registration / Week Start / Semester End / On Promotion / On Failure / Custom Date
Status Dropdown All / Active / Draft

2.4.2 Data Displayed

Column Source Sortable Notes
Template Name emails.name Yes (default: alphabetical) Clickable → opens editor. System-seeded templates (see §2.4.5) show a lock icon next to the name.
Subject emails.subject Yes Truncated to 60 chars with tooltip for full text
Trigger Computed from emails.trigger_type + emails.trigger_config Yes "On Registration", "Week 1 start", "Semester End", "On Promotion", "On Failure", "Custom: [date]"
Semester semesters.name via emails.semester_id No Shown when "All semesters" is active in filter
Status emails.status Yes Badge: Active (green) / Draft (blue)
System Seeded (NEW) emails.system_seeded (boolean) Yes Lock icon if true. System-seeded templates cannot be deleted (delete action hidden/disabled with tooltip "System template — can be edited but not deleted").
Last Sent (NEW) Latest communication_logs.sent_at where source_record_id = this template Yes Formatted as "Mar 8, 2026" or "Never" if unsent
Last Edited emails.updated_at Yes Formatted as "Mar 10, 2026"
Actions No Edit / Preview / Test Send / Delete / Draft for TA (icons or "..." menu). Delete is hidden/disabled on system-seeded templates.

2.4.3 Actions

Action Trigger Permission Behavior Confirmation
Create Template "Create Template" button (top-right) Admin Opens email editor (modal, max-width 800px): Template Name, Subject, Trigger (dropdown with config pane per trigger type), Body (rich text with template variables {{student_name}}, {{semester_name}}, {{level}}, {{ta_name}}), Semester (dropdown), Status toggle (Active / Draft). On save: creates emails record. Toast: "Template '[name]' created." No
Edit Edit icon or row click Admin Opens editor pre-filled. All fields editable. Toast on save: "Template '[name]' updated." No
Preview Preview icon (eye icon) All Opens preview modal (max-width 800px). Renders subject + body with sample data: {{student_name}} = "Sarah Ahmed", {{semester_name}} = current semester, {{level}} = "Level 2", {{ta_name}} = "Ustadha Amina". No
Test Send "Test Send" button (in editor or preview) Admin Sends the email to the logged-in admin's email address with sample data. Toast: "Test email sent to [admin email]." No
Delete Delete icon Admin Destructive confirmation: "Delete template '[name]'? If this template is Active, scheduled sends using it will not be executed." On confirm: deletes emails record. Hidden/disabled on system-seeded templates (see §2.4.5) with tooltip "System template — can be edited but not deleted". Destructive
Clone from Previous "Clone All Templates" secondary button (top-right) Admin Dropdown of previous semesters. Shows count ("[Previous Semester] has [N] templates."). Confirmation: "Clone all email templates from [Previous Semester]? [N] templates will be copied as Drafts." Creates independent copies with Status = Draft in current semester. Toast: "Cloned [N] templates." Yes
Draft for TA (NEW) "Draft for TA" option in "..." menu on row Admin Opens a one-time compose modal pre-filled with this template, plus TA selector (dropdown of all TAs). On save: creates a blast_emails record with predraft_for_ta_id set and status = Draft. Toast: "Draft saved for [TA name]." Note: this creates a one-off send, not a recurring automation — use Blast Emails for routine pre-drafted sends. No

2.4.4 Templates View States

State Display
Has templates Template list table
Empty (semester filter active) "No email templates for [Semester Name]." + "Create Template" button + "Clone from [Previous Semester]" button
Empty (all semesters) "No email templates configured." + "Create Template" button
Filtered — no results "No templates match your filters." + "Clear filters" link
Loading Skeleton data table
Error "Unable to load email templates. Please try again." + "Retry" button

2.4.5 System-Seeded End-of-Semester Templates (NEW)

Three system-seeded templates support End Checklist Step 3 (Send Pass/Fail Emails). These templates are system-integral (not deletable; content editable):

Template Name Trigger Condition Audience Source Domain
End of Semester — Pass (L1–L4) End Checklist Step 3 fires for a student with final_status = 'pass' AND level IN (1,2,3,4) Passing L1–L4 students automation (system-seeded)
End of Semester — Fail (L1–L4, Opt-in Repeat) End Checklist Step 3 fires for a student with final_status = 'fail' AND level IN (1,2,3,4) Failing L1–L4 students. Contains opt-in-to-repeat link. Students are NOT automatically re-enrolled — they must follow the link. Opt-in is fully self-service; no admin approval is required (STAKEHOLDER-ANSWERS-2026-04-22 §C Q2). The link directs the student to the repeat-discount checkout (08-billing-payments.md §2.10) which cross-references the per-semester repeat-eligible list. automation (system-seeded)
End of Semester — Mastery Elective Prompt End Checklist Step 3 fires for a Mastery student (level_tag.is_mastery = 1) Mastery students. Prompts signup for same or different elective next semester. automation (system-seeded)

Note: These three templates are system-seeded and cannot be deleted, but their subject lines, bodies, and template variables are admin-editable. Trigger conditions are fixed (driven by End Checklist Step 3). System-seeded templates show a lock icon next to the name in the Templates view and their Delete action is hidden/disabled with tooltip "System template — can be edited but not deleted".

Mockup scope: static mock templates with placeholder bodies; triggering is mock-only.

2.5 Sequence View (NEW)

2.5.1 Purpose

Answer the question: "What emails will this student receive in the future, and when?" Stakeholder ask: "Search a student, see every email they will receive with exact delivery dates."

2.5.2 Layout

Student search at top (autocomplete, as per Global Search §2.2, scoped to students only) → on selection, renders a vertical timeline below.

2.5.3 Timeline Content

Each upcoming email the selected student will receive, based on:

Timeline Item Field Source Notes
Scheduled Date Computed from trigger + semester calendar "Mar 15, 2026 at 9:00 AM EST" or relative "in 14 days"
Template Name emails.name Clickable → opens Preview modal
Trigger Computed "Week 3 start" / "On promotion" / "Semester end" etc.
Subject emails.subject Truncated
Preview Rendered subject + first 200 chars of body with student's values substituted Expandable inline

Open question (OQ-C1): whether Sequence View shows only the selected student's upcoming emails (current assumption) or a sample student as a preview when no student is searched. Per ADR-003, mockup defaults to searched student.

2.5.4 Sequence View Actions

Action Trigger Permission Behavior Confirmation
Search Student Type in search box Admin, View-Only Autocomplete suggestions. On select: loads timeline. No
Preview Email Click timeline item All Opens preview modal with this student's values substituted (real {{student_name}}, actual {{ta_name}}, etc.) No
Send Now "Send Now" button on timeline item Admin Confirmation: "Send '[template name]' to [student name] now? This is outside the normal trigger schedule." On confirm: sends immediately, logs to Communication Logs. Does not remove the scheduled send. Yes
Skip This Email "Skip" button on timeline item Admin Confirmation: "Skip sending '[template name]' to [student name]? This will not affect other students." On confirm: creates a skip record (production: email_skips table) so this specific template will not fire for this student. Yes

2.5.5 Sequence View States

State Display
No student selected "Search for a student above to see their email sequence." + empty-state illustration
Student selected, has upcoming emails Timeline with 1–N items
Student selected, no upcoming emails "[Student name] has no upcoming automated emails." + hint: "This may mean all templates are Drafts or the student is not enrolled."
Student selected, not enrolled "[Student name] is not enrolled in the current semester. Switch semester filter to see past sequences."
Loading Skeleton timeline
Error "Unable to compute sequence. Please try again." + "Retry"

2.6 End Checklist Email Queue (NEW)

2.6.1 Purpose

Per-student queue of End Checklist Step 3 emails that have not yet been sent (or that failed/bounced). Shows each enrolled student's current final_status, the email template that applies to their track (pass / fail-opt-in / mastery-elective), the send status (Unsent / Queued / Sent / Failed / Bounced), and a per-student "Send Now" button to manually trigger the correct template. Provides admin a clear view of who is and isn't emailed during semester close, and a manual fallback for any student the automatic trigger missed.

2.6.2 Scope

All enrolled students in the closing semester. Branched by track:

Leavers are excluded (per STAKEHOLDER-ANSWERS-2026-04-21: "they handle their own enrollment and payment").

2.6.3 Entry Points

2.6.4 Data Displayed

Column Source Sortable Filterable Format
Student Name users.name via enrollment Yes (default: alphabetical) Yes (search) Clickable → Student Detail
Level level_tag.name via user_link_level_tag Yes Yes (dropdown: Level 1 / Level 2 / Level 3 / Level 4 / Mastery) Level badge
Final Status user_link_level_tag.final_status for closing semester Yes Yes (dropdown: Pass / Fail / Mastery Passed / Not Set) Badge: Pass (green) / Fail (red) / Mastery Passed (blue) / Not Set (gray)
Template Derived from track (see §2.6.2) No Yes (dropdown: Pass / Fail / Mastery Elective) Template name (clickable → opens the template in §2.4 for reference)
Send Status communication_logs.status for this student's End Checklist Step 3 email, or "Unsent" if no record exists Yes Yes (dropdown: Unsent / Queued / Sent / Failed / Bounced — default: Unsent + Failed + Bounced) Badge: Unsent (gray) / Queued (amber) / Sent (green) / Failed (red) / Bounced (red)
Last Attempt Timestamp of most recent send attempt (or delivery) Yes No "Mar 15, 2026 at 11:02 AM" or "—" if never attempted
Action No No "Send Now" button (Unsent/Failed/Bounced) / "View Log" link (Sent) / "Awaiting Pass/Fail" pill + Set-Pass/Fail deep-link (Not Set)

2.6.5 Filter Bar

Filter Type Options
Search Text input Student name or email
Level Dropdown All / Level 1 / Level 2 / Level 3 / Level 4 / Mastery
Template Dropdown All / Pass / Fail / Mastery Elective
Send Status Dropdown All / Unsent / Queued / Sent / Failed / Bounced (default: Unsent + Failed + Bounced — the "work to do" subset)

2.6.6 Actions

Action Trigger Permission Behavior
Send Now (per-student) "Send Now" button on an Unsent/Failed/Bounced row Admin Queues the student's correct End Checklist template for send (routed by their track per §2.6.2). On success: updates communication_logs with Queued → Sent; updates row. Toast: "[Template name] queued for [student name]." On failure (provider error): status → Failed with a failure reason shown on hover.
Send Pending Emails (bulk) Checkbox selection + "Send Pending Emails" button in the bulk action bar Admin Queues all selected Unsent/Failed/Bounced students (each routed to their correct template). Confirmation: "Send pending End Checklist emails to [N] students? ([X] pass, [Y] fail, [Z] mastery)." Progress indicator during batch. On completion shows summary.
Retry Failed (filter shortcut) "Retry all Failed" button (top-right, visible when any Failed rows present) Admin Shortcut for selecting all Failed and running Send Pending Emails.
View Log (per-student) "View Log" link on a Sent row Admin, View-Only Opens Communication Logs (§7) filtered to this student + End Checklist email entry.
Set Pass/Fail deep-link (per-student) "Awaiting Pass/Fail" pill on a Not Set row Admin; TA (own students) Navigates to 03-student §2 Students list filtered to this student with Set Pass/Fail ready. Returns here after status is set.
Return to End Checklist Persistent banner at top when ?from=end-checklist is set All roles with queue access "← Return to End Checklist for [Semester Name]." Clicking returns to 04-semester-management.md §3.8 with scroll position preserved.

2.6.7 States

State Display
All sent Green status bar: "All [N] enrolled students have been emailed for [Semester Name]." Step 3 in End Checklist auto-completes.
In progress Mix of Unsent / Queued / Sent / Failed rows. Counts summarized above the table: "[X] Unsent · [Y] Queued · [Z] Sent · [W] Failed · [Q] Bounced".
Awaiting Pass/Fail Students in L1–L4 with final_status IS NULL appear with an "Awaiting Pass/Fail" pill; they are blocked from send until Step 2 sets status.
Not yet applicable If semester phase is Setup or early Active: informational message "End Checklist Step 3 fires during semester close. No sends expected yet." Queue is still viewable.
Loading Skeleton queue rows.
Error "Unable to load Email Queue. Please try again." + "Retry" button.

2.6.8 Role Visibility

2.7 Role Visibility


3. Screen: Blast Emails (NEW)

3.1 Purpose

Compose and send one-off emails to a filtered or manually selected list of students/teachers. Unlike Automation Emails (event-triggered, per-student), Blast Emails are admin-initiated, multi-recipient, one-time sends. Supports pre-drafting for TAs (ADR-004).

3.2 Entry Points

3.3 Layout

Two views: Campaigns (list of past/scheduled/draft blasts, default) | Compose (full-screen compose).

3.4 Campaigns View

3.4.1 Filter Bar

Filter Type Options
Search Text input Filters by campaign name or subject
Status Dropdown All / Draft / Scheduled / Sent / Failed
Sender Dropdown All / Me / [list of admins]
Date Range Date range picker Sent date range

Note on "Scheduled" records: Scheduling is production-only per STAKEHOLDER-ANSWERS-2026-04-21 (default #5). The Schedule button is removed from the Compose view (§3.5.3), so the mockup cannot create Scheduled campaigns. The Status filter, Scheduled For column, and Cancel Scheduled action are retained for forward-compatibility with production (where Scheduled records will exist) but mockup fixtures will contain no Scheduled rows.

3.4.2 Data Displayed

Column Source Sortable Notes
Campaign Name blast_emails.name Yes Clickable → opens detail/preview
Subject blast_emails.subject Yes Truncated to 60 chars
Recipients Count from blast_emails.recipient_filter_json evaluation or recipient_manual_ids.length Yes "[N] recipients"
Status blast_emails.status Yes Badge: Draft (blue) / Scheduled (amber) / Sent (green) / Failed (red)
Sender users.name via blast_emails.sender_user_id, or "[TA Name] (pre-drafted by [admin])" if predraft_for_ta_id set Yes Shows true sender identity per ADR-004
Scheduled For blast_emails.scheduled_for Yes "Mar 15, 2026 9:00 AM" or "—" if sent-immediately
Sent At blast_emails.sent_at Yes (default: descending) Formatted date/time or "—" if unsent
Actions No View / Duplicate / Delete / Cancel Scheduled (icons or "..." menu)

3.4.3 Campaign Actions

Action Trigger Permission Behavior Confirmation
Compose Blast "Compose Blast" button (top-right) Admin Switches to Compose view with empty form No
View Row click or View icon All Opens read-only detail: campaign metadata + rendered email + recipient list + delivery status breakdown No
Duplicate Duplicate icon Admin Opens Compose view pre-filled with this campaign's subject/body/recipient filter. Campaign Name gets " (copy)" suffix. No
Delete (Draft only) Delete icon Admin Destructive confirmation: "Delete draft '[name]'? This cannot be undone." Destructive
Cancel Scheduled "Cancel Schedule" icon (Scheduled status only) Admin Confirmation: "Cancel scheduled send of '[name]' ([N] recipients)? The email will not be sent." On confirm: sets status = Draft, clears scheduled_for. Yes

3.4.4 Campaigns View States

State Display
Has campaigns Data table with campaigns
Empty "No blast email campaigns yet." + "Compose Blast" button
Filtered — no results "No campaigns match your filters." + "Clear filters" link
Loading Skeleton data table
Error "Unable to load campaigns." + "Retry" button

3.5 Compose View

Three-section layout: Recipients (top) → Message (middle) → Review & Send (bottom, sticky).

3.5.1 Recipients Section

Uses the Shared Recipient Filter defined in Section 1.5. Mode toggle: "Filter by Criteria" (default) | "Select Manually".

Live preview bar at bottom of section: "[N] recipients selected. Sarah Ahmed, Ahmed Ali, +12 more."

Save as Audience (optional): "Save this selection as a named audience" — persists the filter JSON for reuse across blasts. Named audiences appear in a dropdown above the filter: "Use Saved Audience →". Open question (OQ-C4): are saved audiences shared across admins or private per admin.

3.5.2 Message Section

Field Type Notes
Campaign Name Text input Internal label; not shown to recipients. Required.
Template Dropdown "Start from scratch" (default) / named templates from email_templates filtered by source_domain in ('blast', 'unified', 'automation') — unified library confirmed per STAKEHOLDER-ANSWERS 2026-04-21. Templates tagged by source_domain are reusable across Automation + Blast contexts.
Subject Text input Supports template variables. Required.
Body Rich text editor Template variables, links, images (basic formatting). Required.
From Display only "QuranFlow noreply@quranflow.com" — not editable (no identity switching per ADR-004). Shows "Pre-drafted for [TA name]" tag if admin is using Draft for TA action.
Reply-to Display only Admin's email, or TA's email if pre-drafted for TA
Save as Template Checkbox If checked, on send: also creates an email_templates record with the composed subject/body. Requires template name input.

3.5.3 Review & Send Section (sticky footer)

Control Behavior
Preview Opens preview modal showing the rendered email with the first recipient's substituted values + pagination to preview with other recipients' values
Test Send Sends a test to the admin's own email using the first recipient's values
Save Draft Saves the current state as blast_emails with status = Draft. Toast: "Draft saved."
Send Now Destructive confirmation: "Send '[campaign name]' to [N] recipients now? This cannot be undone." On confirm: immediately queues for send. Logs to Communication Logs (Section 7).
Draft for TA Opens TA selector dropdown. On confirm: saves as blast_emails with predraft_for_ta_id set, status = Draft. Toast: "Draft saved for [TA name]. They will see it in their outbox." (TA-side queue is production-only per ADR-004.)

Scheduled sends deferred to production per STAKEHOLDER-ANSWERS 2026-04-21 (default #5). v2 mockup supports Send Now and Save Draft only; scheduled publishing will be added in production. The blast_emails.scheduled_for column is preserved in the data model for production use; only the UI Schedule button is removed from the mockup.

3.5.4 Compose View Actions (full table)

Action Trigger Permission Behavior Confirmation
Preview "Preview" button in sticky footer Admin Modal with rendered email, recipient pagination, and "Send" shortcut No
Test Send "Test Send" button Admin Sends to admin's own email. Toast: "Test email sent." No
Save Draft "Save Draft" button Admin Creates/updates blast_emails with status = Draft. Toast. No
Send Now "Send Now" button (primary) Admin Destructive confirmation with recipient count summary. Logs to Communication Logs. Destructive
Draft for TA "Draft for TA" secondary button Admin TA dropdown → save as pre-draft. TA takes over final send. Yes
Cancel "Cancel" link (top of form) Admin If dirty: "Discard changes? Your draft will not be saved." Otherwise returns to Campaigns view. If dirty

3.6 Role Visibility


4. Screen: Push Notifications

4.1 Purpose

Send push notifications to the mobile app. Absorbed from v1 Admin & System > Notifications and enhanced with the shared recipient filter (Section 1.5), delivery tracking (sent/delivered/failed counts), and a history view. Push notifications are reserved for urgent/time-sensitive communications (urgent session changes, emergency program updates).

Transition hint: "Formerly under Admin & System > Notifications" — shown for first 30 days.

4.2 Entry Points

4.3 Layout

Two-pane: Compose (top, sticky form) | History (below, data table of past notifications).

4.4 Compose Pane

4.4.1 Fields

Field Type Notes
Message Text area Plain text only (no rich formatting — push notifications are short). Character counter 0/200. Required.
Recipients Shared Recipient Filter (§1.5) Filter-by-criteria or manual selection. Live preview. Required.
Title (optional) Text input Max 50 chars. If omitted: defaults to "QuranFlow" in the notification payload.
Deep Link (optional) Dropdown + dynamic field "None" / "Open Student Detail" / "Open Lesson" / "Open Live Session" / "Custom URL". Determines what the app opens when the user taps the notification.

4.4.2 Actions

Action Trigger Permission Behavior Confirmation
Preview "Preview" button Admin Shows a mobile-notification-card preview with the composed title + message rendered No
Send Now "Send Now" button (primary) Admin Destructive confirmation: "Send push notification to [N] recipients now? This cannot be undone." On confirm: queues via push provider (APNs/FCM), creates push_notifications record, logs to Communication Logs. Destructive
Clear Form "Clear" link Admin Confirms if dirty If dirty

Scheduled sends deferred to production per STAKEHOLDER-ANSWERS 2026-04-21 (default #5). v2 mockup supports Send Now only; scheduled publishing will be added in production. The push_notifications.scheduled_for column is preserved in the data model for production use; only the UI Schedule button is removed from the mockup.

4.5 History Pane

4.5.1 Filter Bar

Filter Type Options
Search Text input Filters by message content
Status Dropdown All / Scheduled / Sent / Failed
Sender Dropdown All / Me / [list of admins]
Date Range Date range picker Sent date range

Note on "Scheduled" records: Scheduling is production-only per STAKEHOLDER-ANSWERS-2026-04-21 (default #5). The Schedule button is removed from the Compose view (§4.4.2), so the mockup cannot create Scheduled push notifications. The Status filter and Cancel Scheduled action are retained for forward-compatibility with production.

4.5.2 Data Displayed

Column Source Sortable Notes
Sent At push_notifications.sent_at Yes (default: descending) "Mar 8, 2026 2:14 PM"
Message push_notifications.message No Truncated to 80 chars, tooltip for full
Sender users.name via push_notifications.sent_by Yes Admin name
Recipients push_notifications.recipient_count Yes "247 recipients"
Delivered push_notifications.delivered_count / recipient_count Yes "245/247 (99%)"
Failed push_notifications.failed_count Yes Red text if >0
Status Derived from delivered/failed counts Yes Badge: Sent (green) / Partial (amber, if failed > 0) / Failed (red, if delivered = 0)
Actions No View / Duplicate (icons)

4.5.3 History Actions

Action Trigger Permission Behavior Confirmation
View Row click or View icon All Opens detail modal: full message, recipient breakdown, delivery status per recipient segment (Admin only sees failures with reasons) No
Duplicate Duplicate icon Admin Pre-fills compose pane with this notification's message + recipient filter No
Cancel Scheduled "Cancel" icon (Scheduled only) Admin Confirmation: "Cancel scheduled notification to [N] recipients?" On confirm: sets status = Cancelled. Yes

4.6 States

State Display
Compose — filter producing 0 recipients Warning below recipient filter: "No students match these filters. Adjust filters or switch to manual selection." Send Now disabled.
Compose — ready Live recipient count + sample names above Send button
History — has notifications Data table
History — empty "No push notifications sent yet."
Loading Skeleton form (compose) + skeleton table (history)
Error — provider failure Compose retains input; banner: "Push provider unreachable. Your notification was not sent. [Retry]"

4.7 Role Visibility


5. Screen: Announcement Board (NEW)

5.1 Purpose

Post in-app announcements to students and/or teachers. Replaces the community board concept with a one-way, authored channel. Used for non-urgent program updates, surveys, fix notes, policy changes — things that don't warrant a push notification but should be visible to users when they open the app.

Admins and TAs can post to the Announcement Board (per STAKEHOLDER-ANSWERS 2026-04-21, default #6 CHANGED). TAs can manage their own posts (edit/delete/set audience/set expiry). Moderation of others' posts is admin-only.

Students see the announcement in a dedicated in-app announcement area. Teachers (TAs) see posts targeted to them similarly.

5.2 Entry Points

5.3 Layout

Two-pane: Active Announcements (top, card list of currently visible posts) | All Posts (below, full history table with filter bar).

5.4 Active Announcements Pane

A card list of announcements where status = Published AND expires_at is in the future (or null).

Each card shows:

5.5 All Posts Pane

5.5.1 Filter Bar

Filter Type Options
Search Text input Filters by title or body
Status Dropdown All / Draft / Published / Expired / Deleted
Audience Dropdown All / Students / Teachers / Both
Posted By Dropdown All / Me / [list of admins]
Date Range Date range picker Posted date range

5.5.2 Data Displayed

Column Source Sortable Notes
Title announcements.title Yes Clickable → opens edit/view modal
Audience announcements.audience_filter_json summary No "All students", "Level 1 + 2 students", "All teachers", etc.
Posted By users.name via announcements.posted_by Yes Author name — author_user_id/posted_by can reference an admin or a TA per STAKEHOLDER-ANSWERS 2026-04-21 (no schema change).
Posted At announcements.posted_at Yes (default: descending) "Mar 8, 2026"
Expires At announcements.expires_at Yes "Mar 15, 2026" or "No expiry"
Read Receipts Count from announcement_reads / recipient count if read_receipt_enabled No "134/247 (54%)" or "—" if disabled
Status announcements.status Yes Badge: Draft (blue) / Published (green) / Expired (gray) / Deleted (gray)
Actions No Edit / Delete / Expire Now / View Read Receipts

5.6 Post Announcement Compose Modal

Field Type Notes
Title Text input Max 80 chars. Required.
Body Rich text editor Links + basic formatting. Required. Template variables NOT supported (announcements are broadcast, not per-student).
Audience Shared Recipient Filter (§1.5) Filter-by-criteria only (no manual selection for announcements — announcements are broadcast by definition).
Expires At Date/time picker Optional. If null: announcement remains visible until manually expired/deleted.
Read Receipts Toggle Default: off. When on, tracks per-user read via announcement_reads table. Open question (OQ-C5).
Status Toggle Draft / Published (default on Publish button press)

5.7 Actions

Action Trigger Permission Behavior Confirmation
Post Announcement "Post Announcement" button (top-right) Admin or TA Opens compose modal. On Publish: creates announcements record with status = Published, posted_at = now, posted_by = current user (admin or TA). Logs to Communication Logs. Toast: "Announcement posted to [N] users." No (but summary shown in modal footer)
Save Draft "Save Draft" button in compose modal Admin or TA Status = Draft. Not visible to users. Toast: "Draft saved." No
Edit Edit icon Admin (any post); TA (own posts only) Opens compose modal pre-filled. Warning if Published: "Editing a published announcement will update it in real time for all [N] users currently viewing." Yes if Published
Delete Delete icon Admin (any post); TA (own posts only) Destructive confirmation: "Delete '[title]'? Users will no longer see this announcement. Read receipts will be preserved." On confirm: sets status = Deleted. Destructive
Expire Now "Expire Now" action Admin (any post); TA (own posts only) Confirmation: "Expire '[title]' now? It will no longer be shown to users, but remains in history." On confirm: sets expires_at = now. Yes
View Read Receipts "View Read Receipts" action (if enabled) Admin Opens modal with recipient list, read/unread status, read timestamp No
Post to Both Audiences Audience selector in compose Admin If audience = "Both", creates a single announcement record with broad audience filter; no duplicate post. No

5.8 States

State Display
Has active announcements Active pane shows cards; All Posts shows table
No active announcements Active pane: "No active announcements." + "Post Announcement" button. All Posts table may still have history.
Empty (no posts ever) "No announcements posted yet." + "Post Announcement" button
Loading Skeleton cards (active) + skeleton table (history)
Error "Unable to load announcements." + "Retry"
Read receipts disabled for a post Read Receipts column shows "—"

5.9 Role Visibility


6. Screen: Private Messages (NEW)

6.1 Purpose

Bidirectional conversational messaging between admins, teachers (TAs), and students. Replaces ad-hoc WhatsApp/email for student support and teacher-student check-ins. This is the core screen for the pre-draft pattern (ADR-004): an admin can compose a message, assign it as a draft to a TA, and the TA sends it from their own account.

Key design points (per ADR-003, ADR-004):

6.2 Entry Points

6.3 Layout

Three-pane inbox layout:

6.4 Conversation List (left pane)

6.4.1 Filter Bar

Filter Type Options
Search Text input Filters by participant name or message content
View Dropdown All conversations / My conversations / Pre-drafts I created / Unread
Student Dropdown (autocomplete) Filters to threads involving a specific student
Teacher Dropdown Filters to threads involving a specific TA
Status Dropdown All / Open / Archived / Closed

6.4.2 Thread Card Fields

Field Source Notes
Participants users.name for student + teacher/admin "Sarah Ahmed ↔ Ustadha Amina"
Subject private_message_threads.subject Bold if unread
Last Message Preview First 60 chars of most recent message Truncated
Last Message At private_message_threads.last_message_at "2h ago" or "Mar 8"
Unread Badge Count of messages where read_at IS NULL for viewer Blue dot or count badge
Pre-draft Indicator If any message in thread has predraft_for_ta_id Small "Pre-drafted" tag
Status private_message_threads.status Badge if Archived/Closed

6.5 Thread View (middle pane)

6.5.1 Header

Element Content
Thread subject Editable by admin (inline)
Participants "Sarah Ahmed (Student) · Ustadha Amina (TA)"
Actions Archive / Close / Reopen / Delete (admin only) / Add Participant (admin only, OQ-C7)

6.5.2 Message List

Each message rendered as a bubble aligned by sender (viewer's messages right, others left).

Field Source Notes
Sender Name users.name via private_messages.sender_user_id Shown above bubble
Sender Role Derived from user_type "(TA)", "(Admin)", "(Student)" suffix
Body private_messages.body Rich text, links, line breaks
Attachments private_messages.attachments_json Inline thumbnails for images; download links for other files. Open question (OQ-C8).
Sent At private_messages.sent_at "2:14 PM" or "Mar 8, 2:14 PM"
Read Status private_messages.read_at on recipient side "Read 2:16 PM" / "Delivered" / "Sent"
Pre-draft Tag If predraft_for_ta_id was populated before the TA sent Small tag: "Pre-drafted by [admin name]" visible to admin only

6.5.3 Reply Composer (sticky bottom)

Field Type Notes
Message body Rich text area Basic formatting, links, attachments
Attach Button Open question (OQ-C8): what file types, what max size. Mockup scope: UI affordance only.
Send Primary button Sends as the viewing admin/TA. No identity switching.
Draft for TA Secondary button (admin only) Opens TA selector. Saves as draft targeted to selected TA. Toast: "Draft saved for [TA]. They'll see it in their outbox." (TA outbox production-only.)

6.6 Admin Context Panel (right pane, admin view only)

When an admin is viewing a thread, a right-side panel shows context about the student participant:

Section Content
Student Summary Name, level, semester, TA assignment, status badge
Recent Submissions Last 3 submissions with status (links to Student Detail > Submissions)
Recent Payments Last 3 payment events with status (links to Student Detail > Payments)
Related Issues Open issues from Issue Queue involving this student (link)

This panel is view-only and does not appear for the TA view (TAs already have student context in their own UI).

6.7 Compose New Thread

Triggered from "New Message" button in conversation list, or from cross-domain entry points (Student Detail, Teacher Detail).

Field Type Notes
Recipient (Student) Autocomplete Required. One student per thread.
Recipient (Teacher/Admin) Autocomplete Required if admin is creating on behalf (pre-draft flow). Prefilled if launched from Teacher Detail.
Subject Text input Required.
Body Rich text Required.
Send As Display only The logged-in admin's identity, or "Draft for [TA]" if pre-drafting. No impersonation.

Actions: Send (immediate, creates thread + first message) / Save Draft (draft thread, not visible to recipient) / Draft for TA (saves as pre-draft; TA sends first message from their own account).

6.8 Actions (thread-level)

Action Trigger Permission Behavior Confirmation
New Message "New Message" button (conversation list header) Admin Opens compose new thread form No
Send Reply Send button in composer Thread participant or admin Appends message, updates last_message_at, marks unread for other participants, logs to Communication Logs No
Draft for TA "Draft for TA" button in composer Admin TA selector → saves as pre-draft. Thread not yet visible to student until TA sends. Toast: "Draft saved for [TA]." Yes
Archive Thread "Archive" action Thread participant Confirmation: "Archive this conversation? It will be hidden from your active list but preserved." Yes
Close Thread "Close" action Admin Confirmation: "Close this conversation? No further messages can be sent until reopened." On confirm: sets status = Closed. Yes
Reopen Thread "Reopen" action (Closed only) Admin Sets status = Open. No
Delete Message Delete icon on a message bubble Admin only (not the author) Destructive confirmation: "Delete this message? It will be removed for all participants. Audit trail preserved in Communication Logs." Destructive
Delete Thread "Delete Thread" action Admin Destructive confirmation with typed "DELETE" confirmation: "Delete this thread and all [N] messages? This cannot be undone." Destructive (typed)
Export Thread "Export" action Admin Downloads thread as PDF or markdown for records/compliance No

6.9 States

State Display
No threads "No conversations yet." + "New Message" button (admin) / "Your inbox is empty." (TA)
Has threads — none selected Conversation list populated; middle pane: "Select a conversation to view."
Thread selected Full three-pane view
Thread closed Middle pane shows messages with banner at bottom: "This conversation is closed. [Reopen]" (admin) / no composer (TA/student)
Thread archived Does not appear in default "All" view; accessible via Archived filter
Loading thread Skeleton message bubbles
Error sending Composer shows inline error: "Message failed to send. [Retry]"
Unread messages Thread card shows unread badge in conversation list; new messages in thread view marked with a subtle left accent until scrolled

6.10 Role Visibility


7. Screen: Communication Logs (NEW)

7.1 Purpose

Unified audit trail of every message sent from the backend, across all five outbound channels (automation email, blast email, push notification, announcement, private message). Supports filtering, full-message viewing, delivery-status investigation, and CSV export.

Distinct from Reporting > Logs (09-reporting.md §6), which covers system events (logins, record changes, admin actions). Communication Logs is communication-specific.

7.2 Entry Points

7.3 Layout

Standard filter bar + data table + pagination, following 01-global-patterns.md §4.1 and §4.2.

7.4 Filter Bar

Filter Type Options
Search Text input Searches subject/preview and recipient names/emails
Channel Dropdown (multi-select) All / Automation Email / Blast Email / Push Notification / Announcement / Private Message
Sender Dropdown (autocomplete) Filters by sender_user_id — any admin or TA
Recipient Dropdown (autocomplete) Filters by any recipient_user_ids_json containing the selected user
Status Dropdown All / Queued / Sent / Delivered / Failed / Read
Pre-drafted Toggle Show only messages that were pre-drafted for a TA
Date Range Date range picker Sent-at range

7.5 Data Displayed

Column Source Sortable Filterable Notes
Timestamp communication_logs.sent_at or created_at if unsent Yes (default: descending) Yes (date range) "Mar 8, 2026 2:14 PM"
Channel communication_logs.channel Yes Yes Badge: Automation Email / Blast Email / Push Notification / Announcement / Private Message
Sender users.name via sender_user_id Yes Yes (dropdown) The actual sender — per ADR-004, single identity. If predrafted = true, shows small "(pre-drafted)" tag.
Recipient(s) users.name via recipient_user_ids_json No Yes (dropdown) For 1 recipient: name. For many: "[first name] + [N-1] more" with click to expand full list.
Subject/Preview communication_logs.subject_or_preview Yes Yes (search) For emails: subject. For push: first 80 chars of message. For announcements: title. For private messages: first 80 chars of body. Truncated with tooltip.
Status communication_logs.status Yes Yes Badge: Queued (gray) / Sent (green) / Delivered (green) / Failed (red) / Read (green)
Pre-drafted communication_logs.predrafted + predraft_ta_user_id Yes Yes (toggle) Yes badge with TA name, or "—"
Actions No No View / Retry (failed only, admin) / Open Source (jumps to origin screen)

7.6 Actions

Action Trigger Permission Behavior Confirmation
View Full Message Row click or View icon All roles with access Opens detail modal: full sender/recipient list, rendered message body (as it was sent), delivery timeline (queued → sent → delivered → read if applicable), failure reason if Failed No
Retry "Retry" icon (Failed only) Admin Confirmation: "Retry sending this [channel] message to [N] recipients?" On confirm: re-queues via the original channel. Creates a new log entry; marks original as Retried. Yes
Open Source "Open Source" link in detail modal All roles with access Navigates to the originating screen: Automation Emails > Template detail, Blast Emails > Campaign detail, Push Notifications > History detail, Announcement Board > Post detail, or Private Messages > Thread No
Export CSV "Export" button (top-right) Admin Downloads CSV of current filtered/sorted view. Columns: timestamp, channel, sender, recipients (comma-separated), subject/preview, status, pre-drafted flag, failure reason. Includes up to 10,000 rows; warns if more. No

7.7 Pagination

Standard pagination (01-global-patterns.md §4.1): 50 records per page (higher than default 25 because logs are expected to be high-volume), "1–50 of 3,472" format.

7.8 States

State Display
Has logs Data table
Empty (unfiltered) "No communication has been sent yet." (should not occur in production)
Filtered — no results "No communication matches your filters." + "Clear filters" link
Loading Skeleton data table
Error "Unable to load communication logs. Please try again." + "Retry" button
Export in progress Toast: "Preparing export... this may take a moment."
Export ready Toast: "Export ready. [Download]" (if async) or browser download (if sync)

7.9 Role Visibility


8. Cross-Domain Integration Points

This section documents how Communication connects to other domains. Each integration is specified in detail in the target domain's spec document; this section provides a summary for reference.

8.1 Semester Management (04-semester-management.md)

Link Direction Behavior
Semester Hub > Setup Checklist > "Configure Email Templates" Out → Communication Deep link to Automation Emails with ?semester=[id] filter applied. Preserves the v1 workflow after the Email Management absorption per ADR-003.
Semester Hub > Overview > "View All Emails" Out → Communication Link to Automation Emails filtered to this semester
Semester Hub > End Checklist items (per ADR-001) Out → Communication Automated end-of-semester announcements may be configured as End Checklist items, deep-linking into Announcement Board
Semester Management > Tags In ← Tags Tag values populate the Shared Recipient Filter (§1.5) Tags dimension on Blast Emails, Push Notifications, Announcement Board

8.2 Student Management (03-student-management.md)

Link Direction Behavior
Student Detail > Profile tab > "Message" action Out → Communication Opens Private Messages with a new thread pre-populated with this student as recipient
Students list > bulk "Email Selected" action Out → Communication Opens Blast Emails > Compose with the selected students pre-populated as manual recipients
Student Detail > [Communication History] (future) In ← Communication Logs Shows a student-scoped slice of Communication Logs for support context

8.3 Teacher Management (07-teacher-management.md)

Link Direction Behavior
Teacher Detail > Profile tab > "Pre-draft Message for [TA]" action Out → Communication Opens Private Messages > Compose with this TA locked as the pre-draft sender; admin fills in student recipient and body
TA Schedule > session details > "Notify Student" Out → Communication Push notification pre-filled with session context

8.4 Billing & Payments (08-billing-payments.md)

Link Direction Behavior
Payment Overview > "Send Reminder" action on failed payments Out → Communication Opens Blast Emails > Compose (or pre-draft for TA) with a failed-payment-reminder template and the affected student(s) pre-selected
Scholarships & Deferments > Expiring Scholarships > "Contact" action Out → Communication Opens Private Messages thread with the scholarship student

8.5 Admin & System (10-admin-system.md)

Link Direction Behavior
Issue Queue > Issue Detail > "Start Message" Out → Communication Opens Private Messages thread with the issue reporter as recipient. Boundary: Issue Queue remains in Admin & System per ADR-003; messaging is a follow-up channel, not a replacement for the ticketing flow.
Admin & System > Notifications Removed per ADR-003. Dashboard "Send Notification" quick action now targets Communication > Push Notifications.
Settings > Notifications Removed per ADR-003.

8.6 Dashboard (02-dashboard.md)

Dashboard Element Target
"Send Notification" quick action Communication > Push Notifications (retargeted per ADR-003)
"Post Announcement" quick action (NEW) Communication > Announcement Board
"Send Blast Email" quick action (NEW) Communication > Blast Emails > Compose
Unread private messages tile (NEW — optional) Communication > Private Messages, filtered to Unread

8.7 Reporting (09-reporting.md)

Link Direction Behavior
Reporting > Logs Separate System-level audit logs — does NOT duplicate Communication Logs. The two coexist: communication events are captured in Communication Logs; non-communication events (logins, record changes, admin actions) remain in Reporting > Logs.

9. Assumptions and Open Questions

This domain is net-new and introduces several decisions that require stakeholder validation. Summary of communication-specific open questions, consolidated from ADR-003, ADR-004, and Framework v2 §3.6:

ID Question / Assumption Impact on This Spec Resolution Needed
OQ-C1 Sequence View (§2.5): data source — only searched student, or sample student when none searched? Mockup defaults to searched student. If sample needed, add a "Sample student" toggle above the search box. Confirm with stakeholder: is "see what a typical student receives" a common need?
OQ-C2 Template library: unified across Automation + Blast, or separate? Resolved 2026-04-21 per STAKEHOLDER-ANSWERS (default #4) — Unified template library confirmed. Templates tagged by source_domain are reusable across Automation + Blast contexts. Resolved.
OQ-C3 Scheduling: send-now only, or future scheduling for Blast Emails / Push Notifications / Announcements? Resolved 2026-04-21 per STAKEHOLDER-ANSWERS (default #5) — Mockup supports send-now + save-draft only. Scheduling is deferred to production. Announcement Board continues to use expires_at for post expiry (distinct from scheduled publishing). Resolved.
OQ-C4 Saved audiences: shared across admins or private per admin? Mockup assumes shared (all admins see the same named audiences). Confirm: are audiences a shared org resource or personal shortcuts?
OQ-C5 Announcement read receipts: enabled by default, opt-in per post, or not supported at all? Mockup treats as opt-in per post (read_receipt_enabled flag). Confirm: is this privacy-concerning or desirable metric?
OQ-C6 Announcement Board: can TAs post, or admin-only? Resolved 2026-04-21 per STAKEHOLDER-ANSWERS (default #6, CHANGED) — Admins AND TAs can post to Announcement Board. TAs manage their own posts (edit, delete, set audience, set expiry). Moderation of others' posts is admin-only. Resolved.
OQ-C7 Private Messages: multi-party threads (group conversations), or strictly 1:1? Mockup assumes 1:1 (one student + one teacher/admin). "Add Participant" action placeholder included but may be removed. Confirm: is group messaging a requirement?
OQ-C8 Private Messages: attachment support scope — file types, size limits, storage? Mockup shows UI affordance only. Production scope: images, PDFs, docs. Size limit TBD. Define file-type whitelist, size limit, storage strategy (S3? local?).
OQ-C9 Private Messages: who can students initiate new threads with? Assumption: only their assigned TA and admins (support); not arbitrary TAs. Routing rules TBD. Confirm routing and permission rules from student side.
OQ-C10 Communication Logs: TA sidebar visibility — should TAs see a scoped Logs view of their own sends? Mockup hides from TA sidebar entirely (TAs see sent items in their own production-only outbox). Confirm: do TAs need a self-audit view?
OQ-C11 Pre-draft expiry (ADR-004 OQ3): do unactioned pre-drafts expire, or persist indefinitely? Resolved 2026-04-21 per STAKEHOLDER-ANSWERS (default #10) — Pre-drafts persist indefinitely. No expiry in v2. Resolved.
OQ-C12 Pre-draft multi-TA (ADR-004 OQ2): can an admin pre-draft one message for multiple TAs at once (each TA gets a personalized copy)? Resolved 2026-04-21 per STAKEHOLDER-ANSWERS (default #9) — Single TA per draft. Multi-TA batched pre-drafting is not in v2 scope. Resolved.
OQ-C13 Pre-draft channels (ADR-004 OQ1): which channels support pre-drafting? Resolved 2026-04-21 per STAKEHOLDER-ANSWERS (default #8) — Private Messages and Blast Emails support pre-drafting; Push Notifications and Announcement Board do not. Resolved.
OQ-C14 Automation Emails: do automations reference dynamic fields (e.g., TA name at send time) or frozen at template creation? Mockup: dynamic per-send substitution. Confirm: is this an explicit requirement?
OQ-C15 Email sending infrastructure: existing transactional email provider (Postmark/SendGrid/SES)? Assumed: existing infrastructure — mockup does not simulate actual send. Confirm infrastructure; impacts Communication Logs delivery-status granularity.
OQ-C16 Announcement expiry vs. delete: do expired announcements remain visible in the app (e.g., archive view) or disappear entirely? Mockup: disappear from active view, remain in admin history. Confirm user-side behavior.

Preserved assumptions from absorbed domains: