diff --git a/AGENTS.md b/AGENTS.md index c1bde1d3a..2cd37bec5 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -18,6 +18,16 @@ This file provides guidance to coding agents working in this repository. - See `docs/architecture/nx-workspace-boundaries.md` for the current Nx tag and alias policy. - Repository-specific skills are committed under `.codex/skills/`. If an external agent does not support skills, treat those files as concise ownership docs. +## PWA / Self-hosted Web + +- The browser self-hosted backend lives in `apps/web-backend`. Do not rely on the historical external `4gray/iptvnator-backend` container for the default Docker flow unless the task explicitly asks to re-sync missing behavior from that repository. +- The Angular PWA resolves its backend through `window.__IPTVNATOR_CONFIG__.BACKEND_URL`, read by `apps/web/src/app/services/runtime-config.ts`. The placeholder file is `apps/web/src/assets/app-config.js`; Docker rewrites the built copy at container startup. +- Keep `assets/app-config.js` out of Angular service worker hashing in `ngsw-config.json`. Runtime rewrites after `web:pwa` must not invalidate `ngsw.json`. +- For PWA output checks, run `pnpm nx build web --configuration=pwa --skip-nx-cache` and verify `dist/apps/web/ngsw-worker.js` plus `dist/apps/web/ngsw.json` exist. If Nx serves stale build metadata after project config changes, run `pnpm nx reset`. +- `web:serve-static` should serve `dist/apps/web` from `web:build:pwa`; do not point it back at the old `dist/apps/web/browser` layout. +- The unified Docker image builds `web:pwa` and `web-backend`, serves static files through nginx, and proxies `/api/*` to the internal Express backend. Keep `BACKEND_URL=/api` for the bundled self-hosted setup. +- Validate Xtream and Stalker self-hosted changes with the mock servers and `pnpm nx run web-e2e:e2e -- --project=chromium --grep @self-hosted`. + ## Documentation After Changes - After implementing a meaningful change, agents must assess whether canonical repo docs need updates before considering the task complete. diff --git a/README.md b/README.md index a7d1c594b..24b735be3 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ The application is a cross-platform, open-source project built with Electron and - Polish - Custom "User Agent" header configuration for playlists - Light and Dark themes -- Docker version available for self-hosting +- Docker image available for self-hosting the PWA and web backend together ## Screenshots: @@ -79,6 +79,21 @@ The application is a cross-platform, open-source project built with Electron and _Note: First version of the application which was developed as a PWA is available in an extra git branch._ +## Self-hosted PWA + +The Docker setup builds the Angular PWA and the monorepo web backend into one +image. The backend handles remote M3U/XMLTV parsing plus Xtream and Stalker +proxy requests under `/api`, so a separate `4gray/iptvnator-backend` container +is not required for the default self-hosted flow. + +```bash +docker compose -f docker/docker-compose.yml up --build +``` + +The application is available at . See +[`docker/README.md`](./docker/README.md) for environment variables and build +details. + ## Download Download the latest version of the application for macOS, Windows, and Linux from the [release page](https://github.com/4gray/iptvnator/releases). diff --git a/docker/README.md b/docker/README.md index 7c895db54..dd8f3b78e 100644 --- a/docker/README.md +++ b/docker/README.md @@ -1,16 +1,55 @@ -# Self-hosted version of IPTVnator +# Self-hosted IPTVnator -You can deploy and run the PWA version of IPTVnator on your own machine with `docker-compose` using the following command: +The self-hosted image contains both pieces required for the browser PWA: - $ cd docker - $ docker-compose up -d +- Angular PWA static files served by nginx +- The monorepo `web-backend` Express app proxied under `/api` -This command will launch the frontend and backend applications. By default, the application will be available at: http://localhost:4333/. The ports can be configured in the `docker-compose.yml` file. +The historical standalone `4gray/iptvnator-backend` image is no longer needed +for the default Docker deployment. -## Build frontend +## Run With Docker Compose - $ docker build -t 4gray/iptvnator -f docker/Dockerfile . +```bash +docker compose -f docker/docker-compose.yml up --build -d +``` -## Build backend +By default the app is available at . -You can find the backend app with all instructions in a separate GitHub repository - https://github.com/4gray/iptvnator-backend \ No newline at end of file +## Build The Image + +```bash +docker build -t 4gray/iptvnator -f docker/Dockerfile . +``` + +The image build runs: + +```bash +pnpm nx build web --configuration=pwa +pnpm nx build web-backend +``` + +## Runtime Configuration + +The container writes `/usr/share/nginx/html/assets/app-config.js` on startup. +That file sets `window.__IPTVNATOR_CONFIG__.BACKEND_URL`, which the PWA reads +before it creates `PwaService`. + +| Variable | Default | Purpose | +| ------------- | ----------------------- | ------------------------------------------------------------------------------------------------ | +| `BACKEND_URL` | `/api` | Browser-facing backend URL used by the PWA. Keep `/api` for the bundled nginx proxy. | +| `CLIENT_URL` | `http://localhost:4333` | Allowed browser origin for backend CORS. Use the public URL when hosting behind a reverse proxy. | +| `PORT` | `3000` | Internal Express backend port. nginx proxy config is patched to match it at container startup. | + +The nginx config serves the PWA with SPA fallback, avoids caching +`assets/app-config.js`, and proxies `/api/*` to the internal backend. + +## Local Validation + +```bash +pnpm nx test web-backend +pnpm nx build web --configuration=pwa --skip-nx-cache +pnpm nx build web-backend +pnpm nx run web-e2e:e2e -- --project=chromium --grep @self-hosted +docker compose -f docker/docker-compose.yml config +``` diff --git a/docs/architecture/pwa-self-hosted.md b/docs/architecture/pwa-self-hosted.md new file mode 100644 index 000000000..ee78cbf83 --- /dev/null +++ b/docs/architecture/pwa-self-hosted.md @@ -0,0 +1,98 @@ +# PWA Self-hosted Architecture + +This document describes the browser PWA and self-hosted Docker path. + +## Ownership + +- `apps/web` owns the Angular browser UI and PWA service worker configuration. +- `apps/web-backend` owns the browser-only backend proxy for remote playlist, + XMLTV, Xtream, and Stalker requests. +- `docker/` owns the production self-hosted image that bundles the PWA and + `web-backend` into one container. + +The old external `4gray/iptvnator-backend` repository is not required for the +default self-hosted deployment. Sync behavior from that repository only when a +change intentionally restores or imports missing backend capabilities. + +## Runtime Backend Configuration + +The PWA reads `window.__IPTVNATOR_CONFIG__.BACKEND_URL` through +`apps/web/src/app/services/runtime-config.ts`. The static placeholder lives at +`apps/web/src/assets/app-config.js` and keeps hosted builds working without +Docker-specific values. + +The Docker entrypoint rewrites `assets/app-config.js` at container startup. +`ngsw-config.json` explicitly excludes this file from Angular service worker +asset hashing so a runtime rewrite does not break cache validation. + +## Service Worker Build + +Use the PWA build configuration for browser deployments: + +```bash +pnpm nx build web --configuration=pwa +``` + +The build must emit these files in `dist/apps/web`: + +- `ngsw-worker.js` +- `ngsw.json` +- `safety-worker.js` +- `worker-basic.min.js` + +`web:serve-static` serves `dist/apps/web` and builds with +`web:build:pwa`, so it exercises the same output layout as Docker. If Nx daemon +state returns stale service worker outputs while changing build options, run: + +```bash +pnpm nx reset +pnpm nx build web --configuration=pwa --skip-nx-cache +``` + +## Web Backend + +`apps/web-backend` exposes these routes: + +- `GET /health` +- `GET /config.js` +- `GET /parse?url=` +- `GET /parse-xml?url=` +- `GET /xtream?url=&username=&password=

&action=` +- `GET /stalker?url=&macAddress=&action=` + +The PWA continues to use `PwaService`; only the backend base URL is resolved at +runtime. Electron routes remain owned by the Electron backend and preload +bridge. + +## Docker Runtime + +The Docker image has two stages: + +1. Build stage installs dependencies and runs `web:pwa` plus `web-backend`. +2. Runtime stage uses `node:22-alpine` with nginx installed. nginx serves + `dist/apps/web` and proxies `/api/*` to the local Express backend. + +Default runtime values: + +- `BACKEND_URL=/api` +- `CLIENT_URL=http://localhost:4333` +- `PORT=3000` + +When hosting behind another domain, set `CLIENT_URL` to the browser origin and +keep `BACKEND_URL=/api` unless the reverse proxy exposes the backend elsewhere. + +## Validation + +Use the narrow validation ladder for self-hosted changes: + +```bash +pnpm nx test web-backend +pnpm nx test web --runTestsByPath apps/web/src/app/services/runtime-config.spec.ts +pnpm nx build web --configuration=pwa --skip-nx-cache +pnpm nx build web-backend +pnpm nx run web-e2e:e2e -- --project=chromium --grep @self-hosted +docker compose -f docker/docker-compose.yml config +``` + +Run `docker build -t iptvnator:self-hosted-test -f docker/Dockerfile .` when a +Docker daemon is available.