---
path: /domains/tara/courses/[id]
surface: customer
domain: tara
auth: signed-in
source: apps/oshun/web/src/app/domains/tara/courses/[id]/page.tsx
status: walked
last_walked:
  '2026-05-29 automated runtime walk (Playwright headless) — render, /v1 data
  (2xx), console/page-errors, expected content, screenshot verified; live
  screen-reader, touch, offline, and telemetry-delivery checks pending a manual
  AT pass. Evidence: WALKTHROUGH/results/runtime-sweep-2026-05-29.md; 2026-06-29
  targeted Playwright course-detail coverage added for shipped route anatomy,
  enrollment transition, section accordion, lesson overlays, quiz pass/fail
  scoring, missing-course fallback, and scoped axe scan. Evidence:
  apps/oshun/web/e2e/tara-course-detail.spec.ts'
---

# Tara — course detail

## Purpose

Dynamic course-detail surface in the `/domains/tara/*` namespace. Renders one
Tara meditation course identified by the URL segment, with sections, lessons,
enrollment flow, learning objectives, quiz interface, completion certificate,
and per-lesson resources.

## Entry points

- **Course list / collections / search** — surfaces under `/domains/tara/*` link
  here with the course id
- **Direct URL / bookmark** — yes; `params.id` flows directly into
  `TaraCourseDetailPage`
- **Domain back-stack** — `router.back()` wired into `onBack`

## Layout regions

`page.tsx` is a `'use client'` thin wrapper that reads `params.id` via
`useParams<{ id: string }>()` and renders
`<TaraCourseDetailPage courseId={courseId} onBack={() => router.back()} />`.

Inside `TaraCourseDetailPage` (`TaraCourseDetail.tsx`):

- **Header / back affordance** — back button, course title
- **Format badge** — `FORMAT_COLORS[course.format]` (daily / weekly / self-
  paced / scheduled / live) with the appropriate icon
- **Course meta** — duration, lesson count, enrollment count, completion rate,
  average rating, difficulty
- **Hero CTA** — Enrollment / Continue / Completed CTA reflects
  `EnrollmentStatus` (not-enrolled → enrolled → in-progress → completed)
- **Learning objectives** — list of stated objectives
- **Section accordion** — one accordion per `TaraCourseSection` with progress
  bar; expands to show `TaraCourseLesson` rows
- **Lesson row** — icon by `LESSON_TYPE_ICONS[lesson.type]` (meditation / video
  / article / exercise / quiz / reflection / discussion), status by
  `STATUS_COLORS[lesson.status]` (locked / available / in-progress / completed)
- **Lesson resources panel** — supporting materials for the active lesson
- **Reflection prompts** — reflection cards
- **Quiz interface** — multiple-choice / true-false with submit and review;
  scores produce a quiz-results card
- **Completion certificate** — full-page certificate when the course is complete
  (`Trophy` icon)

## States

- [x] **Course found** — `SIMULATED_COURSES.find(...)` returns a record; hero +
      sections render
- [x] **Course missing (unknown id)** — friendly inline empty state renders with
      `Course not found` and the domain back affordance
- [x] **Enrollment status: not-enrolled** — enrollment CTA visible
- [x] **Enrollment status: enrolled** — local click transition enters `enrolled`
      before auto-advancing
- [x] **Enrollment status: in-progress** — "Continue where you left off" CTA
      with progress percent
- [ ] **Enrollment status: completed** — certificate screen + share/download
      affordance is not route-reachable with current course fixtures
- [x] **Lesson status branches** — locked (no entry) / available (Play) /
      in-progress (Continue) / completed (`CheckCircle2`)
- [x] **Quiz answered correctly / incorrectly** — result card copy and score
      attributes verified for 0% fail and 100% pass
- [x] **Course rating display** — shows `Star` rating + average score
- [x] **Reduced motion** — `./fixtures` emulates reduced motion and the scoped
      course-detail accessibility test runs against the settled route root

## Interactions

### Header

- [ ] **Back** (button) — calls `router.back()` via `onBack`; direct header
      click still needs a browser assertion

### Course hero

- [x] **Enroll** (button, `not-enrolled` state) — flips state to `enrolled`,
      then local `in-progress`
- [x] **Continue / Start lesson** (button) — opens the next available lesson
- [ ] **Download certificate** / **Share** (`Download`, `Share2` icon buttons) —
      visible only after completion; completion fixture absent today
- [ ] **Resume CTA** — uses local fixture progress today; persisted progress
      contract still needs BFF coverage

### Section accordion

- [x] **Section header row** (button) — toggles open/closed; chevron rotates
- [x] **Per-section progress bar** — non-interactive progress attributes
      verified

### Lesson row

- [x] **Lesson click**
  - When `status === 'locked'`: `aria-disabled="true"` and does not open an
    overlay
  - When `status === 'available' | 'in-progress'`: opens the lesson resources
    panel
  - When `status === 'completed'`: opens the completed quiz for review/retry

### Quiz

- [x] **Multiple-choice options** — radio-style selection
- [x] **True/false options** — two-option selection
- [x] **Submit** (button) — scores and reveals results
- [x] **Retry** — no explicit retry button; re-opening a completed quiz starts a
      fresh attempt and is browser-covered

### Resources / reflection prompts

- [x] **Resource link** — current resource/download/share controls are
      display-only disabled buttons until real downloads/shares are wired
- [ ] **Reflection prompt** — no available reflection lesson exists in current
      fixtures; all reflection rows are locked

## Data & contracts

- **Reads**:
  - `SIMULATED_COURSES` from `@/lib/tara/tara-simulation-data`
  - Content types from `@/lib/tara/content-types`: `TaraCourse`,
    `TaraCourseSection`, `TaraCourseLesson`, `LessonType`, `LessonStatus`,
    `CourseFormat`, `EnrollmentStatus`
- **Writes**: enrollment + progress state are local to this component today
- **Realtime**: _None._
- **Caching**: client-only
- **Auth/role check**: shell middleware
- **Route param**: `params.id: string` — no decode in the page wrapper

## Current E2E evidence

- `apps/oshun/web/e2e/tara-course-detail.spec.ts` opens
  `/domains/tara/courses/tara-course-001`, verifies the in-progress course
  anatomy, stats, objectives, teacher card, section progress, lesson statuses,
  disabled resource actions, section toggling, failed quiz scoring, passed quiz
  scoring, and unknown-course fallback.
- The same spec opens `/domains/tara/courses/tara-course-003`, verifies the
  not-enrolled state, clicks enroll, observes the local `enrolled` →
  `in-progress` transition, and opens the first available lesson.
- The scoped accessibility test runs axe against
  `[data-tara-course-detail="tara-course-001"]` under reduced motion.
- `apps/oshun/web/e2e/tara-teacher-pages.spec.ts` covers a real teacher-profile
  course link into `tara-course-001` and browser back to the profile.

## Cross-references

- Sibling Tara routes:
  - [`tara.md`](./tara.md),
    [`domains-tara-analytics.md`](./domains-tara-analytics.md),
    [`domains-tara-collections.md`](./domains-tara-collections.md),
    [`domains-tara-programs.md`](./domains-tara-programs.md),
    [`domains-tara-search.md`](./domains-tara-search.md),
    [`domains-tara-sounds.md`](./domains-tara-sounds.md),
    [`domains-tara-teachers.md`](./domains-tara-teachers.md),
    [`domains-tara-teachers-id.md`](./domains-tara-teachers-id.md)
- Component sources:
  - `apps/oshun/web/src/components/domains/tara/TaraCourseDetail.tsx`
  - `apps/oshun/web/src/lib/tara/tara-simulation-data.ts`
  - `apps/oshun/web/src/lib/tara/content-types.ts`
- Feature spec: [`V1/features.md#tara`](../../../V1/features.md#tara)

## Open questions / known gaps

- [ ] Confirm the BFF endpoint that hydrates real course content; currently
      `SIMULATED_COURSES` is local fixture data
- [ ] Document the persistence target for enrollment status and lesson progress
      (client vs. BFF)
- [ ] Verify how the certificate share / download interacts with the user's
      Library — should completed courses surface there automatically? Current
      fixtures do not expose a completed course state.
- [ ] Confirm whether the friendly inline missing-course state is the intended
      product behavior or whether this route should use a Next not-found page.
- [ ] Add a fixture or harness for an available reflection lesson if the
      reflection journal hand-off should be route-tested before BFF content
      exists.
