# WP6b — Build hardening & MoonStack distribution wiring for `/store/`

**Repo:** FE — `/home/moonui4/public_html/moon-erp`, branch `hazemdev4`. Build config + `projects/storefront/`.
**Review:** code-reviewer · **[FIN]:** no · **Migration:** no
**Depends on:** **WP6a must be ✅ and committed first.** One writer per repo — do not start while WP6a is open.

## Goal

Make the storefront build correct-by-default and self-contained, and wire `/store/` as a real distribution target instead of a hand-copied preview. Today the app is one forgotten CLI flag away from a silently broken deploy, and it fetches its fonts and icons from Google at runtime.

## Verified starting facts (do NOT re-derive; DO report if reality differs)

| Fact | Value |
|---|---|
| `baseHref` in `angular.json` | **NOT pinned** for the storefront project — `--base-href /store/` must be typed manually every build |
| External runtime dependencies | **7 tags** in `projects/storefront/src/index.html` lines 13–25: 2 `preconnect`, Tajawal + Inter from `fonts.googleapis.com`, and 3 Material Icons families (`Material Icons`, `Material Icons Outlined`, `Material Icons Round`) |
| Dynamic Tailwind classes | **0** — verified by grep for `class` containing `${` |
| Current `/store/` deployment | An orchestrator hand-copy: `npx ng build --base-href /store/` → `dist/storefront/browser/*` → `/home/moonui4/public_html/store/`. **`store/.htaccess` and `store/assets/config.json` live ONLY in the deploy target, not in the repo** — exactly like `app/.htaccess`. Anything that clears the target must not delete them. |
| Host constraint | cPanel; `mod_proxy` is **not** available in `.htaccess` |

## The job

### 1. Pin `baseHref` in `angular.json` (the highest-value fix here)
Set the storefront project's production build `baseHref` to `/store/` so a plain `npx ng build` is correct. This has already caused one real silently-blank deploy on this project.

⛔ **The admin app's `moon-erp` block must remain byte-identical.** WP0 established that property and proved it with a diff; preserve it. Also note WP0 found the admin app has the **same missing-`ignore` assets-glob leak** the storefront had — that is a **known deferral, out of scope, do not fix it here.**

### 2. Self-host fonts and icons
Vendor Tajawal, Inter, and the Material Icons families into the app and drop all 7 external tags. Rationale: a storefront that hangs on `fonts.googleapis.com` is a storefront that hangs for the customer, and this is a self-hosted product shipped to installs that may not have open egress.

- Subset sensibly — do **not** ship every weight if the app uses four. Report the byte cost you added.
- ⚠️ **Verify the icon glyphs still render.** The app uses `material-icons-outlined` class names on `<span>` elements; a wrong `font-family` or a missing ligature setting silently renders the *icon name as text* — which looks like a broken translation, not a font bug. Check rendered pages, not just that the file loads.
- Check licensing permits redistribution (both families are OFL/Apache — confirm and state which).

### 3. Production Tailwind audit
0 dynamic classes were found by grep, but grep is not proof. Build for production and verify that classes used only in rarely-rendered branches (empty states, error states, the disabled out-of-stock button, the discount badge, toast variants) actually exist in the emitted CSS. Paste the method you used. **If a class is missing, the fix is to write it as a whole literal — never to add a safelist that papers over the pattern.**

### 4. MoonStack distribution wiring
Wire `/store/` as a first-class distribution target the way `/app/` is, so deploying is a documented repeatable sequence rather than tribal knowledge.

- Document the exact sequence in the repo (mirroring the `/app/` flow in the root `CLAUDE.md`), **including that `store/.htaccess` and `store/assets/config.json` must survive**, and that the `rm` glob must therefore stay limited to top-level `*.js/css/html/ico`.
- The `.htaccess` for `/store/` must provide: SPA fallback under `/store/`, year-long immutable caching for hashed assets, and `no-store` on `index.html`. Verify the deployed one already does this and record it in the repo (a template file is fine — it is not currently version-controlled anywhere, which is itself a risk).
- ⛔ **Do NOT deploy.** Write the wiring; the orchestrator deploys.

## Constraints — absolute

1. ⛔ **Do not push, deploy, `/fullpush`, or merge to `main`.** Commit on `hazemdev4` and stop.
2. ⛔ Admin app (`src/`, and `angular.json`'s `moon-erp` block) untouched — prove it with a diff.
3. `src/assets/config.json` (both apps) is gitignored and per-instance — never commit, never edit.
4. ⛔ Never delete anything under `/home/moonui4/public_html/store/` — the live preview and its two untracked files.
5. Do NOT run `npx playwright install` — bundled browsers are root-owned and unreadable. Use `/usr/bin/chromium-browser`.
6. `/home/moonui`, `/home/moonui2`, `/home/moonui3` are off-limits entirely.

## Acceptance criteria — paste real output, do not assert

- [ ] `npx ng build` **with no flags** produces `<base href="/store/">`. Paste the grep of the built `index.html`.
- [ ] Zero requests to any external host at runtime. Paste a headless-Chromium network log of a page load showing no `fonts.googleapis.com` / `fonts.gstatic.com` request.
- [ ] Icons render as **glyphs, not words** — paste a screenshot or a measured check (an icon `<span>` whose rendered width matches a glyph, not the text "shopping_cart").
- [ ] Both fonts render in Arabic and English; paste the computed `font-family` actually resolved.
- [ ] Tailwind audit: paste the method and the result for the rarely-rendered branches listed above.
- [ ] Byte cost of self-hosting, before/after bundle size.
- [ ] Admin app untouched: `git diff --stat` proves it.
- [ ] Deploy sequence documented; `.htaccess` template in the repo.

## Commit
Conventional commit on `hazemdev4`. This is **internal/tooling** → use `[skip-changelog]` in the commit message and add **no** CHANGELOG bullet. (Self-hosting fonts is arguably user-visible as a speed improvement — if you judge it worth a bullet, add ONE and say why in your report; append only, preserve all 14+ existing bullets and every released section.)

## Report back
Paste actual output for every check. **Flag anything in this brief that turns out to be wrong** — every work package on this project has found a genuine error in its own brief. Be explicit about **VERIFIED** vs **INFERRED**. If self-hosting the icons turns out to require a change to how icons are referenced across many components, **stop and report** rather than doing a sweeping rename — that would be scope this WP did not buy.
