# Solution Design

## Goals

- Enable npm-based third-party JavaScript libraries (e.g., Syncfusion) in BuyerKiosk.
- Keep all existing legacy scripts working unchanged (hybrid loading).
- Provide a clean path for new features to ship as bundled ES modules.
- Avoid FOUC by ensuring Vite-produced CSS loads in `<head>`.
- Support local development with optional HMR (dev-server mode).

## Non-Goals

- Migrating legacy scripts into the bundler in this phase.
- Replacing the existing CSS pipeline (`conductor`) in this phase.
- Requiring Node.js/npm on production servers (build artifacts are committed).

---

## Directories

- **Module source directory:** `resources/js/` (not web-accessible).
- **Production output directory:** `public_html/js/dist/` (committed artifacts).

---

## Deployment Model: Committed Artifacts

### Rationale
Because there is no concrete CI build pipeline today, the simplest reliable approach is to commit build outputs:

- Production deploys do not need Node.js/npm.
- Rollbacks are deterministic (assets roll back with code).
- Fewer moving parts during deploy.

### Rules

- `package.json` and `package-lock.json` are committed.
- `public_html/js/dist/` build artifacts are committed.
- `node_modules/` is never committed (gitignored).
- Vite caches (e.g., `.vite/`) are never committed (gitignored).
- Builds must remove stale files from `public_html/js/dist/` before writing new output (prevents orphaned bundles referenced nowhere but lingering in git/deploys).

### Failure Modes + Mitigations

- “Forgot to rebuild”: mitigation is a deploy-time or pre-merge check that `manifest.json` exists and referenced files exist.
- Repo growth over time: mitigate by keeping the number of entry points small and periodically pruning obsolete dist files.

---

## Asset Injection Strategy (Avoid FOUC)

### Conventions

- **CSS:** Include Vite-generated CSS in `<head>` to prevent FOUC.
- **JS:** Include Vite entry scripts near the end of `<body>` (workspace footer pattern) to preserve expected ordering with legacy scripts and avoid surprising early execution.

### Twig Helper Surface

Use two helpers to match the HTML loading norms:

- `vite_styles(entry)` for `<head>` (emits `<link rel="stylesheet" ...>` tags)
- `vite_scripts(entry)` for end-of-body (emits `<script type="module" ...>` tags)

If a single helper is preferred later, it should support a “collect then flush” pattern so CSS can still be emitted in `<head>`.

---

## Dev Server Mode (HMR)

### What HMR Is
HMR (Hot Module Replacement) updates JS/CSS in an open browser during development without a full page reload.

### Scope

- Dev server mode is for **local development only** (never used in production).
- HMR is required for the standard “same-machine browser” dev flow.
- If using ngrok at `dev2.buyerkiosk.com`, HMR support is best-effort and may require Vite server/HMR host/origin configuration.
- If the app pages enforce `upgrade-insecure-requests`, dev-server URLs must be HTTPS (or the browser will upgrade `http://...` to `https://...` and Vite will appear “down”).

### Mode Selection (Guardrails)

Production should never accidentally switch into dev-server mode. Use an explicit flag:

- `VITE_DEV_SERVER_ENABLED=false` by default
- `VITE_DEV_SERVER_URL=` configured only in local dev

The asset helper should only use dev-server URLs when the flag is enabled and the dev server is reachable; otherwise it should fall back to the production manifest.

---

## Manifest + Caching

- Production assets use hashed filenames for safe long-term caching.
- `manifest.json` should not be cached aggressively; changes in manifest must be visible immediately after deploy.

---

## Hybrid Compatibility Notes

- Bundled modules may read legacy globals from `window` (if legacy scripts run first).
- If legacy code needs to call into a module bundle, the module should explicitly attach an API to `window` (intentional bridging).

---

## Syncfusion Licensing

- Store the Syncfusion license string in `.env` (or equivalent server config) and keep it out of git.
- If the license must be registered in client-side JS, the value will be delivered to clients; this is acceptable for the chosen licensing model, but it should be treated as “not committed”, not as a secret.
