Implements the frontend of the #329 design (spike doc on that issue; epic #323). Depends on #331.
Anonymous session bootstrap in language-runner: obtain/store anonId (localStorage, beside sandbox state); lesson mode no longer hard-redirects anonymous users to login — within-horizon lessons play through the anon attempt/submit endpoints
Route anon completions through the progress-sync outbox pattern pointed at the anon endpoints (offline-queue behavior preserved)
Sidebar lock semantics: ratio-locked (beyond horizon) gets a distinct icon + tooltip ("Complete N more to reveal — or sign in and see everything"), separate from the existing prerequisite lock; all titles remain listed
Horizon-advance celebration snackbar; quiet persistent sign-in line in the sidebar footer — no modals, no nags
Sign-in claim flow: call POST /api/Lessons/progress/claim after first authenticated load when an anonId exists; celebrate the response ("N lessons claimed, badge earned"); clear the anonId
Funnel events via activity-tracking: anon-session-created, anon-lesson-completed, unlock-milestone, signup-with-claim
E2E: extend the anonymous walk — anonymous visitor completes a free lesson, sees the horizon advance (ties into epic #307's P3/P4 fixtures)
Guardrails from the design: sandbox mode untouched; books/text/videos stay free; the server's horizon is authoritative — the client renders it, never computes it.
Implements the frontend of the #329 design (spike doc on that issue; epic #323). Depends on #331.
- [ ] Anonymous session bootstrap in `language-runner`: obtain/store `anonId` (localStorage, beside sandbox state); lesson mode no longer hard-redirects anonymous users to login — within-horizon lessons play through the anon attempt/submit endpoints
- [ ] Route anon completions through the `progress-sync` outbox pattern pointed at the anon endpoints (offline-queue behavior preserved)
- [ ] Sidebar lock semantics: ratio-locked (beyond horizon) gets a distinct icon + tooltip ("Complete N more to reveal — or sign in and see everything"), separate from the existing prerequisite lock; all titles remain listed
- [ ] Horizon-advance celebration snackbar; quiet persistent sign-in line in the sidebar footer — no modals, no nags
- [ ] Sign-in claim flow: call `POST /api/Lessons/progress/claim` after first authenticated load when an anonId exists; celebrate the response ("N lessons claimed, badge earned"); clear the anonId
- [ ] Funnel events via activity-tracking: `anon-session-created`, `anon-lesson-completed`, `unlock-milestone`, `signup-with-claim`
- [ ] E2E: extend the anonymous walk — anonymous visitor completes a free lesson, sees the horizon advance (ties into epic #307's P3/P4 fixtures)
Guardrails from the design: sandbox mode untouched; books/text/videos stay free; the server's horizon is authoritative — the client renders it, never computes it.
Splitting this into two reviewable PRs since it spans critical shared lesson code.
Part 1 (up now): spikersoft-angular#99 — the self-contained, fully-tested foundation:
new @spikersoft/platform-anon-session lib (AnonSessionService owns the PII-free localStorage handle + lazy mint; AnonLessonService typed client for horizon/submit/claim via X-Anon-Session)
sign-in claim-on-auth in AppComponent (migrate ledger → celebrate snackbar → clear handle → signup-with-claim; retries on failure)
sidebar ratio-lock (distinct spark marker + "complete more or sign in" tooltip, horizonLessonNumber input; null = unchanged for authed users) + en/es i18n
Part 2 (next): the keystone — remove the lesson-mode hard-redirect in the shared LanguageRunner, route within-horizon anonymous play through attempt/anonymous + submit/anonymous across the five runtime adapters, add the anonymous progress outbox, light up the reserved My Journey horizon slot for anonymous viewers, and extend the Playwright anonymous walk. Kept separate because it touches the shared runner base + every adapter and deserves its own focused review.
Leaving this open until part 2 lands.
Splitting this into two reviewable PRs since it spans critical shared lesson code.
**Part 1 (up now): spikersoft-angular#99** — the self-contained, fully-tested foundation:
- new `@spikersoft/platform-anon-session` lib (`AnonSessionService` owns the PII-free `localStorage` handle + lazy mint; `AnonLessonService` typed client for horizon/submit/claim via `X-Anon-Session`)
- sign-in **claim-on-auth** in `AppComponent` (migrate ledger → celebrate snackbar → clear handle → `signup-with-claim`; retries on failure)
- sidebar **ratio-lock** (distinct spark marker + "complete more or sign in" tooltip, `horizonLessonNumber` input; null = unchanged for authed users) + en/es i18n
- funnel events `anon-session-created`, `signup-with-claim`
- 11 new tests; `nx build spikersoft` green
**Part 2 (next):** the keystone — remove the lesson-mode hard-redirect in the shared `LanguageRunner`, route within-horizon anonymous play through `attempt/anonymous` + `submit/anonymous` across the five runtime adapters, add the anonymous progress outbox, light up the reserved My Journey horizon slot for anonymous viewers, and extend the Playwright anonymous walk. Kept separate because it touches the shared runner base + every adapter and deserves its own focused review.
Leaving this open until part 2 lands.
Done — merged to master in two parts: pt1 (anon-session foundation, sign-in claim, sidebar ratio-lock) in PR #99, and pt2 (anonymous ratio-unlock lesson play across all tracks: anon-lesson interceptor, progress-sync anon routing, runner anon mode + horizon gating, My Journey horizon overlay, funnel events, E2E) in PR #100. Closing.
Done — merged to `master` in two parts: pt1 (anon-session foundation, sign-in claim, sidebar ratio-lock) in PR #99, and pt2 (anonymous ratio-unlock lesson play across all tracks: anon-lesson interceptor, progress-sync anon routing, runner anon mode + horizon gating, My Journey horizon overlay, funnel events, E2E) in PR #100. Closing.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Implements the frontend of the #329 design (spike doc on that issue; epic #323). Depends on #331.
language-runner: obtain/storeanonId(localStorage, beside sandbox state); lesson mode no longer hard-redirects anonymous users to login — within-horizon lessons play through the anon attempt/submit endpointsprogress-syncoutbox pattern pointed at the anon endpoints (offline-queue behavior preserved)POST /api/Lessons/progress/claimafter first authenticated load when an anonId exists; celebrate the response ("N lessons claimed, badge earned"); clear the anonIdanon-session-created,anon-lesson-completed,unlock-milestone,signup-with-claimGuardrails from the design: sandbox mode untouched; books/text/videos stay free; the server's horizon is authoritative — the client renders it, never computes it.
Splitting this into two reviewable PRs since it spans critical shared lesson code.
Part 1 (up now): spikersoft-angular#99 — the self-contained, fully-tested foundation:
@spikersoft/platform-anon-sessionlib (AnonSessionServiceowns the PII-freelocalStoragehandle + lazy mint;AnonLessonServicetyped client for horizon/submit/claim viaX-Anon-Session)AppComponent(migrate ledger → celebrate snackbar → clear handle →signup-with-claim; retries on failure)horizonLessonNumberinput; null = unchanged for authed users) + en/es i18nanon-session-created,signup-with-claimnx build spikersoftgreenPart 2 (next): the keystone — remove the lesson-mode hard-redirect in the shared
LanguageRunner, route within-horizon anonymous play throughattempt/anonymous+submit/anonymousacross the five runtime adapters, add the anonymous progress outbox, light up the reserved My Journey horizon slot for anonymous viewers, and extend the Playwright anonymous walk. Kept separate because it touches the shared runner base + every adapter and deserves its own focused review.Leaving this open until part 2 lands.
Done — merged to
masterin two parts: pt1 (anon-session foundation, sign-in claim, sidebar ratio-lock) in PR #99, and pt2 (anonymous ratio-unlock lesson play across all tracks: anon-lesson interceptor, progress-sync anon routing, runner anon mode + horizon gating, My Journey horizon overlay, funnel events, E2E) in PR #100. Closing.