# Stalker Portal

> Use when changing Stalker or Ministra routes, stores, catalog or series shapes, playback progress, favorites and recent items, EPG, or remote control.

- Skill: `4gray/stalker-portal` (Agent Skill)
- Install (CLI): `npx skillmds@latest add 4gray/stalker-portal`
- Raw SKILL.md: https://api.skillmd.com/api/skills/4gray/stalker-portal/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: 4gray (https://skillmd.com/u/4gray)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/4gray/stalker-portal

---


# Stalker Portal

## Read First

- `docs/architecture/stalker-portal.md`
- `docs/architecture/stalker-epg.md` for ITV EPG
- `docs/architecture/remote-control.md` for live remote control

## Ownership

- Routed UI: `libs/portal/stalker/feature/src/lib/`
- Session, store, and normalization:
  `libs/portal/stalker/data-access/src/lib/`
- Wire-format and identity contracts: `libs/shared/interfaces/src/lib/` —
  portal-mode predicate, MAC/device-ID utils, auth-failure classifier, `cmd`
  encoder, URL/identity builders. There because Electron main cannot import
  renderer libs; never fork them.
- Electron transport: `apps/electron-backend/src/app/events/stalker.events.ts`
- Provider-neutral collections: `libs/portal/shared/data-access/src/lib/`

Keep Stalker shape and store rules in Stalker data access. Shared portal UI
must remain provider-neutral.

## Portal Mode And Session

Full vs. simple mode is decided by observed behavior, not URL shape, and read
only through `isFullStalkerPortalPlaylist()`. Route playlist-backed catalog,
content and playback calls through `executeStalkerRequest()`. Auth, discovery,
account-profile refresh and row-less collection resolution go direct; read
`stalker-request.utils.ts` before adding a fifth. Repair is lazy per session,
never eager.
Full portals reuse the persisted idempotent handshake token while its session
fingerprint matches, and ping `get_events` at the profile cadence (default
120 s). Auth failures are HTTP 200 plus plain text.

## Series Contract

Inside Stalker portal code, `isStalkerSeriesFlag()` is the canonical predicate
and accepts exactly `true`, `1`, and `'1'`. `normalizeStalkerSeriesFlag()`
delegates to it and produces the normalized positive marker `true` or
`undefined`. The activity normalizer in shared interfaces keeps its
dependency-neutral equivalent for favorites/recent and dashboard
classification. Preserve all three modes: regular `/series`, VOD with embedded
`series[]`, and lazy Ministra VOD `is_series`.

Favorites/recent preserve the normalized positive marker and VOD origin so
reopening still uses the correct lazy or embedded mode. Keep quick-start
translation parameters and the naturally ordered season fallback when
`season_number` is absent.

Lazy episodes use a deterministic tracking ID scoped by parent series,
provider episode, season key, and episode number. `legacyTrackingId` is only a
guarded compatibility alias. Reconciliation is limited to the current parent
series and optional matching season/episode metadata; an exact scoped row
always wins the resolved display position, while a compatible legacy row may
remain tracked only for cleanup. The scoped ID is the in-memory key. At the
strict migration boundary, save the scoped row before clearing a confirmed
legacy row, and keep legacy progress when the save fails.

Before inline or external handoff, attach parent `seriesXtreamId` and resolved
season/episode numbers. Keep them on subsequent position writes.

## Live Contract

- Start bulk ITV EPG eagerly once channel rows exist. Rows read the bulk
  cache, falling back to throttled `get_short_epg` previews when it lacks
  "now".
- Radio skips EPG and external players, preserves live collection identity
  with `radio: 'true'`, and uses the shared inline audio player.

## Validation

Run:

- `pnpm nx test shared-interfaces`
- `pnpm nx test portal-stalker-data-access`
- `pnpm nx test portal-stalker-feature`
- the affected `portal-shared-data-access` / `portal-shared-ui` target for
  collection or radio behavior
- the affected `workspace-dashboard-data-access` and
  `workspace-dashboard-feature` test targets

For the user workflow, run
`pnpm nx run web-e2e:e2e-ci--src/stalker.e2e.ts` or document the strongest
focused coverage available.

