Data fetching for the browse surfaces relies on Angular HttpClient + coarse service-worker HTTP caching. There's no in-app reactive cache, so we don't get request de-duplication, stale-while-revalidate in the app layer, or cache invalidation (e.g. refresh progress after completing a lesson).
As catalog browsing/filtering/pagination becomes a primary flow, this shows up as redundant refetches, manual loading/error boilerplate, and stale progress after mutations.
Current state
provideHttpClient(withInterceptorsFromDi()); lesson data via HttpClient.
Service worker (ngsw-config.json) caches api-lessons-catalog (maxAge 7d) and api-lessons-progress (maxAge 10m) at the HTTP layer only — not reactive, no dedupe, no invalidation.
Endpoints that would benefit: GET /api/Lessons (paginated, filters: language/category/difficulty/searchTerm/skip/take/sort) and GET /api/Lessons/progress.
No query/cache lib present (no TanStack/Apollo/urql/SWR).
Out of scope for caching:GET /api/Lessons/{n}/attempt — each attempt is randomized/unique per request and intentionally uncacheable; it must be explicitly excluded from any cache layer.
Why a spike (not a commit-to-library)
The obvious pick, TanStack Query's Angular adapter (@tanstack/angular-query-experimental), is still experimental as of 2026-07 — its README warns breaking changes can land in minor and patch releases, and there are open maintainer-activity concerns on the stable-release tracker. That conflicts with the "won't break anything" bar, so we should evaluate before adopting.
Spike deliverables
Evaluate and recommend the lowest-risk, locally-controlled option for a reactive catalog/progress cache:
In-house signals + rxjs cache service — shareReplay/signal-backed store, manual invalidation. Zero new deps, fully controlled, Angular-21 signals-native. (Likely default recommendation.)
@ngrx/signals (SignalStore) with entity caching — first-party-adjacent, stable, signals-first.
@tanstack/angular-query-experimental, version-pinned — most features, but experimental; only if the caveats are acceptable and the version is locked.
Produce: a short comparison (bundle cost, stability, testing/SSR story, invalidation ergonomics), a recommendation, and a tiny proof-of-concept on the catalog list + progress refresh-after-completion.
Why the eventual change is non-breaking
Whatever we pick is additive — introduced on the catalog/progress flows only; existing HttpClient usage elsewhere is untouched.
The attempt endpoint stays on the direct path (explicitly not cached).
Acceptance criteria (spike)
Written recommendation with the tradeoff table + chosen option.
POC: catalog list de-dupes/caches queries by filter key; completing a lesson invalidates and refreshes progress without a full reload.
Confirmed compatibility with Angular 21.2 and SSR/hydration; no regression to existing HttpClient flows.
Follow-up implementation ticket(s) opened from the recommendation.
Priority
Medium — pick up when catalog browse/filter/pagination becomes a primary flow. Coordinate with the Angular v22/Nx upgrade epic (#219) since the choice interacts with the framework version.
(Local-hosting only — no CDN.)
## Problem
Data fetching for the browse surfaces relies on Angular `HttpClient` + coarse **service-worker** HTTP caching. There's no in-app reactive cache, so we don't get request de-duplication, stale-while-revalidate in the app layer, or cache invalidation (e.g. refresh progress after completing a lesson).
As catalog browsing/filtering/pagination becomes a primary flow, this shows up as redundant refetches, manual loading/error boilerplate, and stale progress after mutations.
## Current state
- `provideHttpClient(withInterceptorsFromDi())`; lesson data via `HttpClient`.
- Service worker (`ngsw-config.json`) caches `api-lessons-catalog` (maxAge 7d) and `api-lessons-progress` (maxAge 10m) at the HTTP layer only — not reactive, no dedupe, no invalidation.
- Endpoints that would benefit: `GET /api/Lessons` (paginated, filters: language/category/difficulty/searchTerm/skip/take/sort) and `GET /api/Lessons/progress`.
- No query/cache lib present (no TanStack/Apollo/urql/SWR).
- **Out of scope for caching:** `GET /api/Lessons/{n}/attempt` — each attempt is randomized/unique per request and intentionally uncacheable; it must be explicitly excluded from any cache layer.
## Why a spike (not a commit-to-library)
The obvious pick, TanStack Query's Angular adapter (`@tanstack/angular-query-experimental`), is **still experimental as of 2026-07** — its README warns breaking changes can land in **minor and patch** releases, and there are open maintainer-activity concerns on the stable-release tracker. That conflicts with the "won't break anything" bar, so we should evaluate before adopting.
## Spike deliverables
Evaluate and recommend the **lowest-risk, locally-controlled** option for a reactive catalog/progress cache:
1. **In-house signals + rxjs cache service** — `shareReplay`/signal-backed store, manual invalidation. Zero new deps, fully controlled, Angular-21 signals-native. (Likely default recommendation.)
2. **`@ngrx/signals` (SignalStore)** with entity caching — first-party-adjacent, stable, signals-first.
3. **`@tanstack/angular-query-experimental`, version-pinned** — most features, but experimental; only if the caveats are acceptable and the version is locked.
Produce: a short comparison (bundle cost, stability, testing/SSR story, invalidation ergonomics), a recommendation, and a tiny proof-of-concept on the catalog list + progress refresh-after-completion.
## Why the eventual change is non-breaking
- Whatever we pick is **additive** — introduced on the catalog/progress flows only; existing `HttpClient` usage elsewhere is untouched.
- The attempt endpoint stays on the direct path (explicitly not cached).
## Acceptance criteria (spike)
- [ ] Written recommendation with the tradeoff table + chosen option.
- [ ] POC: catalog list de-dupes/caches queries by filter key; completing a lesson invalidates and refreshes progress without a full reload.
- [ ] Confirmed compatibility with Angular 21.2 and SSR/hydration; no regression to existing HttpClient flows.
- [ ] Follow-up implementation ticket(s) opened from the recommendation.
## Priority
Medium — pick up when catalog browse/filter/pagination becomes a primary flow. Coordinate with the Angular v22/Nx upgrade epic (#219) since the choice interacts with the framework version.
_(Local-hosting only — no CDN.)_
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.
Problem
Data fetching for the browse surfaces relies on Angular
HttpClient+ coarse service-worker HTTP caching. There's no in-app reactive cache, so we don't get request de-duplication, stale-while-revalidate in the app layer, or cache invalidation (e.g. refresh progress after completing a lesson).As catalog browsing/filtering/pagination becomes a primary flow, this shows up as redundant refetches, manual loading/error boilerplate, and stale progress after mutations.
Current state
provideHttpClient(withInterceptorsFromDi()); lesson data viaHttpClient.ngsw-config.json) cachesapi-lessons-catalog(maxAge 7d) andapi-lessons-progress(maxAge 10m) at the HTTP layer only — not reactive, no dedupe, no invalidation.GET /api/Lessons(paginated, filters: language/category/difficulty/searchTerm/skip/take/sort) andGET /api/Lessons/progress.GET /api/Lessons/{n}/attempt— each attempt is randomized/unique per request and intentionally uncacheable; it must be explicitly excluded from any cache layer.Why a spike (not a commit-to-library)
The obvious pick, TanStack Query's Angular adapter (
@tanstack/angular-query-experimental), is still experimental as of 2026-07 — its README warns breaking changes can land in minor and patch releases, and there are open maintainer-activity concerns on the stable-release tracker. That conflicts with the "won't break anything" bar, so we should evaluate before adopting.Spike deliverables
Evaluate and recommend the lowest-risk, locally-controlled option for a reactive catalog/progress cache:
shareReplay/signal-backed store, manual invalidation. Zero new deps, fully controlled, Angular-21 signals-native. (Likely default recommendation.)@ngrx/signals(SignalStore) with entity caching — first-party-adjacent, stable, signals-first.@tanstack/angular-query-experimental, version-pinned — most features, but experimental; only if the caveats are acceptable and the version is locked.Produce: a short comparison (bundle cost, stability, testing/SSR story, invalidation ergonomics), a recommendation, and a tiny proof-of-concept on the catalog list + progress refresh-after-completion.
Why the eventual change is non-breaking
HttpClientusage elsewhere is untouched.Acceptance criteria (spike)
Priority
Medium — pick up when catalog browse/filter/pagination becomes a primary flow. Coordinate with the Angular v22/Nx upgrade epic (#219) since the choice interacts with the framework version.
(Local-hosting only — no CDN.)