# Migrate HeroWars static JSON imports to HttpClient assets

- Status: accepted
- Date: 2026-04-26

## Context and Problem Statement

Six large JSON files (36 KB–3 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.
