Code map — dashboard shell
Shared
| Path | Responsibility |
|---|---|
libs/shared/src/lib/i18n/dictionaries/{en,he,ru}.json | nav.* (reused), dashboardShell.* (sections, switcher, home, Schedule title/subtitle/WOD chip/stats.wodsPosted*, Coaching list/new-plan dialog/stats.plans*/workoutsThisWeekCount, Ways to train’s two switches and its waysToTrain.blocked.* “still in use” dialog), programs.stats.* (reused by both screens’ strips — enrolled, workoutsThisWeek, completionRate, sessionsThisWeek, bookingsThisWeek, membersThisWeek, fillRate; the strips use short stats.* subtitles instead of the tooltips), announcements.title (reused for the Thrive entry), schedule.setupTimetable.classTypes* (the Schedule screen’s Class types menu item) |
API
| Path | Responsibility |
|---|---|
apps/api/src/programs/programs.service.ts | coachingStats(orgId, programId, weekStart) (private, extracted from findByIdWithStats’s coaching branch — no behavior change) and coachingSummary(orgId, clerkId, weekStart?), which fans it out over every active coaching program and aggregates totals; getDeactivationBlockers(orgId, programId) (counts future published sessions / active enrollments by delivery mode) and checkDeactivationBlockers(orgId, programId, clerkId) (membership + owner/admin gate, then delegates), both consumed by remove() and the isActive: true → false path of update() to refuse deactivation with a 409 while either count is nonzero |
apps/api/src/programs/programs.controller.ts | GET :orgId/programs/coaching-summary, registered in the literal sub-routes block before :id; GET :orgId/programs/:id/deactivation-blockers, returning { data: { futurePublishedSessions, activeEnrollments } } |
Config
| Path | Responsibility |
|---|---|
apps/web/src/config/dashboard-sections.ts | SectionId, ROUTE_PLACEMENT for optional Home cards and exhaustive route coverage, SECTION_DEFAULT_ROUTE, sectionsForRole, sectionForPath |
Hooks
| Path | Responsibility |
|---|---|
apps/web/src/hooks/dashboard-shell/use-section-nav-items.tsx | Builds optional Home-card item lists — icons, hrefs, badges, and feature gates |
apps/web/src/hooks/dashboard-shell/use-section-navigation.ts | Resolves Home-card sections and their destinations; records Home preferences and computes Train’s live default |
apps/web/src/lib/dashboard-shell/home-prefs.ts | localStorage read/write for optional Home preferences, keyed by user+org |
apps/web/src/hooks/use-programming-week-actions.ts | The Spotter handler for WeeklyCalendar’s condensed-view toolbar — see daily-programming/code-map.md. Copy-week/publish-week mutations were removed along with their only caller, the standalone board |
Components
| Path | Responsibility |
|---|---|
apps/web/src/components/dashboard-shell/section-greeting.tsx | SectionGreeting({eyebrow, action?}) — the Overview greeting under a section-name eyebrow, reused by Schedule and Coaching. Overview keeps its own copy |
apps/web/src/components/programs/stats-strip.tsx | StatsStrip({tiles, isLoading}) — a row of ProgramStatCard tiles, column count tracking tile count, each with a soft stagger-in animation |
apps/web/src/components/programs/program-stat-card.tsx | ProgramStatCard — one KPI tile (icon, value/skeleton, label, info tooltip). Moved out of the program detail page; imported back there unchanged |
apps/web/src/components/programs/program-with-stats.ts | ProgramWithStats type (the GET .../programs/:id?weekStart= payload shape) — shared by the detail page and ScheduleScreen |
Routes
| Path | Responsibility |
|---|---|
apps/web/src/app/[lang]/(protected)/dashboard/layout.tsx | Always renders DashboardSidebar and the original dashboard header |
apps/web/src/app/[lang]/(protected)/dashboard/home/page.tsx | Optional direct Home landing — greeting, role-aware work-area cards, “remember my choice”, and “continue where I left off”; never an entry redirect |
apps/web/src/app/[lang]/(protected)/dashboard/schedule/page.tsx | Renders schedule-screen.tsx |
apps/web/src/app/[lang]/(protected)/dashboard/schedule/schedule-screen.tsx | The Schedule destination: SectionGreeting, a StatsStrip for the viewed week (Sessions/Bookings/Members/Fill rate/WODs posted), then WeeklyCalendar for the org’s one active schedule program (enableClassStudioExtras). Redirects to Workouts when the org runs no schedule program |
apps/web/src/app/[lang]/(protected)/dashboard/coaching/page.tsx | The Coaching destination: SectionGreeting with the “New coaching plan” action, a StatsStrip from .../programs/coaching-summary, then a list of the org’s active coaching plans (name, active state, per-plan enrolled/workouts/completion line) — each row sourced from the same summary payload, no per-row fetch. Opening a plan navigates to /dashboard/programs/:id. None: redirects to Workouts. |
apps/web/src/app/[lang]/(protected)/dashboard/programs/page.tsx | No list: forwards to Settings > General’s Ways to train section (#settings-ways-to-train). |
apps/web/src/components/settings/ways-to-train-settings.tsx | Owner/admin-only training-mode configuration in Settings > General: Schedule and Cohorts switches create/reactivate/deactivate their underlying program(s) through the existing programs API. Turning a switch off first fetches deactivation blockers for the affected program(s) (fetchBlockers); zero counts show the existing confirm dialog, a nonzero count opens the blocking “still in use” dialog instead (and the same dialog reopens from a racing 409 on the DELETE itself). |
apps/web/src/app/[lang]/(protected)/dashboard/programs/[id]/page.tsx | Renders every tab for both delivery modes. Its delete button shows a deleteBlocked toast on a 409 program_in_use (upcoming published sessions or active enrollments), the generic failure toast otherwise; a successful delete lands on Coaching |
apps/web/src/app/[lang]/(protected)/dashboard/audit-log/page.tsx | New standalone route for the top bar’s Audit log link — renders the existing AuditLogContent, gated by useCan('audit', 'view') |
apps/web/src/app/[lang]/(protected)/dashboard/messages/page.tsx | Reads ?tab=announcements once at mount for deep links (announcements is a tab of Messages under Train, not a sidebar entry) |
Flat navigation
| Path | Responsibility |
|---|---|
apps/web/src/components/overview/sidebar-nav.tsx (DashboardSidebar) | The permanent flat sidebar: all permitted navigation items remain concurrently visible. Training shows enabled Schedule/Cohorts plus Workouts/Movements. Courses and Programs are hidden. |
apps/web/src/app/[lang]/(protected)/dashboard/settings/(shell)/admin/page.tsx | Audit log route inside Settings |
apps/web/src/app/[lang]/(protected)/dashboard/programs/[id]/page.tsx | See Routes above |
Test infra
| Path | Responsibility |
|---|---|
apps/web/vitest.setup.ts, apps/web/src/testing/global-mock-state.tsx | useFeatureFlag/useGatedFeature mocks now forward the flag key to mockFeatureFlag, so a spec can discriminate flags with mockFeatureFlag.mockImplementation((flag) => flag === FeatureFlags.X). Backward compatible with existing mockReturnValue(...) usage |
Existing coverage
apps/web/src/config/dashboard-sections.unit.spec.ts— placement map vs. the actual route folders on diskapps/web/src/lib/dashboard-shell/home-prefs.unit.spec.ts— optional Home preferencesapps/web/src/components/overview/sidebar-nav.int.spec.tsx— flat sidebar navigation contractapps/web/src/app/[lang]/(protected)/dashboard/schedule/schedule-screen.int.spec.tsx— single-schedule-program resolution and empty-state redirect, the section greeting, the week stats strip (sourced from the detail-stats endpoint), and the WODs-posted tileapps/web/src/components/overview/schedule/weekly-calendar.int.spec.tsx— includes the folded-in WOD chip, board toolbar actions, and Class types menu item, all gated onenableClassStudioExtras(see daily-programming/code-map.md)apps/web/src/app/[lang]/(protected)/dashboard/coaching/coaching-page.int.spec.tsx— the plan list, enrolled count, “New coaching plan”, the section greeting’s action button, the stats-strip totals and per-row stats sourced fromcoaching-summaryapps/api/src/programs/programs.service.unit.spec.ts—ProgramsService.coachingSummary: totals aggregation, enrolled-weighted completion mean excluding programs with no assignments that week, zero-plan org, membership enforcement;getDeactivationBlockers/remove/update— per-mode blocker counts,409 program_in_usewith the counts when either is nonzero, deactivation proceeding at zeroapps/web/src/components/settings/ways-to-train-settings.int.spec.tsx— the two Settings > General switches: create/reactivate/deactivate for each, confirm dialogs, the blocked “still in use” dialog for a nonzero session/enrollment count (per switch, never callingDELETE), the same dialog from a racing409, the coach omissionapps/web/src/app/[lang]/(protected)/dashboard/home/home-page.int.spec.tsx— includes the “Ways to train” secondary linkapps/web/src/app/[lang]/(protected)/dashboard/layout.int.spec.tsx- These are coverage locations, not claims that this documentation pass ran validation.