# Service Map

Generated for the `/self` continuous self-testing loop.

## This repo — `arcade` (primary)
- **Stack:** Laravel 13.5 / PHP 8.4 + Inertia 3 / React 19 (TS strict) + Vite 8. SQLite (dev).
- **Run:** `php artisan serve --port=8765` (Playwright MCP target) · `npm run dev` (Vite HMR) · `php artisan reverb:start` (WebSockets, port 8080).
- **Test:** `php artisan test` (Pest 4, in-memory SQLite, RefreshDatabase global) · `npm run lint` (eslint) · `tsc --noEmit` (typecheck, part of `npm run build`).
- **Build:** `npm run build` (tsc + vite + docs sub-build).
- **Baseline (2026-06-27):** 1703 passed / 7147 assertions, ~213s.

## External dependency — Upstream Catalog API (black box)
- **What:** Read-only game catalog importer source. `https://games.titansys.dev/api/games`.
- **Talks via:** HTTP GET, purchase-code auth (`APP_DEMO_CODE` → `purchase_code` system_setting). Pulled by `GameImporter`.
- **Repo:** Not local, not owned. Test boundary as black box / contract-level only (mock `Http::fake` in tests).
- **Note:** `ctl_`-prefixed `uniqueId` games default `api_enabled=true` (carry `ctl_arcade_save_score` postMessage hook).

## Optional infra (not required for loop)
- **Reverb** (WebSockets) — Arcade TV multiplayer, live GP/tournament updates. Best-effort; `safeBroadcast()` guards.
- **Sentry** — optional, `APP_SENTRY` env. Off in dev.

## Blocked / Deferred

### Deferred
- **Email subject frozen at construct-time locale** (confirmed real, not yet fixed).
  - **Where:** all 15 `app/Mail/*` subclasses set `$this->emailSubject = __(...)` in their
    constructors; `BaseMailable::envelope()` returns it verbatim. `SettingsMailer::send()`
    forces the recipient locale only via `Mail::to()->locale($locale)->send()` (line 58),
    which translates the body lazily during render but NOT the already-frozen subject.
  - **Impact:** cron-triggered (subscription expiry/renewal reminders, inventory expiring)
    and admin-triggered mail to non-English users gets an English subject with a translated
    body. Self-registration is unaffected (request locale already matches the recipient).
  - **Fix recipe (≈17 files, regression-tested by existing mail tests):**
    1. `BaseMailable`: add `protected function subject(): string { return $this->emailSubject; }`;
       change `envelope()` + `content()` to call `$this->subject()` instead of `$this->emailSubject`.
    2. Each mailable: move the `__()`/`match($variant)` subject expression out of `__construct`
       into an overridden `subject()` (constructor-set props remain available as instance props).
    3. `SettingsMailer::send()`: resolve the EmailLog subject inside the recipient locale
       (wrap the `$mail->subject()` read in `App::setLocale($locale)` or resolve post-send) so
       `email_logs.subject` matches what was delivered.
  - **Why deferred:** broad change across all transactional mail; lower severity (subject-line
    locale only, body already correct). Worth a dedicated focused pass, not a rushed loop edit.

### Blocked
- _(none)_
