# Lessons List Page Ideation ## Purpose Define the most useful, straight-to-the-point information to show in a non-grouped lessons list page (lessons + exercises), split by persona and course type, plus a data availability audit and implementation effort. ## Data Sources Checked - `apps/dashboard/src/lib/features/course/pages/lessons.svelte` - `apps/dashboard/src/lib/features/course/components/lesson/content-list.svelte` - `apps/api/src/services/course/course.ts` - `apps/api/src/services/course/utils.ts` - `packages/db/src/queries/course/content.ts` - `packages/db/src/schema.ts` ## Data Availability & Effort Legend: ✅ available now, ⚠️ exists but not in list payload, ❌ missing data ### Teachers — Generic | Field | Content Type (Lesson/Exercise) | Availability | Source / Notes | Effort | Visualization | Should Implement | | --- | --- | --- | --- | --- | --- | --- | | Title | Both | ✅ | `CourseContentItem.title` | Low | Primary title text | [x] | | Item type icon | Both | ✅ | `CourseContentItem.type` | Low | Lesson/Exercise icon (no text) | [x] | | Quick actions | Both | ✅ | UI-only | Low | Action buttons (Edit/Assign/Preview) | [x] | | Lock status (locked/unlocked) | Both | ✅ | `isUnlocked` on lessons/exercises | Low | Lock/unlock icon (clickable) | [x] | | Resources attached | Lesson | ✅ | `documentsCount` + `videosCount` in list payload | Medium | Icons with counts | [x] | | Question count | Exercise | ✅ | `questionCount` in list payload | Medium–High | “5 questions” chip | [x] | ### Teachers — Live Class | Field | Content Type (Lesson/Exercise) | Availability | Source / Notes | Effort | Visualization | Should Implement | | --- | --- | --- | --- | --- | --- | --- | | Scheduled date/time | Lesson | ✅ | `lessonAt` in list payload | Medium | Date/time chip + calendar icon | [x] | | Join/host link | Lesson | ✅ | `callUrl` in list payload | Medium | Primary CTA button | [x] | | Submissions count | Exercise | ⚠️ | Submissions endpoints exist, not per exercise | High | Count pill + “needs review” tag | [ ] | | Attendance snapshot | Lesson | ❌ | Attendance has only upsert, no GET | High | Mini stat: “12/18 attended” | [ ] | ### Teachers — Self-Paced | Field | Content Type (Lesson/Exercise) | Availability | Source / Notes | Effort | Visualization | Should Implement | | --- | --- | --- | --- | --- | --- | --- | | Status (Not started/Submitted/Graded) | Exercise | ⚠️ | Needs submission grading state in list payload | Medium–High | Status badge | [ ] | | Due date / window | Exercise | ✅ | `dueBy` in list payload | Medium | Date chip | [x] | | Due date / window | Lesson | ❌ | No lesson due date field | High | Date chip | [ ] | | Submissions pending review | Exercise | ⚠️ | “for-grading” exists, not per exercise | High | Count + alert pill | [ ] | | Last student activity | Both | ❌ | No per-item activity log | High | “Last activity: 2d ago” text | [ ] | ### Students — Generic | Field | Content Type (Lesson/Exercise) | Availability | Source / Notes | Effort | Visualization | Should Implement | | --- | --- | --- | --- | --- | --- | --- | | Title | Both | ✅ | `CourseContentItem.title` | Low | Primary title text | [x] | | Item type icon | Both | ✅ | `CourseContentItem.type` | Low | Lesson/Exercise icon (no text) | [x] | | Lock status (locked/unlocked) | Both | ✅ | `isUnlocked` on lessons/exercises (read-only) | Low | Lock icon (disabled) | [x] | | Lesson content (materials) | Lesson | ✅ | `documentsCount` + `videosCount` in list payload | Medium | Icons with counts | [x] | | Completion state (Complete/Not complete) | Lesson | ✅ | `isComplete` | Low | Status badge | [x] | | Submission state (Not started/Submitted/Graded) | Exercise | ⚠️ | Needs submission/grading state | Medium | Status badge | [ ] | | Next step | Both | ✅ | Derive from `isComplete`/`isUnlocked` | Low | “Continue” button | [x] | ### Students — Live Class | Field | Content Type (Lesson/Exercise) | Availability | Source / Notes | Effort | Visualization | Should Implement | | --- | --- | --- | --- | --- | --- | --- | | Scheduled date/time | Lesson | ✅ | `lessonAt` in list payload | Medium | Date/time chip | [x] | | Join link/button | Lesson | ✅ | `callUrl` in list payload | Medium | Primary CTA button | [x] | | Lesson content (materials) | Lesson | ✅ | `documentsCount` + `videosCount` in list payload | Medium | Icons with counts | [x] | | Instructor name | Lesson | ⚠️ | `lesson.teacherId` exists; needs profile join | High | Secondary label | [ ] | | Notes / prep checklist | Lesson | ✅ | `hasNoteContent` in list payload (derived from lesson note translations) | Medium | Note/`no-content` chip | [x] | ### Students — Self-Paced | Field | Content Type (Lesson/Exercise) | Availability | Source / Notes | Effort | Visualization | Should Implement | | --- | --- | --- | --- | --- | --- | --- | | Due date | Exercise | ✅ | `dueBy` in list payload | Medium | Date chip | [x] | | Due date | Lesson | ❌ | No lesson due date field | High | Date chip | [ ] | | Estimated time | Both | ❌ | No field currently | High | “~30 min” text | [ ] | ## Implemented (2026-02-08) ### Field Contract Added to Course Content List Payload - `lessonAt: string | null` - `callUrl: string | null` - `hasNoteContent: boolean | null` - `videosCount: number | null` - `documentsCount: number | null` - `questionCount: number | null` - `dueBy: string | null` ### UI Behavior Delivered - Persona-first rendering for teachers/admin vs students in both list modes (grouped and non-grouped). - Date rendering uses existing app formatter (`formatDate`); missing values are hidden. - Lock toggle is teacher/admin-only; students get read-only lock state. - Teacher/admin rows include schedule/join CTA for live class, resources count for lessons, question count and due date for exercises. - Student rows include completion state (lesson), materials count (lesson), note/no-content status (lesson), schedule/join (live), due date (self-paced), and next-step CTA. ### Verification Run - `pnpm --filter @cio/dashboard build` ✅ - `pnpm --filter @cio/api build` ✅ ## Visualization Recommendations (Summary) - Use a **two-line row**: title, then meta chips. - Status and time should be **chips/badges** aligned right or under title. - Progress should be implied by status; avoid redundant percent bars. - Resources and requirements should be **icons with counts**. - Primary action should be a **single CTA** (Join / Continue / Review). - Separate lesson items from exercise items (distinct sections or tabs). ## Kanban Board (Ideation Phase) | Ticket | Title | Todo | In Progress | Verification | Done | | --- | --- | --- | --- | --- | --- | | T1 | Teachers: show lesson/exercise title | [ ] | [ ] | [x] | [x] | | T2 | Teachers: show lesson/exercise type icon | [ ] | [ ] | [x] | [x] | | T3 | Teachers: show quick actions | [ ] | [ ] | [x] | [x] | | T4 | Teachers: show lock/unlock status | [ ] | [ ] | [x] | [x] | | T5 | Teachers: show lesson resources count | [ ] | [ ] | [x] | [x] | | T6 | Teachers: show exercise question count | [ ] | [ ] | [x] | [x] | | T7 | Teachers live class: show schedule time | [ ] | [ ] | [x] | [x] | | T8 | Teachers live class: show join/host link | [ ] | [ ] | [x] | [x] | | T9 | Teachers self-paced: show exercise due date | [ ] | [ ] | [x] | [x] | | T10 | Students: show lesson/exercise title | [ ] | [ ] | [x] | [x] | | T11 | Students: show lesson/exercise type icon | [ ] | [ ] | [x] | [x] | | T12 | Students: show lock status (read-only) | [ ] | [ ] | [x] | [x] | | T13 | Students: show lesson materials count | [ ] | [ ] | [x] | [x] | | T14 | Students: show lesson completion state | [ ] | [ ] | [x] | [x] | | T15 | Students: show next-step action | [ ] | [ ] | [x] | [x] | | T16 | Students live class: show schedule time | [ ] | [ ] | [x] | [x] | | T17 | Students live class: show join button | [ ] | [ ] | [x] | [x] | | T18 | Students live class: show lesson materials | [ ] | [ ] | [x] | [x] | | T19 | Students self-paced: show exercise due date | [ ] | [ ] | [x] | [x] | ## Ticket Breakdown (Backend/UI Split) | Parent Ticket | Backend Ticket | UI Ticket | | --- | --- | --- | | T1 | T1-BE: ensure list payload includes title (existing) | T1-UI: render title in list row | | T2 | T2-BE: ensure item type present (existing) | T2-UI: show lesson/exercise icon | | T3 | T3-BE: none | T3-UI: render actions per role | | T4 | T4-BE: ensure `isUnlocked` for lessons/exercises (existing) | T4-UI: render lock status (teacher toggles) | | T5 | T5-BE: add documents/videos counts to list payload | T5-UI: render lesson resources count | | T6 | T6-BE: add exercise question count to list payload | T6-UI: render question count chip | | T7 | T7-BE: add `lessonAt` to list payload | T7-UI: render schedule date/time | | T8 | T8-BE: add `callUrl` to list payload | T8-UI: render join/host CTA | | T9 | T9-BE: add `dueBy` to list payload | T9-UI: render exercise due date chip | | T10 | T10-BE: ensure list payload includes title (existing) | T10-UI: render title in list row | | T11 | T11-BE: ensure item type present (existing) | T11-UI: show lesson/exercise icon | | T12 | T12-BE: ensure `isUnlocked` for lessons/exercises (existing) | T12-UI: render lock icon (read-only) | | T13 | T13-BE: add documents/videos counts to list payload | T13-UI: render lesson materials count | | T14 | T14-BE: ensure `isComplete` for lessons (existing) | T14-UI: render completion badge | | T15 | T15-BE: none | T15-UI: render next-step CTA | | T16 | T16-BE: add `lessonAt` to list payload | T16-UI: render schedule date/time | | T17 | T17-BE: add `callUrl` to list payload | T17-UI: render join CTA | | T18 | T18-BE: add documents/videos counts to list payload | T18-UI: render lesson materials count | | T19 | T19-BE: add `dueBy` to list payload | T19-UI: render exercise due date chip |