[2026-06-25T21:48:03.654Z] === WS Hub + Role-aware Dashboard smoke test ===
[2026-06-25T21:48:03.659Z] HTTP base: http://localhost:3001
[2026-06-25T21:48:03.659Z] WS base:   ws://localhost:3001
[2026-06-25T21:48:03.659Z] 
[2026-06-25T21:48:03.659Z] --- 1. Login as each demo role ---
[2026-06-25T21:48:03.895Z] admin   id=2 role=school_admin
[2026-06-25T21:48:04.003Z] teacher id=3 role=teacher
[2026-06-25T21:48:04.106Z] student id=6 role=student
[2026-06-25T21:48:04.209Z] parent  id=11 role=parent
[2026-06-25T21:48:04.209Z] 
[2026-06-25T21:48:04.209Z] --- 2. WS invalid-JWT rejection ---
[2026-06-25T21:48:04.215Z] WS(invalid) result: REJECTED ÔÇö HTTP 401
[2026-06-25T21:48:04.216Z] 
[2026-06-25T21:48:04.217Z] --- 3. WS valid-JWT connect + subscribe ---
[2026-06-25T21:48:04.228Z] WS(open): connection established
[2026-06-25T21:48:04.230Z] WS(msg): {"type":"welcome","userId":2,"role":"school_admin","serverTime":"2026-06-25T21:48:04.227Z"}
[2026-06-25T21:48:04.231Z] WS(msg): {"type":"subscribed","channels":["class:1","class:2"]}
[2026-06-25T21:48:04.441Z] WS(msg): {"type":"pong","serverTime":"2026-06-25T21:48:04.442Z"}
[2026-06-25T21:48:04.647Z] WS(valid) received 3 message(s): ["welcome","subscribed","pong"]
[2026-06-25T21:48:04.647Z] 
[2026-06-25T21:48:04.647Z] --- 4. Role-aware dashboard analytics ---
[2026-06-25T21:48:04.670Z] admin    status=200 time=22ms under500=true
[2026-06-25T21:48:04.670Z]            analytics fields: {"active_enrollments":5,"attendance_rate_30d":0,"grade_distribution":{"A":0,"B":0,"C":0,"D":0,"F":0,"total":0},"programs_count":3,"classes_count":5,"users_by_role":{"librarian":1,"parent":1,"school_admin":1,"student":6,"systems_admin":1,"teacher":3}}
[2026-06-25T21:48:04.678Z] teacher  status=200 time=8ms under500=true
[2026-06-25T21:48:04.678Z]            analytics fields: {"per_course":[],"overall_students_count":0,"pending_grading_count":0}
[2026-06-25T21:48:04.688Z] student  status=200 time=10ms under500=true
[2026-06-25T21:48:04.688Z]            analytics fields: {"per_course":[],"recent_marks":[],"gamification_points":212,"leaderboard_rank":1}
[2026-06-25T21:48:04.698Z] parent   status=200 time=10ms under500=true
[2026-06-25T21:48:04.699Z]            analytics fields: {"per_dependent":[{"student_id":7,"name":"Tatenda Banda","upcoming_deadlines":0,"attendance_flags":{"percent":0,"total":0,"present":0,"absent":0,"late":0,"flag":"low_attendance"},"fee_status":{"outstanding":0,"paid_count":0,"pending_count":0,"total_count":0,"flag":"clear"},"grade_progression":{"recent_avg_percent":null,"prior_avg_percent":null,"trend":null,"direction":"unknown"}},{"student_id":10,"name":"Blessing Dube","upcoming_deadlines":0,"attendance_flags":{"percent":0,"total":0,"present":0,"absent":0,"late":0,"flag":"low_attendance"},"fee_status":{"outstanding":0,"paid_count":0,"pending_count":0,"total_count":0,"flag":"clear"},"grade_progression":{"recent_avg_percent":null,"prior_avg_percent":null,"trend":null,"direction":"unknown"}},{"student_id":6,"name":"Nyasha Moyo","upcoming_deadlines":0,"attendance_flags":{"percent":0,"total":0,"present":0,"absent":0,"late":0,"flag":"low_attendance"},"fee_status":{"outstanding":0,"paid_count":0,"pending_count":0,"total_count":0,"flag":"clear"},"grade_progression":{"recent_avg_percent":null,"prior_avg_percent":null,"trend":null,"direction":"unknown"}},{"student_id":8,"name":"Kudakwashe Ncube","upcoming_deadlines":0,"attendance_flags":{"percent":0,"total":0,"present":0,"absent":0,"late":0,"flag":"low_attendance"},"fee_status":{"outstanding":0,"paid_count":0,"pending_count":0,"total_count":0,"flag":"clear"},"grade_progression":{"recent_avg_percent":null,"prior_avg_percent":null,"trend":null,"direction":"unknown"}},{"student_id":9,"name":"Rutendo Sithole","upcoming_deadlines":0,"attendance_flags":{"percent":0,"total":0,"present":0,"absent":0,"late":0,"flag":"low_attendance"},"fee_status":{"outstanding":0,"paid_count":0,"pending_count":0,"total_count":0,"flag":"clear"},"grade_progression":{"recent_avg_percent":null,"prior_avg_percent":null,"trend":null,"direction":"unknown"}}]}
[2026-06-25T21:48:04.699Z] 
[2026-06-25T21:48:04.699Z] --- 5. Verdict ---
[2026-06-25T21:48:04.699Z] all_ok=true all_under_500ms=true
[2026-06-25T21:48:04.699Z] VERDICT: PASS
===SMOKE_RESULT_JSON==={"pass":true,"summary":{"admin":{"status":200,"timeMs":22,"under500":true,"ok":true,"newFields":{"active_enrollments":5,"attendance_rate_30d":0,"grade_distribution":{"A":0,"B":0,"C":0,"D":0,"F":0,"total":0},"programs_count":3,"classes_count":5,"users_by_role":{"librarian":1,"parent":1,"school_admin":1,"student":6,"systems_admin":1,"teacher":3}},"bodyKeys":["stats","recentActivity","attendanceByDay","enrollmentByClass","active_enrollments","attendance_rate_30d","grade_distribution","programs_count","classes_count","users_by_role"]},"teacher":{"status":200,"timeMs":8,"under500":true,"ok":true,"newFields":{"per_course":[],"overall_students_count":0,"pending_grading_count":0},"bodyKeys":["myClasses","mySubjects","todayStats","recentMessages","todaysAttendance","per_course","overall_students_count","pending_grading_count"]},"student":{"status":200,"timeMs":10,"under500":true,"ok":true,"newFields":{"per_course":[],"recent_marks":[],"gamification_points":212,"leaderboard_rank":1},"bodyKeys":["attendancePercent","attendanceStats","attendanceByDay","activeClasses","myClasses","mySubjects","feesSummary","unreadMessages","pendingAssignments","upcomingExams","recentGrades","per_course","pending_assignments_count","recent_marks","gamification_points","leaderboard_rank","leaderboard_total_students"]},"parent":{"status":200,"timeMs":10,"under500":true,"ok":true,"newFields":{"per_dependent":[{"student_id":7,"name":"Tatenda Banda","upcoming_deadlines":0,"attendance_flags":{"percent":0,"total":0,"present":0,"absent":0,"late":0,"flag":"low_attendance"},"fee_status":{"outstanding":0,"paid_count":0,"pending_count":0,"total_count":0,"flag":"clear"},"grade_progression":{"recent_avg_percent":null,"prior_avg_percent":null,"trend":null,"direction":"unknown"}},{"student_id":10,"name":"Blessing Dube","upcoming_deadlines":0,"attendance_flags":{"percent":0,"total":0,"present":0,"absent":0,"late":0,"flag":"low_attendance"},"fee_status":{"outstanding":0,"paid_count":0,"pending_count":0,"total_count":0,"flag":"clear"},"grade_progression":{"recent_avg_percent":null,"prior_avg_percent":null,"trend":null,"direction":"unknown"}},{"student_id":6,"name":"Nyasha Moyo","upcoming_deadlines":0,"attendance_flags":{"percent":0,"total":0,"present":0,"absent":0,"late":0,"flag":"low_attendance"},"fee_status":{"outstanding":0,"paid_count":0,"pending_count":0,"total_count":0,"flag":"clear"},"grade_progression":{"recent_avg_percent":null,"prior_avg_percent":null,"trend":null,"direction":"unknown"}},{"student_id":8,"name":"Kudakwashe Ncube","upcoming_deadlines":0,"attendance_flags":{"percent":0,"total":0,"present":0,"absent":0,"late":0,"flag":"low_attendance"},"fee_status":{"outstanding":0,"paid_count":0,"pending_count":0,"total_count":0,"flag":"clear"},"grade_progression":{"recent_avg_percent":null,"prior_avg_percent":null,"trend":null,"direction":"unknown"}},{"student_id":9,"name":"Rutendo Sithole","upcoming_deadlines":0,"attendance_flags":{"percent":0,"total":0,"present":0,"absent":0,"late":0,"flag":"low_attendance"},"fee_status":{"outstanding":0,"paid_count":0,"pending_count":0,"total_count":0,"flag":"clear"},"grade_progression":{"recent_avg_percent":null,"prior_avg_percent":null,"trend":null,"direction":"unknown"}}]},"bodyKeys":["children","childrenCount","feesSummary","messages","upcomingEvents","per_dependent"]}},"wsMessages":[{"type":"welcome","userId":2,"role":"school_admin","serverTime":"2026-06-25T21:48:04.227Z"},{"type":"subscribed","channels":["class:1","class:2"]},{"type":"pong","serverTime":"2026-06-25T21:48:04.442Z"}]}
