An Angular application and Node/Express API for planning multi-film visits to Cineworld.
- Find a cinema — search Cineworld locations by name, mark favourites for quick access, or sort by your current location to see distance and direction.
- Browse upcoming listings — choose a day from the next week and view the films and screening times available at that cinema.
- Filter screening formats — include or exclude formats and accessibility options such as 2D, 3D, 4DX, ScreenX, Superscreen, subtitled, and audio-described screenings.
- Open useful links — jump to Cineworld cinema and film pages, trailers, maps, and booking pages from the planner.
- Compare several films — select the films you want to see and compare all of their screenings on a colour-coded timeline.
- Account for trailers and runtime estimates — configure the trailer allowance used to estimate when each film finishes.
- Narrow the schedule — restrict listings by earliest start, latest finish, and maximum break length.
- Build an itinerary manually — select individual screenings and immediately see overlaps or breaks in your chosen schedule.
- Generate multi-film itineraries — automatically find compatible combinations of screenings, including estimated break times between films.
- Remember preferences — retain favourite cinemas, saved screening filters, trailer allowance, and maximum break length in the browser.
src/appcontains the Angular frontend.src/node/servercontains the API, which retrieves and maps Cineworld data.- The frontend and API are deployed separately. The production frontend uses the API URL configured in
src/constants/constants.ts.
- Node.js 26.x and npm
- Docker, only when building or running the API container
The required Node version is declared in package.json and used by CI and the Docker image.
Install the locked dependencies:
npm ciStart the API in one terminal. It listens on http://localhost:3000 and restarts when server source files change:
npm run watch-nodeStart the Angular development server in another terminal:
npm run start-appThe browser opens at http://localhost:4200. This origin is allowed by the API's CORS policy and the local frontend configuration points to port 3000.
| Variable | Required | Purpose |
|---|---|---|
PORT |
No | API port. Defaults to 3000. |
HTTPS_CERTIFICATES_PATH |
No | Enables HTTPS. The directory must contain readable cert.pem and privkey.pem files. The server fails to start if either file cannot be read. |
The API only accepts browser requests from the origins listed in src/node/server/index.ts. Update that list deliberately when adding a frontend host.
The frontend API endpoint is selected at build time:
| Configuration | Command | API target |
|---|---|---|
| Local | npm run start-app |
http://localhost:3000 |
| Ring | npm run start-app-ring |
http://ring:43000 |
| Production | npm run build-prod |
https://api.kingshill.cineworld-planner.co.uk:43000 |
These URLs are defined in src/constants/constants.ts rather than runtime environment variables.
Run the same quality gate used by GitHub Actions:
npm run verify-releaseThis cleans generated output, lints the TypeScript and Angular templates, builds the API, runs the unit tests once, and creates an optimized frontend build.
Useful individual commands:
| Command | Result |
|---|---|
npm run lint |
Lint application and server source. |
npm test |
Run the Vitest suite once. |
npm run watch-test |
Run tests in watch mode. |
npm run build-node |
Compile the API to dist/node. |
npm run build-prod |
Build static frontend files in dist/cineworld-planner/browser. |
npm run start-node |
Run the previously compiled API. |
Pushes and pull requests to master run npm run verify-release with Node 26 in GitHub Actions. They do not deploy the website or publish a container.
A version tag triggers the release workflow. It verifies the application, publishes the website to GitHub Pages, and pushes versioned and latest API images to Docker Hub. A separate GitHub Release page is not required.
Before the first release:
- In the repository's Settings → Pages, set the source to GitHub Actions.
- Add a repository Actions secret named
DOCKERHUB_TOKENcontaining a Docker Hub access token with permission to writeroaders/cineworldplanner. - If the
github-pagesenvironment restricts deployment sources, allow tags matchingv*.
Build the application before the image because the Dockerfile packages the compiled dist/node output:
npm run verify-release
docker build -t roaders/cineworldplanner:latest .
docker run --name cineworldplanner --rm \
--read-only \
--cap-drop=ALL \
--security-opt=no-new-privileges \
--pids-limit=100 \
--memory=256m \
--cpus=1 \
-p 127.0.0.1:3000:3000 \
roaders/cineworldplanner:latestThe image runs as the unprivileged node user. Keep the filesystem read-only, do not use --privileged, and do not mount host paths unless the service needs them. The loopback port binding prevents direct network access; a reverse proxy on the host can reach it locally.
To serve HTTPS, mount the certificate directory read-only and configure it:
docker run --name cineworldplanner --rm \
--read-only \
--cap-drop=ALL \
--security-opt=no-new-privileges \
--pids-limit=100 \
--memory=256m \
--cpus=1 \
-p 127.0.0.1:3000:3000 \
-e HTTPS_CERTIFICATES_PATH=/certificates \
-v /path/to/certificates:/certificates:ro \
roaders/cineworldplanner:latestThe release workflow publishes dist/cineworld-planner/browser to GitHub Pages. Until a custom domain is configured, the site is available at https://roaders.github.io/cineworld-planner/.
To publish a patch release from a clean master branch:
npm run releaseThis increments the patch version, creates the version commit and vX.Y.Z tag, and pushes them to origin. Pushing the tag starts the release workflow; normal branch pushes never deploy. The workflow rejects tags that are not on master or do not match the version in package.json.



