# CultRoll

CultRoll is the standalone public app, portal, and scraper for cinema discovery,
showtimes, and title operations.

## Surfaces

- Public app: `cultroll.com`
- Portal/admin app: `portal.cultroll.com`
- Scraper worker: `cultroll-scraper`

## Local commands

```bash
npm run build
npm run build:cultroll
npm run build:cultroll-admin
npm run dev:cultroll
npm run dev:portal
```

## Local Nix / devenv

This repo now ships with a native `devenv.sh` setup (`devenv.yaml` + `devenv.nix`)
for a fully local Cloudflare-oriented workflow.

```bash
direnv allow
devenv shell
cultroll-install
```

Copy the local env templates before starting services:

```bash
cp .env.example .env
cp .dev.vars.example .dev.vars
cp functions/cultroll-scraper/.dev.vars.example functions/cultroll-scraper/.dev.vars
```

Useful commands inside the devenv shell:

```bash
cultroll-dev
cultroll-admin-dev
cultroll-scraper-dev
devenv tasks run cultroll:scrape-local
cultroll-build
cultroll-db-local-reset
cultroll-dns-plan
devenv up
```

Notes:

- All local listeners now read `HOST` + `PORT`; the devenv shell defaults
  `HOST=0.0.0.0` and uses ports `4324` (public), `4328` (admin), and `8787`
  (scraper).
- The app/admin dev servers also inherit `CULTROLL_ALLOWED_HOSTS` from `devenv`,
  which automatically includes loopback plus the current `$HOSTNAME` so requests
  through the local devenv hostname are accepted.
- The dev launchers clear stale repo-owned listeners on their target ports before
  starting, so restarted processes pick up new hostname allowlists and `HOST`
  changes instead of leaving an older Astro process bound to `4324` or `4328`.
- Repo-local mutable state lives under `./.devenv/state/`, including Wrangler's
  local persistence (`./.devenv/state/wrangler/v3`), scraper logs
  (`./.devenv/state/logs`), the local npm cache (`./.devenv/state/npm`), the
  repo-local temp directory (`./.devenv/state/tmp`), and repo-local XDG
  cache/config/state paths used by local tooling.
- Wrangler workspace scratch directories are also redirected under
  `./.devenv/state/wrangler/workspaces/`, so local `wrangler dev` runs do not
  leave `./.wrangler/tmp` or `functions/cultroll-scraper/.wrangler/tmp`
  artifacts behind in the working tree.
- Cloudflare commands in `devenv` prefer the repo-pinned
  `node_modules/.bin/wrangler` when it is installed, with the Nix package only
  as a bootstrap fallback, so local compatibility-date support follows the
  project's lockfile instead of whatever Wrangler version happens to be in
  nixpkgs.
- Astro's Cloudflare platform proxy is pinned to the matching Wrangler config
  for each surface and shares local state via `./.devenv/state/wrangler/v3`,
  matching Wrangler's local D1 persistence layout, so the public app, admin
  app, and scraper all point at the same local D1 data.
- `devenv up` now runs only the public app and admin app. Use
  `devenv tasks run cultroll:scrape-local` for a one-shot local scrape that
  resets D1, runs all enabled source targets, and then executes the enrichment
  pipeline stages needed to populate local data.
- `cultroll-db-local-reset` now clears the persisted local D1 files before it
  reapplies schema and seed data, so repeated local scraper runs start from a
  truly clean database state.
- Full metadata enrichment in local runs requires `TMDB_API_KEY`. The scrape
  task now honors `TMDB_API_KEY` from either
  `functions/cultroll-scraper/.dev.vars` or the shell environment and prints a
  metadata coverage summary after each run.
- `cultroll-scraper-dev` is still available when you want the scraper worker
  running continuously for live admin controls or direct endpoint testing.
- The one-shot `cultroll:scrape-local` task now tears down the temporary local
  scraper worker process tree when it exits, so it should not leave a stray
  `workerd` listener behind on port `8787`.
- `cultroll-db-local-reset` uses local D1 state; the `cultroll-db-remote-*`
  scripts require `CLOUDFLARE_ACCOUNT_ID` and `CLOUDFLARE_API_TOKEN` in `.env`.
- `cultroll-dns-plan` and `cultroll-dns-apply` use `CLOUDFLARE_TOKEN` from `.env`.

Test URLs after `devenv up`:

- Public app: `http://127.0.0.1:4324`
- Admin app: `http://127.0.0.1:4328/admin`
- Scraper worker when running: `http://127.0.0.1:8787`
- If your local devenv hostname resolves, the same ports also work via
  `http://$HOSTNAME:4324` and `http://$HOSTNAME:4328/admin`.

## Deployments

GitHub Actions in `.github/workflows/` deploy:

- `deploy-cultroll.yml` — public app
- `deploy-cultroll-admin.yml` — portal/admin app
- `deploy-cultroll-scraper.yml` — scraper worker
- `sync-cultroll-infra.yml` — D1 and R2 bootstrap
- `sync-dns.yml` — CultRoll DNS zones
- `sync-bulk-redirects.yml` — CultRoll alias redirects

## Required GitHub secrets

- `CLOUDFLARE_ACCOUNT_ID`
- `CLOUDFLARE_API_TOKEN`
- `CULTROLL_AUTH_FROM_EMAIL`
- `CULTROLL_AUTH_FROM_NAME`
- `CULTROLL_GOOGLE_CLIENT_ID`
- `SCRAPER_ADMIN_TOKEN`
- `SMTP2GO_API_KEY`
- `TMDB_API_KEY`

Secret names can be inventoried from GitHub, but secret values must be recreated
from their original source-of-truth systems when bootstrapping a new repo.
