# RP Learning Portal — User Journeys & Workflows

**Version:** 4.0 — Post Phase 9  
**Date:** 2026-06-12  
**Status:** Updated with all approved business decisions

---

## 1. PARENT SELF-REGISTRATION WORKFLOW

**Screens:** REG-01 → REG-02 → REG-03 → REG-04  
**Route:** /register → /register/parent → /register/add-ward → /register/credentials  
**Actor:** Public (unauthenticated) → Parent

```
[REG-01: Registration Landing Page]
├── Hero: "Join Your Child's Learning Journey"
├── CTA: [Register as Parent] → REG-02
├── Info cards: What parents can do (monitor, pay, communicate)
└── Footer: [Already have an account? Login]

        ↓ Click "Register as Parent"

[REG-02: Parent Registration Form]
├── Fields:
│   ├── Full Name (text, required)
│   ├── Email Address (email, required, unique)
│   ├── Phone Number (tel, required)
│   ├── Password (password, min 8 chars, strength meter)
│   └── Confirm Password (password, must match)
├── Consent Checkboxes (all required):
│   ├── ☐ I accept the Terms of Service
│   ├── ☐ I accept the Privacy Policy
│   ├── ☐ I accept the Payment Responsibility Agreement
│   └── ☐ I consent to Data Processing
├── On Submit:
│   ├── policy_acceptances records created (4 records)
│   ├── IP address + user agent logged cryptographically
│   ├── User created: role=parent, status=active
│   └── Redirect → REG-03

        ↓ Redirect

[REG-03: Add Ward Form]
├── Fields:
│   ├── Child's Full Name (text, required)
│   ├── Date of Birth (date, required)
│   ├── Gender (select: male/female/other)
│   └── Class to Enroll (select from active school_classes)
├── On Submit:
│   ├── CredentialGeneratorService runs:
│   │   ├── Generates student ID: RP-2026-00001
│   │   ├── Generates temporary password
│   │   ├── Creates user: role=student
│   │   ├── Links parent → student via parent_student pivot
│   │   ├── Sets is_primary_guardian = TRUE
│   │   └── Logs to credential_delivery_logs
│   └── Redirect → REG-04

        ↓ Redirect

[REG-04: Credential Display]
├── Display:
│   ├── Student Name
│   ├── Student ID: RP-2026-00001 (large, monospace, copyable)
│   ├── Temporary Password: •••••••• (eye toggle to reveal)
│   └── Class enrolled
├── Actions:
│   ├── [Copy Credentials] — copies both to clipboard
│   ├── [Download PDF] — generates credential PDF (DomPDF)
│   ├── [Email to Student] — sends credentials to entered email
│   ├── [+ Add Another Ward] → REG-03
│   └── [Go to Dashboard] → PAR-01
├── Warning Banner:
│   └── "Please save these credentials. The temporary password will expire on first login."
└── Note: Parent can add unlimited wards (repeat REG-03)
```

---

## 2. TEACHER INVITATION WORKFLOW

**Screens:** INV-01 → INV-02  
**Route:** /invite/{token} → /invite/{token}/register  
**Actor:** Admin (sender) → Teacher (recipient)

```
[Admin: ADM-07 Teachers List]
├── Admin clicks [Invite Teacher]
├── Modal: Enter teacher's email address
└── POST /admin/teachers/invite
    ├── TeacherInvitationService:
    │   ├── Creates teacher_invitations record
    │   ├── Generates hashed token (72-hour expiry)
    │   └── Sends invitation email
    └── Success toast: "Invitation sent to {email}"

        ↓ Teacher receives email

[INV-01: Teacher Invitation Landing]
├── Display:
│   ├── "You've been invited to join RP Learning Portal"
│   ├── Inviting school name
│   ├── Invitation expiry notice (72 hours)
│   └── CTA: [Accept Invitation & Complete Profile]
├── If token expired: Error page with [Request New Invitation]
└── If token invalid: 404 page

        ↓ Click "Accept Invitation"

[INV-02: Teacher Profile Completion]
├── Fields:
│   ├── Full Name (pre-filled from invitation, locked)
│   ├── Email (pre-filled, locked)
│   ├── Password (password, min 8)
│   ├── Confirm Password
│   ├── Date of Birth (date)
│   ├── Phone Number (tel)
│   ├── Qualifications (textarea)
│   ├── Bio (textarea, max 500 chars)
│   └── Upload CV (file: PDF/DOC/DOCX, max 5MB)
├── On Submit:
│   ├── User created: role=teacher, status=pending
│   ├── CV uploaded via Spatie Media Library
│   ├── teacher_invitations record marked as used
│   ├── Admin notification sent
│   └── Redirect: "Your account is pending approval"
└── Admin approves → status → active → teacher can login
```

---

## 3. LOGIN & AUTHENTICATION WORKFLOW

**Screens:** AUTH-01 → AUTH-04  
**Route:** /login, /forgot-password, /reset-password/{token}, /verify-email  
**Actor:** All roles

```
[AUTH-01: Login]
├── Fields:
│   ├── Email (email, required)
│   └── Password (password, required)
├── Actions:
│   ├── [Login] → authenticate → redirect to role portal
│   ├── [Forgot Password?] → AUTH-02
│   └── [Register as Parent] → REG-01
├── Role-based redirect:
│   ├── super-admin → /admin/dashboard
│   ├── admin → /admin/dashboard
│   ├── teacher → /teacher/dashboard
│   ├── student → /student/dashboard
│   └── parent → /parent/dashboard
└── Error: "Invalid email or password"

[AUTH-02: Forgot Password]
├── Field: Email (email, required)
├── Action: [Send Reset Link]
├── Success: "Check your email for the reset link"
└── Fallback: "Didn't receive it? [Resend]"

[AUTH-03: Reset Password]
├── Fields:
│   ├── Password (min 8, strength meter)
│   └── Confirm Password
├── Action: [Reset Password]
└── Success: Redirect → AUTH-01 with success toast

[AUTH-04: Email Verification]
├── Display: "Please verify your email address"
├── Action: [Resend Verification Email]
└── Note: Auto-dismissed after verification
```

---

## 4. LIVE CLASSROOM WORKFLOW (Zoom Video SDK)

**Screens:** TCH-04 → TCH-05 / STU-04 → STU-05  
**Actor:** Teacher (host) + Students (participants)

```
[Teacher: TCH-04 Session Detail]
├── Display: Session info (subject, date, time, class, students enrolled)
├── Status: Scheduled → Ready → In Progress → Completed
├── Teacher clicks [Start Session]
│   ├── class_sessions.status → in_progress
│   ├── class_sessions.started_at → now()
│   └── Redirect → TCH-05

        ↓

[TCH-05: Live Classroom (Teacher View)]
├── ZoomVideoSDKService generates JWT token
├── Browser connects to Zoom Video SDK cloud
├── Layout:
│   ├── Main area: Video feeds (speaker view / gallery toggle)
│   ├── Sidebar: Participant list with join/leave timestamps
│   ├── Top bar: Session timer, subject, class
│   ├── Controls bar:
│   │   ├── [Mute/Unmute] [Start/Stop Video]
│   │   ├── [Share Screen]
│   │   ├── [Start Recording] / [Stop Recording]
│   │   ├── [Chat] (in-class chat panel)
│   │   ├── [Participants] (count badge)
│   │   └── [End Session]
│   └── Teacher can see attendance log in sidebar
├── On [End Session]:
│   ├── POST /classroom/{session}/end
│   ├── class_sessions.status → completed
│   ├── class_sessions.ended_at → now()
│   └── Zoom webhook confirms end

        ↓ Students see notification

[Student: STU-04 Session Detail]
├── Display: Session info + [Join Session] button
├── Status indicator: "Starting soon" / "In Progress" / "Completed"
├── Student clicks [Join Session]
│   ├── POST /classroom/{session}/join
│   ├── class_session_joins record created with joined_at
│   └── Redirect → STU-05

[STU-05: Live Classroom (Student View)]
├── Same Zoom Video SDK embedded experience
├── Layout:
│   ├── Main area: Video feeds
│   ├── Controls: [Mute] [Video] [Chat] [Leave]
│   ├── Top bar: Session timer, subject
│   └── No recording controls (teacher only)
├── AutoAttendanceService fires on join:
│   IF joined_at <= (started_at + threshold_minutes):
│     → attendance.status = 'present'
│   ELSE:
│     → attendance.status = 'late'
└── On [Leave] or browser close:
    ├── class_session_joins.left_at logged
    └── Zoom webhook confirms for accuracy
```

---

## 5. ASSESSMENT WORKFLOW (9 Question Types + Attempt Rules)

**Screens:** TCH-12 → TCH-16 → STU-09 → TCH-15 → STU-10  
**Actor:** Teacher (creator/grading) → Student (test-taker)

### 5A. Exam Creation (Teacher)

```
[TCH-12: Create Exam]
├── Section 1: Basic Info
│   ├── Title (text, required)
│   ├── Description (textarea)
│   ├── Instructions (textarea, shown to students before exam)
│   ├── Subject (select, required)
│   ├── Class (select, required)
│   └── Scheduled At (datetime picker)
│
├── Section 2: Scoring
│   ├── Max Score (number, required)
│   ├── Passing Score (number, required)
│   └── Duration in Minutes (number)
│
├── Section 3: Attempt Rules
│   ├── Attempt Limit Type (radio, default: Single):
│   │   ├── ○ Single Attempt — student gets exactly one try
│   │   ├── ○ Unlimited Attempts — student can retake infinitely
│   │   ├── ○ Fixed Number — show [Max Attempts] number input
│   │   └── ○ Teacher Override — teacher can reset per student
│   └── Allow Teacher Override (toggle, default: off)
│       — visible for all types, lets teacher reset individual students
│
├── Section 4: Grading
│   ├── Grading Type (radio, default: Percentage):
│   │   ├── ○ Percentage — 0-100%
│   │   ├── ○ Letter Grade — A+/A/B+/B/C+/C/D+/D/F
│   │   ├── ○ Numeric Score — raw number out of max
│   │   └── ○ Custom Scale — opens scale builder
│   └── Custom Scale Builder (if Custom Scale):
│       ├── Table: Label | Min % | Max % | Color picker
│       ├── [+ Add Tier] button
│       ├── Drag to reorder
│       └── Live preview of grade bands
│
├── Section 5: Feedback Configuration
│   ├── Show Correct Answers (toggle, default: off)
│   ├── Show Feedback After (select, default: After Graded):
│   │   ├── ○ Immediately after submission
│   │   ├── ○ After due date passes
│   │   ├── ○ After teacher grades (default)
│   │   └── ○ Never
│   └── Feedback Visible To (select, default: Both):
│       ├── ○ Student only
│       ├── ○ Parent only
│       └── ○ Both student and parent
│
├── Section 6: Questions
│   └── [Add Question] → TCH-16 Question Builder
│
└── Actions:
    ├── [Save as Draft]
    ├── [Publish] → students notified
    └── [Cancel]
```

### 5B. Question Builder (All 9 Types)

```
[TCH-16: Question Builder]
├── Type Selector (tabs):
│   [MC] [Multi] [T/F] [Short] [Essay] [Match] [Fill] [Upload] [Num]
│
├── FOR ALL TYPES:
│   ├── Question Text (rich textarea, required)
│   └── Points (number, required)
│
├── [Multiple Choice]
│   ├── Options (add/remove rows, min 2, max 6):
│   │   ├── ○ Option text (text input)
│   │   ├── [Mark Correct] radio (one only)
│   │   └── [Delete] button
│   ├── [+ Add Option]
│   └── Explanation (textarea, optional — shown after grading)
│
├── [Multi Select]
│   ├── Options (add/remove rows, min 2, max 6):
│   │   ├── ☐ Option text (text input)
│   │   └── [Delete] button
│   ├── [+ Add Option]
│   ├── Min correct selections (number)
│   ├── Partial credit (toggle)
│   └── Explanation (textarea, optional)
│
├── [True/False]
│   ├── Options: auto-created (True / False)
│   ├── Correct Answer (radio): ○ True ○ False
│   └── Explanation (textarea, optional)
│
├── [Short Answer]
│   ├── Correct Answer (text input, required)
│   ├── Case Sensitive (toggle, default: off)
│   └── Explanation (textarea, optional)
│
├── [Essay]
│   ├── Word Limit (number, optional)
│   ├── Marking Criteria (textarea — shown to teacher when grading)
│   └── NOTE: Always manual grading — flagged for review
│
├── [Matching]
│   ├── Match Pairs (add/remove rows, min 2):
│   │   ├── Left Item (text input) → Right Item (text input)
│   │   └── [Delete] button
│   ├── [+ Add Pair]
│   └── NOTE: Right items shuffled on student interface
│
├── [Fill in the Blank]
│   ├── Question Text with [BLANK] markers:
│   │   e.g., "The capital of Ghana is [BLANK]"
│   ├── Live Preview (renders question with blank boxes)
│   ├── Acceptable Answers (per blank):
│   │   ├── Blank 1: [answer] [+ Add Alternative]
│   │   └── Blank 2: [answer] [+ Add Alternative]
│   └── Case Sensitive (toggle, default: off)
│
├── [File Upload]
│   ├── Question Text / Instructions (textarea)
│   ├── Accepted File Types (checkboxes):
│   │   ├── ☐ PDF ☐ DOC/DOCX ☐ JPG/PNG ☐ ZIP ☐ Other
│   ├── Max File Size (number in MB, default: 10)
│   └── NOTE: Always manual grading — teacher downloads and reviews
│
└── [Numeric]
    ├── Correct Answer (number input, required)
    ├── Tolerance (number — ± acceptable range)
    └── Explanation (textarea, optional)
```

### 5C. Student Exam Experience

```
[STU-08: Exam List]
├── Tabs: [Upcoming] [In Progress] [Completed]
├── Each card:
│   ├── Exam title, subject, class
│   ├── Date + time
│   ├── Duration (if set)
│   ├── Attempt info: "Attempt 1 of 3" or "Unlimited attempts"
│   └── Action: [Start Exam] / [Continue] / [View Result] / [Retry]
└── Locked if: not yet available, attempts exhausted

        ↓ Click "Start Exam"

[STU-09: Exam Interface]
├── Top Bar:
│   ├── Exam title
│   ├── Timer countdown (if duration set)
│   ├── Attempt counter: "Attempt 1 of 3"
│   └── Progress: "Question 3 of 15"
├── Question Display (one per screen — mobile-friendly):
│   ├── Question number + text
│   ├── Answer input (varies by type):
│   │   ├── MC: Radio buttons
│   │   ├── Multi Select: Checkboxes
│   │   ├── T/F: Radio buttons
│   │   ├── Short Answer: Text input
│   │   ├── Essay: Rich textarea + word count
│   │   ├── Matching: Drag-and-drop or dropdown pairs
│   │   ├── Fill Blank: Inline text inputs
│   │   ├── File Upload: Dropzone + file picker
│   │   └── Numeric: Number input
│   └── Navigation: [← Previous] [Next →]
├── Sidebar (desktop): Question navigator (answered/unanswered/review)
├── Auto-grade on submit (MC, T/F, Numeric, Multi-Select, Fill-in-Blank)
├── Essay/Short Answer/File Upload → flagged requires_review
└── On [Submit]:
    ├── Confirmation modal: "Are you sure? You can't change answers."
    ├── exam_attempts record created
    ├── Score calculated (auto-graded portion)
    ├── IF attempt_limit_type = 'single' OR attempts exhausted:
    │   └── No more attempts available
    └── IF more attempts allowed:
        └── [Retry Exam] button shown

[STU-10: Exam Result]
├── Score display (based on grading_type):
│   ├── Percentage: "78%"
│   ├── Letter Grade: "B+"
│   ├── Numeric Score: "78 / 100"
│   └── Custom Scale: "Good (70-89%)" with color band
├── Feedback section (based on show_feedback_after):
│   ├── If "immediately": show feedback now
│   ├── If "after_due": show when due date passes
│   ├── If "after_graded": show when teacher finalizes
│   └── If "never": no feedback shown
├── Correct answers (if show_correct_answers = true):
│   └── Side-by-side: Student answer vs Correct answer
├── Teacher comments (if provided)
├── Retake available (if attempts remain)
└── Parent visibility (based on feedback_visibility)
```

### 5D. Teacher Grading Queue

```
[TCH-15: Question Review Queue]
├── Filter: [Pending Review] [Reviewed] [Overridden]
├── List of flagged answers:
│   ├── Student name, exam title, question type
│   ├── Question text + student's answer
│   ├── File attachment (for File Upload type)
│   └── [Review] button
├── Review modal:
│   ├── Student answer displayed
│   ├── Marking criteria (for Essay type)
│   ├── Score input (out of points)
│   ├── Feedback textarea
│   ├── [Approve] / [Override Score]
│   └── Override reason (if score changed)
└── Bulk actions: [Mark All as Reviewed]
```

---

## 6. PARENT COMMAND CENTER WORKFLOW

**Screens:** PAR-01 → PAR-02 through PAR-16  
**Route:** /parent/dashboard, /parent/child/{id}/...  
**Actor:** Parent

```
[PAR-01: Parent Command Center Dashboard]
├── Top Navigation:
│   ├── Child Switcher Dropdown (x-rp-child-switcher):
│   │   ├── Shows all linked children (unlimited)
│   │   ├── Each: Avatar + Name + Class
│   │   ├── AJAX state switch — reloads data without page refresh
│   │   └── Active child highlighted
│   ├── Notification Bell (x-rp-notification-bell)
│   └── Profile Menu
├── KPI Cards (2×2 grid):
│   ├── [Child OPS % + trend arrow]
│   ├── [Attendance % this term]
│   ├── [Outstanding Fees + due date] (Phase 10)
│   └── [Uncompleted Action Items count]
├── Widgets (vertical stack, reorderable):
│   ├── 1. Action Items List (PAR-06 link)
│   ├── 2. Teacher Remarks Feed (PAR-05 link)
│   ├── 3. Goal Progress Bars (PAR-04 link)
│   ├── 4. Invoice Quick-Pay (Phase 10)
│   ├── 5. Upcoming Sessions (next 3)
│   └── 6. Credential Management (PAR-16 link)
└── Dashboard Preferences:
    ├── [Customize] button → widget reorder/hide panel
    └── Saves to user_dashboard_preferences table

[PAR-02: Child OPS Detail]
├── OPS Score Ring (large)
├── "Why is my score X%?" expandable breakdown:
│   ├── Exams: 30% weight | Score: X% | Contribution: Y pts
│   ├── Assignments: 20% weight | Score: X% | Contribution: Y pts
│   ├── Attendance: 25% weight | Score: X% | Contribution: Y pts
│   ├── Participation: 15% weight | Score: X% | Contribution: Y pts
│   └── Behavior: 10% weight | Score: X% | Contribution: Y pts
├── Trend chart (ApexCharts area — multi-term)
└── Class rank: #X of Y

[PAR-03: Child Attendance]
├── Attendance rate KPI card
├── Monthly heatmap calendar (x-rp-attendance-calendar)
│   ├── Green: Present
│   ├── Yellow: Late
│   ├── Red: Absent
│   └── Grey: No class
├── By-subject breakdown table
└── Trend chart

[PAR-04: Child Goals]
├── List of active goals (x-rp-goal-card):
│   ├── Goal title + description
│   ├── Progress bar (%)
│   ├── Target date
│   └── Status badge
└── Completed goals section (collapsed)

[PAR-05: Teacher Remarks Feed]
├── Chronological feed:
│   ├── Teacher name + avatar
│   ├── Subject tag
│   ├── Date
│   └── Remark text
└── Filter by subject, teacher, date range

[PAR-06: Action Items]
├── Filter: [Pending] [In Progress] [Completed] [Overdue]
├── Each item:
│   ├── Title
│   ├── Teacher name
│   ├── Due date
│   ├── Status badge
│   ├── [Mark Complete] button
│   └── [View Detail] → PAR-07

[PAR-07: Action Item Detail]
├── Full description
├── Assigned by (teacher name)
├── Due date
├── Status
├── Log history (parent_action_item_logs):
│   ├── State changes with timestamps
│   └── Notes
└── Actions: [Mark Complete] [Add Note]

[PAR-15: Policy Acceptances]
├── Table of accepted policies:
│   ├── Policy type (Terms, Privacy, Payment, Data Processing)
│   ├── Accepted date
│   ├── IP address
│   └── Status (accepted)
└── Note: "These records are cryptographically logged and immutable"

[PAR-16: Credential Management]
├── Per child:
│   ├── Child name + Student ID
│   ├── [Copy Password]
│   ├── [Resend Credentials] (to parent email)
│   ├── [Download PDF]
│   └── [Email to Student] (enter email)
└── Security note: "Temporary password expires on first login"
```

---

## 7. STUDENT PORTAL WORKFLOW

**Screens:** STU-01 through STU-18  
**Route:** /student/dashboard, /student/...  
**Actor:** Student

```
[STU-01: Student Dashboard]
├── Hero Section (full width):
│   ├── OPS Score Ring (large, color-coded zones)
│   ├── Class Rank: #X of Y
│   ├── Streak: X days (x-rp-streak-badge)
│   └── Current Tier: Bronze/Silver/Gold/Platinum/Diamond (x-rp-tier-badge)
├── Subject Cards (grid):
│   ├── One per enrolled subject
│   ├── Subject name + color accent
│   ├── Score % + trend arrow
│   ├── Last grade
│   └── Color: green (>80%) / amber (60-79%) / red (<60%)
├── Widgets:
│   ├── Upcoming Deadlines (assignments + exams by date)
│   ├── Recent Badges Earned (last 3)
│   ├── Points to Next Tier (progress bar)
│   └── Leaderboard Position (mini leaderboard)
└── Dashboard Preferences: [Customize] → reorder/hide

[STU-02: OPS Breakdown]
├── "Why is my score X%?" expandable panel
├── Component breakdown table
├── Multi-term trend (ApexCharts area chart)
└── Comparison: class average, school average

[STU-03: My Timetable]
├── Weekly calendar view (Mon-Fri)
├── Time slots with subject blocks
├── Color-coded by subject
└── Click block → session detail

[STU-12: My Attendance]
├── Overall rate KPI
├── Monthly heatmap calendar
├── By-subject attendance table
└── Trend chart (ApexCharts)

[STU-13: My Goals]
├── Active goals with progress bars
├── Target dates
└── Goal history

[STU-14: Achievements]
├── Tier Progress:
│   ├── Current tier badge (large)
│   ├── Points: X / Y to next tier
│   └── Progress bar
├── Streak Tracker:
│   ├── Current streak: X days
│   ├── Longest streak: Y days
│   └── Milestone badges: 7/14/30/60/100
├── Badge Collection:
│   ├── Grid of earned badges
│   ├── Locked badges (greyed out)
│   └── Date earned
└── Points History (recent transactions)

[STU-15: Leaderboard]
├── Tabs: [Class] [School]
├── Table:
│   ├── Rank (with medal icons for top 3)
│   ├── Student name
│   ├── OPS Score
│   ├── Tier badge
│   └── Highlight current student row
├── Your Position card (sticky at top on mobile)
└── Filter: [This Term] [This Year] [All Time]

[STU-17: Notification Center]
├── Tab: [All] [Unread] [Academic] [Financial] [System]
├── Each notification:
│   ├── Icon (by category)
│   ├── Title + preview text
│   ├── Time (relative: "2 hours ago")
│   ├── Read/unread indicator (dot)
│   └── Click → mark as read + navigate to context
├── [Mark All as Read] button
└── Pagination or infinite scroll

[STU-18: Notification Preferences]
├── Per category (rows):
│   ├── Academic Updates
│   ├── Financial / Invoices
│   ├── Attendance Warnings
│   ├── System Announcements
│   └── Achievements / Gamification
├── Per channel (columns):
│   ├── In-App (always on)
│   ├── Email (toggle)
│   └── SMS (toggle)
├── Digest settings:
│   ├── Frequency: [None] [Daily] [Weekly]
│   └── Preferred time (time picker)
└── [Save Preferences]
```

---

## 8. TEACHER WORKSPACE WORKFLOW

**Screens:** TCH-01 through TCH-26  
**Route:** /teacher/dashboard, /teacher/...  
**Actor:** Teacher

```
[TCH-01: Teacher Dashboard]
├── KPI Cards:
│   ├── [Students at Risk count]
│   ├── [Pending Submissions count]
│   ├── [This Week's Sessions count]
│   └── [My KPI Score]
├── Widgets:
│   ├── Upcoming Timetable (next 3 sessions)
│   ├── Recent Submissions Needing Review
│   ├── At-Risk Students Alert (OPS < 50%)
│   └── Earnings Summary (Phase 11)
├── Quick Actions:
│   ├── [Create Assignment]
│   ├── [Create Exam]
│   ├── [Log Attendance]
│   └── [Start Live Session]
└── Dashboard Preferences: [Customize]

[TCH-02: My Timetable]
├── Weekly calendar (Mon-Fri, 8am-5pm)
├── Session blocks with:
│   ├── Subject + class
│   ├── Time slot
│   ├── Room / online indicator
│   └── Click → TCH-04 Session Detail

[TCH-04: Session Detail]
├── Session info:
│   ├── Subject, class, date, time
│   ├── Mode: Physical / Online / Hybrid
│   ├── Room / Zoom link
│   └── Status badge
├── Actions:
│   ├── [Start Session] (if online) → TCH-05
│   ├── [Log Attendance] → TCH-06
│   ├── [Start Recording] (if in session)
│   └── [End Session] (if in session)
├── Attendance summary (if session completed):
│   ├── Present: X | Late: Y | Absent: Z
│   └── [View Full Log]

[TCH-06: Attendance Logger]
├── Session header info
├── Student list:
│   ├── Name
│   ├── Status dropdown: [Present] [Late] [Absent] [Excused]
│   └── Notes (text, optional)
├── Bulk actions:
│   ├── [Mark All Present]
│   └── [Mark All Absent]
├── For online sessions:
│   └── Auto-populated from class_session_joins + AutoAttendanceService
│       ├── Students who joined on time: pre-set to Present
│       ├── Students who joined late: pre-set to Late
│       └── Students who didn't join: Absent
└── [Save Attendance]

[TCH-07: My Students]
├── Filters: [Class] [Performance Level] [Attendance Risk]
├── List:
│   ├── Student name + avatar
│   ├── Class
│   ├── OPS Score + ring (mini)
│   ├── Attendance %
│   ├── Risk indicator (green/amber/red)
│   └── [View Detail] → TCH-08
└── Export option (Excel)

[TCH-08: Student Detail (Teacher View)]
├── Tab: [Overview] [OPS] [Attendance] [Submissions] [Goals]
├── Overview tab: Profile, OPS ring, quick stats
├── OPS tab: Component breakdown, trend
├── Attendance tab: Calendar, rate by subject
├── Submissions tab: Assignments + exams with grades
└── Goals tab: Active goals, progress

[TCH-09: Create Assignment]
├── Fields:
│   ├── Title, description
│   ├── Subject, class, term
│   ├── Due date + time
│   ├── Max score
│   ├── Grading type (percentage/letter/numeric/custom)
│   ├── Late submission policy (allow/discount/deduct)
│   └── Attachments / resource links
├── Questions section (if question-based assignment):
│   └── [Add Question] → TCH-16 Question Builder
└── Actions: [Save Draft] [Publish]

[TCH-10: Assignment Detail]
├── Assignment info header
├── Tabs: [Submissions] [Grading Queue] [Analytics]
├── Submissions tab:
│   ├── Student list with submission status
│   ├── Submitted files (downloadable)
│   └── [Grade] → TCH-11
├── Grading Queue tab:
│   └── Pending submissions sorted by submit date
└── Analytics tab:
    ├── Average score (ApexCharts)
    ├── Score distribution (histogram)
    └── Submission timeline

[TCH-11: Grade Submission]
├── Student info + submission date
├── Submitted answer/file (preview inline)
├── Grading:
│   ├── Score (number input, out of max)
│   ├── Feedback (textarea)
│   └── Rubric scoring (if rubric attached)
└── Actions: [Save Draft] [Submit Grade]

[TCH-12: Create Exam]
├── Full form specification in Section 5A above
└── [Add Question] → TCH-16 Question Builder

[TCH-15: Question Review Queue]
├── Full specification in Section 5D above
└── Dedicated queue for manual grading

[TCH-18: Student Goals]
├── Active goals:
│   ├── Student selector
│   ├── Goal title + description
│   ├── Target metric + target value
│   ├── Target date
│   └── Current progress
├── [Create New Goal]
└── Goal history + achieved goals

[TCH-19: Intervention Plans]
├── List of active intervention plans
├── [Create Intervention Plan]:
│   ├── Student (select)
│   ├── Reason / trigger (OPS drop, attendance, etc.)
│   ├── Action items (add/remove):
│   │   ├── Action description
│   │   ├── Assigned to (teacher/parent/student)
│   │   └── Due date
│   └── Review date
└── Plan history + completed interventions

[TCH-20: Parent Action Items]
├── Create action item:
│   ├── Title + description
│   ├── Assign to parent (select linked parent)
│   ├── Due date
│   └── Priority (normal/high/urgent)
├── Active items list:
│   ├── Title, parent name, due date
│   ├── Status badge
│   └── [View Log] → state changes history
└── Completed items (collapsed)

[TCH-21: My Availability]
├── Weekly grid (Mon-Sun, time slots)
├── Set available hours:
│   ├── Click + drag to select time blocks
│   ├── Color-code by type (regular/available/unavailable)
│   └── Save per recurring week
└── [Save Availability]

[TCH-24: Messages]
├── Inbox (tabs: [All] [Unread] [Archived])
├── Conversation list:
│   ├── Participant name/avatar
│   ├── Last message preview
│   ├── Timestamp
│   └── Unread indicator
├── Conversation view:
│   ├── Message thread (chat-style)
│   ├── Message input + send
│   ├── File attachment
│   └── Read receipts
└── Compose: Select recipient(s) → Start conversation

[TCH-26: My Profile]
├── Personal info (name, email, phone, DOB)
├── Professional info (qualifications, bio)
├── CV (Spatie Media Library):
│   ├── Current CV preview/download
│   ├── [Upload New CV]
│   └── Supported: PDF, DOC, DOCX (max 5MB)
└── [Save Changes]
```

---

## 9. ADMIN PORTAL WORKFLOW

**Screens:** ADM-01 through ADM-31  
**Route:** /admin/...  
**Actor:** Admin / Super-Admin

```
[ADM-01: Admin Dashboard]
├── KPI Cards:
│   ├── [Total Students] + trend
│   ├── [Active Teachers] + trend
│   ├── [Attendance Rate Today]
│   ├── [Pending Payments] (Phase 10)
│   ├── [At-Risk Students count]
│   └── [Active Interventions count]
├── Widgets:
│   ├── Enrollment Trend (ApexCharts stacked bar)
│   ├── Recent Alerts
│   ├── Quick Actions panel
│   └── System health indicators
└── Dashboard Preferences: [Customize]

[ADM-07: Teachers List]
├── Table: Name, Email, Status, Classes, Actions
├── [Invite Teacher] → invitation modal
├── Actions per row: [View] [Edit] [Deactivate]
└── Filters: [Status] [Subject] [Class]

[ADM-09: Students List]
├── Table: Name, Student ID (RP-2026-XXXXX), Class, OPS, Status
├── [Add Student] (manual, admin-created)
├── Actions: [View] [Edit] [Withdraw]
├── Filters: [Class] [Status] [OPS Range]
└── Export: [Download Excel]

[ADM-10: Student Detail]
├── Tabs: [Profile] [OPS] [Attendance] [Academic] [Financial] [Audit]
├── Profile: Name, ID, DOB, gender, guardian(s), enrollment date
├── Financial (Phase 10): Invoices, payments, balance
└── Audit: Activity log (Spatie)

[ADM-12: Parent Detail]
├── Parent info + linked students
├── Policy acceptances list
├── Invoices (Phase 10)
└── Action items history

[ADM-13: Timetable Manager]
├── Weekly grid view
├── Create/edit entry:
│   ├── Class, Subject, Teacher
│   ├── Day, Time slot
│   ├── Room / Online
│   └── Recurring pattern
└── Conflict detection

[ADM-18: OPS Dashboard]
├── School-wide OPS distribution (histogram)
├── Class comparison (bar chart)
├── Subject performance (radial gauges)
├── At-risk student alerts
└── Trend analysis (multi-term)

[ADM-20: Fee Categories] (Phase 10)
├── CRUD list with drag-to-reorder
├── Each: Name, color, active status
└── [Create] [Edit] [Delete]

[ADM-21: Fee Structures] (Phase 10)
├── CRUD list
├── Each: Name, category, amount, frequency, due date
└── [Create] [Edit] [Archive]

[ADM-22: Invoices List] (Phase 10)
├── Tabs: [Draft] [Sent] [Paid] [Overdue] [All]
├── Table: Invoice #, Student, Parent, Amount, Status, Due Date
├── [Generate Invoice] → wizard
└── Bulk actions: [Send Selected] [Cancel Selected]

[ADM-27: Announcements]
├── Create announcement:
│   ├── Title
│   ├── Body (rich textarea)
│   ├── Target audience (radio): All / Admin / Teacher / Student / Parent
│   ├── Urgent toggle (shows as system banner)
│   ├── Publish date (immediate or scheduled)
│   └── Expiry date (optional)
├── Published announcements list
└── Read statistics

[ADM-29: School Settings]
├── Tabs: [Branding] [OPS Config] [Finance] [Zoom] [Auto-Attendance] [Notifications]
├── Branding:
│   ├── School name, logo, colors
│   └── Dark mode default setting
├── OPS Config:
│   ├── Component weights (Exam, Assignment, Attendance, Participation, Behavior)
│   └── Must sum to 100%
├── Finance (Phase 10):
│   ├── Paystack public key
│   ├── Paystack secret key
│   ├── Currency code: GHS
│   ├── Currency symbol: GHS
│   └── Default due date offset
├── Zoom:
│   ├── SDK Key
│   ├── SDK Secret
│   └── Webhook URL
├── Auto-Attendance:
│   └── Threshold minutes (default: 10)
├── Notifications:
│   └── Default digest frequency
└── [Save Settings]

[ADM-30: Teacher Compensation Settings]
├── Per-teacher configuration:
│   ├── Base session rate (GHS)
│   ├── Private session rate (GHS)
│   ├── Admin fee percentage
│   └── Effective date
├── Audit log of changes
└── Bulk update option
```

---

## 10. FINANCE WORKFLOW (Phase 10 Preview)

**Screens:** ADM-20 through ADM-24, PAR-08 through PAR-11  
**Actor:** Admin (management) + Parent (payment)

```
[Parent: PAR-08 Invoices List]
├── KPI: Outstanding Fees total + next due date
├── Tabs: [Outstanding] [Paid] [All]
├── Each invoice card (x-rp-invoice-card):
│   ├── Invoice #: INV-2026-NNNN
│   ├── Student name
│   ├── Amount: GHS 1,500.00
│   ├── Due date
│   ├── Status badge
│   └── [Pay Now] / [View Detail] / [Download PDF]

[Parent: PAR-09 Invoice Detail]
├── Invoice header:
│   ├── Invoice #: INV-2026-NNNN
│   ├── Date issued
│   ├── Due date
│   └── Status
├── Student: Name + Student ID
├── Line items table:
│   ├── Description | Qty | Unit Price | Discount | Total
│   ├── Subtotal
│   ├── Discount
│   └── Total: GHS X,XXX.XX
├── Actions:
│   ├── [Proceed to Payment] → PAR-10
│   ├── [Download PDF]
│   └── Payment history (if partially paid)

[Parent: PAR-10 Payment Flow]
├── Invoice summary (sticky header)
├── Amount due: GHS X,XXX.XX
├── Payment Method Tabs:
│   ├── [Card]
│   │   └── Paystack inline popup triggered
│   │       └── Card number, expiry, CVV (Paystack UI)
│   ├── [Mobile Money]
│   │   ├── Provider select: MTN / Vodafone Cash / AirtelTigo
│   │   ├── Mobile number (tel input)
│   │   ├── [Send Payment Request]
│   │   ├── Loading state: "Confirm on your phone..."
│   │   ├── Polling status (every 5s)
│   │   ├── Success: "Payment Confirmed ✓"
│   │   ├── Timeout (3 min): "Payment timed out. [Retry]"
│   │   └── [Cancel]
│   ├── [Bank Transfer]
│   │   ├── Paystack generates virtual account
│   │   ├── Bank: [Bank Name]
│   │   ├── Account: [generated number]
│   │   ├── Amount: GHS X,XXX.XX (exact)
│   │   ├── [I have made the transfer]
│   │   └── Polling for confirmation
│   └── [USSD]
│       ├── Select bank (dropdown)
│       ├── USSD Code: *737*[amount]*[reference]#
│       ├── Instructions per bank
│       └── [I have completed the payment]
├── On Success:
│   ├── Success screen: "Payment Confirmed ✓"
│   ├── Payment record created
│   ├── Invoice status updated
│   ├── PDF receipt generated (DomPDF)
│   ├── [Download Receipt PDF]
│   ├── [Return to Dashboard]
│   └── Email receipt sent automatically
└── On Failure:
    ├── Error message with reason
    └── [Try Again] / [Choose Different Method]

[Admin: ADM-24 Payments List]
├── Tabs: [Today] [This Week] [This Month] [All]
├── Table: Reference, Parent, Student, Amount, Method, Status, Date
├── Filters: [Method] [Status] [Date Range]
├── [Record Manual Payment] (cash/cheque/waiver)
└── Export: [Download Excel]
```

---

## 11. PAYROLL WORKFLOW (Phase 11 Preview)

**Screens:** ADM-25, ADM-26, TCH-22  
**Actor:** Admin (management) + Teacher (view)

```
[Admin: ADM-25 Payroll List]
├── Payroll periods list:
│   ├── Period name (e.g., "June 2026")
│   ├── Date range
│   ├── Status: Draft / Preview / Processing / Completed
│   └── Actions: [View] [Process]
└── [Create Payroll Period]

[Admin: ADM-26 Payroll Period Detail]
├── Period header
├── Preview table (before processing):
│   ├── Teacher | Sessions | Gross | Admin Fee | Net
│   └── Total row
├── Actions:
│   ├── [Calculate] → runs PayrollCalculatorService
│   ├── [Process] → finalizes payroll
│   └── [Export Excel]
└── Post-processing:
    ├── Individual payslips (PDF download)
    └── Transaction log

[Teacher: TCH-22 My Payroll]
├── Waterfall chart (ApexCharts):
│   ├── Gross Earnings
│   ├── - Admin Fee
│   ├── + Adjustments
│   └── = Net Earnings
├── History table:
│   ├── Period | Gross | Admin Fee | Adjustments | Net | Status
│   └── [Download Payslip]
└── Current balance indicator
```

---

## 12. NOTIFICATION SYSTEM WORKFLOW

**Actor:** All roles  
**Infrastructure:** notifications table, notification_preferences table

```
[Notification Delivery Pipeline]
├── Event triggers notification creation
├── NotificationPreference lookup:
│   ├── Category: academic / financial / attendance / payroll / system / gamification
│   └── Channels: in_app (always) | email | sms
├── Delivery:
│   ├── In-App → notifications table → x-rp-notification-bell badge update
│   ├── Email → Mail queue → delivered
│   └── SMS → TxtConnectService → delivered
├── Digest (if configured):
│   ├── Daily: Scheduled job at 8:00 AM local
│   └── Weekly: Scheduled job Monday 8:00 AM local
│   └── Aggregates unread notifications into summary email/SMS
└── Read tracking:
    ├── Click notification → mark as read
    └── [Mark All as Read] in notification center

[Notification Categories & Channels]
┌──────────────────────┬────────┬───────┬─────┐
│ Category             │ In-App │ Email │ SMS │
├──────────────────────┼────────┼───────┼─────┤
│ Academic Updates     │   ✓    │   ✓   │  ✓  │
│ Financial / Invoices │   ✓    │   ✓   │  ✓  │
│ Attendance Warnings  │   ✓    │   ✓   │  ✓  │
│ Payroll / Earnings   │   ✓    │   ✓   │  —  │
│ System Announcements │   ✓    │   ✓   │  —  │
│ Achievements         │   ✓    │   —   │  —  │
└──────────────────────┴────────┴───────┴─────┘

[Notification Types]
┌──────────────────────────┬────────────────────────────┬──────────────┐
│ Trigger                  │ Recipients                 │ Channels     │
├──────────────────────────┼────────────────────────────┼──────────────┤
│ InvoiceGenerated         │ Parent (primary guardian)  │ In-App+Email │
│ InvoicePaid              │ Parent + Admin             │ In-App+Email │
│ InvoiceOverdue           │ Parent (primary guardian)  │ In-App+Email+SMS │
│ PaymentReceiptReady      │ Parent                     │ In-App+Email │
│ PayrollProcessed         │ Teacher                    │ In-App+Email │
│ AssignmentPublished      │ Students in class          │ In-App+Email │
│ AssignmentGraded         │ Student + Parent           │ In-App+Email │
│ ExamScheduled            │ Students in class          │ In-App+Email │
│ ExamResultFinalised      │ Student + Parent           │ In-App+Email │
│ AttendanceWarning        │ Parent (primary guardian)  │ In-App+Email+SMS │
│ ActionItemAssigned       │ Parent                     │ In-App+Email │
│ ActionItemOverdue        │ Parent                     │ In-App+Email+SMS │
│ CertificateIssued        │ Student + Parent           │ In-App+Email │
│ StudentGoalAchieved      │ Student + Parent           │ In-App+Email │
│ MilestoneEarned          │ Student                    │ In-App       │
│ SessionStarting          │ Students + Parents         │ In-App+Email │
│ TeacherInvitationSent    │ Teacher (email)            │ Email        │
└──────────────────────────┴────────────────────────────┴──────────────┘
```

---

## 13. DASHBOARD PREFERENCES WORKFLOW

**Actor:** All authenticated users  
**Table:** user_dashboard_preferences

```
[Dashboard Customization Panel]
├── Trigger: [Customize] button on any dashboard
├── Overlay/drawer slides in from right
├── Widget List (draggable):
│   ├── Each widget row:
│   │   ├── Drag handle (⠿)
│   │   ├── Widget name
│   │   ├── Eye icon toggle (show/hide)
│   │   └── Preview thumbnail
│   └── Drag to reorder
├── Theme selector:
│   ├── ○ Light
│   ├── ○ Dark
│   └── ○ System (follow OS preference)
├── Sidebar state:
│   ├── ○ Expanded
│   └── ○ Collapsed
├── Actions:
│   ├── [Save Layout] → POST /dashboard/preferences
│   ├── [Reset to Default]
│   └── [Cancel]
└── Saved to user_dashboard_preferences:
    ├── widget_order (JSON array of widget keys)
    ├── hidden_widgets (JSON array of hidden keys)
    ├── theme (light/dark/system)
    └── sidebar_state (expanded/collapsed)
```

---

## 14. CONSENT MANAGEMENT WORKFLOW

**Actor:** Parent (Primary Guardian)  
**Table:** policy_acceptances

```
[Consent Collection Points]
├── Registration (REG-02):
│   ├── Terms of Service acceptance
│   ├── Privacy Policy acceptance
│   ├── Payment Responsibility acceptance
│   └── Data Processing consent
├── Policy update (future):
│   ├── Banner: "Updated policies require your acceptance"
│   ├── Review diff
│   └── Accept → new policy_acceptances record
└── View history (PAR-15):
    ├── Table of all accepted policies
    ├── Timestamp, IP address
    └── Cryptographic log (immutable)

[Consent Record]
├── policy_type: terms | privacy | payment | data_processing
├── accepted_at: timestamp
├── ip_address: string
├── user_agent: string
└── version: string (policy version at time of acceptance)