feat(herowars): migrate JSON static imports to HttpClient assets

Replace all TypeScript JSON imports with an HWDataService that loads
6 data files from /assets/files-data/ via HttpClient with shareReplay(1).
Update all 9 consumer components to subscribe asynchronously. Remove
unused qcm-bpa.json import and dead methods from QcmComponent.
Add ADR 0013 documenting the decision.
This commit is contained in:
2026-04-26 23:46:35 +02:00
parent 86c075db10
commit fa00719a3e
23 changed files with 89071 additions and 551 deletions
@@ -0,0 +1,67 @@
# Migrate HeroWars static JSON imports to HttpClient assets
- Status: accepted
- Date: 2026-04-26
## Context and Problem Statement
Six large JSON files (36 KB3 MB) were statically imported directly into Angular components and services via TypeScript `import` statements. This bundled all the data into the main JavaScript bundle, inflating the initial download regardless of whether the user navigated to the HeroWars section. The largest file (`hw-guild-raids.json`, 3 MB) alone would significantly delay first contentful paint for all users.
Additionally, a seventh file (`qcm-bpa.json`, 210 KB) was imported but never consumed — the component had switched to a route resolver but the dead import remained.
## Decision Drivers
- Static JSON imports are compiled into the bundle — they cannot be lazy-loaded or cached by the browser independently.
- Updating the data files required a recompile and redeployment; serving them as assets allows hot-swapping without a rebuild.
- The HeroWars section is used by a small subset of users; its data should not penalise all other users' load time.
## Considered Options
- Keep static imports
- Move JSON to assets and load via `HttpClient`
- Fetch data from the API backend
## Decision Outcome
Chosen option: "Move JSON to assets and load via HttpClient", because it removes the data from the bundle, enables browser-level HTTP caching, and requires no backend changes. The files are not secret (guild-internal analytics data) so serving them as static assets is appropriate.
Structure:
- JSON files moved from `src/files-data/` to `src/assets/files-data/`
- `HWDataService` created at `src/app/core/services/herowars/hw-data.service.ts` — exposes one `readonly` observable per file, each piped through `shareReplay(1)` so the HTTP request fires at most once per app lifecycle
- `HWClanService.loadClan()` and `HWMemberService.loadMembers()` converted from synchronous return values to `Observable<T>`
- All consumer components inject `HWDataService` and subscribe in `ngOnInit()`; template-called methods that previously accessed `guildWarSlots.slots` inline now read from a `_slots` class property populated in the subscribe callback
- Unused `import data from 'src/qcm-bpa.json'` and two dead import-helper methods removed from `qcm.component.ts`
### Positive Consequences
- HeroWars JSON (~4 MB total) no longer shipped in the initial bundle.
- Each JSON file is independently cacheable by the browser with standard HTTP cache headers.
- Data files can be updated without recompiling the Angular application.
- `shareReplay(1)` ensures a single HTTP request per session even when multiple components subscribe to the same observable.
### Negative Consequences
- Components now initialize asynchronously — there is a brief render before data arrives (consistent with the rest of the app's HTTP-driven components).
- `Object.entries()` on `any`-typed HTTP responses requires explicit `Record<string, T>` casts to satisfy strict TypeScript, adding minor verbosity.
## Pros and Cons of the Options
### Keep static imports
- Good, because synchronous — no async lifecycle complexity.
- Bad, because adds up to 4 MB to the initial bundle.
- Bad, because data updates require a full rebuild and redeployment.
### Move JSON to assets and load via HttpClient
- Good, because removes data from the bundle entirely.
- Good, because browser-cacheable independently of the app JS.
- Good, because hot-swappable without a recompile.
- Bad, because converts synchronous service methods to observables, requiring component updates.
### Fetch from API backend
- Good, because data could be managed dynamically via the admin interface.
- Bad, because requires significant backend work (new endpoints, data model) for data that is currently managed as flat files.
- Bad, because adds latency and a failure mode not present with local assets.