feat(lessons): thin GET /api/Lessons/journey aggregation for My Journey #334

Closed
opened 2026-07-02 05:40:01 +00:00 by spikerj · 3 comments
Owner

Optional backend support for the #330 My Journey visualization. Nice-to-have: lets the frontend do one round trip instead of stitching curriculum order + /progress client-side, and keeps the #329 completion-ratio horizon server-authoritative.

Scope

  • GET /api/Lessons/journey?language=<c|cpp|csharp|python|javascript> — returns, per language, the ordered lesson list with: lesson number, title, prerequisites, completed flag + completion timestamp, and (when #329 lands) the horizon lock boundary.
  • Anonymous-friendly (like /api/Lessons/reading): anonymous callers get the free/earned slice + horizon; authenticated callers get full progress.
  • MediatR query + handler under Domain/Lessons/Queries/GetJourney/. No new collection — composes existing curriculum + UserLessonProgress.
  • Unit tests: ordering, prereq resolution, completed mapping, anonymous vs authed slicing.

Out of scope: streaks, any schema change. If we decide to stitch client-side instead (see #330 decision 2), this ticket is dropped.

Depends on: #330 (spike). Integrates with #329 for the horizon boundary.

Optional backend support for the #330 My Journey visualization. Nice-to-have: lets the frontend do one round trip instead of stitching curriculum order + `/progress` client-side, and keeps the #329 completion-ratio horizon server-authoritative. **Scope** - `GET /api/Lessons/journey?language=<c|cpp|csharp|python|javascript>` — returns, per language, the ordered lesson list with: lesson number, title, prerequisites, completed flag + completion timestamp, and (when #329 lands) the horizon lock boundary. - Anonymous-friendly (like `/api/Lessons/reading`): anonymous callers get the free/earned slice + horizon; authenticated callers get full progress. - MediatR query + handler under `Domain/Lessons/Queries/GetJourney/`. No new collection — composes existing curriculum + `UserLessonProgress`. - Unit tests: ordering, prereq resolution, completed mapping, anonymous vs authed slicing. **Out of scope:** streaks, any schema change. If we decide to stitch client-side instead (see #330 decision 2), this ticket is dropped. **Depends on:** #330 (spike). Integrates with #329 for the horizon boundary.
Author
Owner

Scope expansion per #330 decision: this endpoint also returns streak data (current + longest streak, computed from UserLessonProgress completion timestamps — no schema change, lazy compute on read). Frontend (#333) renders the streak flame + milestone feedback in v1.

Scope expansion per #330 decision: this endpoint also returns **streak data** (current + longest streak, computed from `UserLessonProgress` completion timestamps — no schema change, lazy compute on read). Frontend (#333) renders the streak flame + milestone feedback in v1.
Author
Owner

Done in spikersoft-backend#55 (merged to master). GET /api/Lessons/journey ships with per-language trail composition + platform-wide daily streaks + reserved horizon slot. 21 tests green. Closing.

Done in spikersoft-backend#55 (merged to master). `GET /api/Lessons/journey` ships with per-language trail composition + platform-wide daily streaks + reserved horizon slot. 21 tests green. Closing.
Author
Owner

Done — merged to master. GET /api/Lessons/journey aggregation (ordered lessons + prereqs + completion + horizon boundary, anonymous-friendly) plus daily streaks landed in PR #55 (4dfb444). Closing.

Done — merged to `master`. `GET /api/Lessons/journey` aggregation (ordered lessons + prereqs + completion + horizon boundary, anonymous-friendly) plus daily streaks landed in PR #55 (`4dfb444`). Closing.
Sign in to join this conversation.