- Node 22+
- npm
- Wrangler authenticated locally
Check Wrangler auth:
npx wrangler whoami- Install dependencies:
npm installnpm install also installs the repo Git hooks through Husky.
- Copy the local env file:
cp .env.example .env- Fill in the values you need in
.env.example.
Minimum local browsing setup:
APP_URL=http://localhost:9000INTERNAL_API_SECRETTWITCH_EVENTSUB_SECRETSESSION_SECRET
Add these when you test Twitch auth, EventSub, bot flows, or the panel:
TWITCH_CLIENT_IDTWITCH_CLIENT_SECRETTWITCH_TOKEN_ENCRYPTION_SECRETTWITCH_EXTENSION_CLIENT_IDTWITCH_EXTENSION_SECRETADMIN_TWITCH_USER_IDSTWITCH_BOT_USERNAME
Use VITE_ALLOWED_HOSTS when you need extra local hostnames, and VITE_TWITCH_EXTENSION_API_BASE_URL when the standalone panel build needs a different app origin.
- Bootstrap the app database:
npm run db:bootstrap:localThat resets D1, applies migrations, and prepares the app database.
- Start the app:
npm run devThe local app runs on:
http://localhost:9000
For this repo, treat http://localhost:9000 as the default existing dev app. Before starting another server or changing ports, first confirm whether the app is already running there.
npm run devnpm run tunnelnpm run db:migratenpm run check:prepushnpm run check:shipnpm run buildnpm run test:e2e
Use npm run db:migrate for normal local schema updates.
Use npm run db:bootstrap:local only when you intentionally want to reset the app database.
- home page and channel pages
- search and filters
- settings and moderation UI
- playlist management flows
- Twitch panel UI
Twitch sign-in, EventSub, bot replies, and hosted Twitch panel testing need valid Twitch credentials.
TWITCH_SCOPES applies to the broadcaster app login, not the shared bot login. The current default scope set is:
openid user:read:moderated_channels moderator:read:chatters channel:bot channel:read:subscriptions bits:read channel:manage:redemptions
Use a dedicated local bot account in TWITCH_BOT_USERNAME. The bot OAuth callback only accepts the username configured in local env, so the local env and the connected bot account have to match.
If you test the native channel point reward flow locally, use a Twitch Affiliate or Partner channel. Twitch rejects custom reward calls on channels without channel points.
localhost is enough for basic local browsing, but Twitch auth and callback testing work better through the existing public HTTPS tunnel:
https://dev.itsaunix.systems
Use that tunnel first for sign-in and other auth-sensitive browser checks.
EventSub and Twitch panel hosted testing also work better with a public HTTPS URL.
Start the existing tunnel with:
npm run tunnelThat script points https://dev.itsaunix.systems at http://localhost:9000 using the repo-local Cloudflare tunnel defaults and the credentials file under your local .cloudflared folder.
Override the defaults with:
REQUEST_BOT_TUNNEL_IDREQUEST_BOT_TUNNEL_HOSTREQUEST_BOT_TUNNEL_URLREQUEST_BOT_TUNNEL_CREDENTIALS_FILE
If you need to recreate the tunnel yourself, then set:
APP_URL=https://dev.itsaunix.systemsVITE_ALLOWED_HOSTS=dev.itsaunix.systemsif Vite blocks the hostnameVITE_TWITCH_EXTENSION_API_BASE_URL=https://dev.itsaunix.systemsfor the standalone panel build
Also register these Twitch redirect URIs:
https://dev.itsaunix.systems/auth/twitch/callbackhttps://dev.itsaunix.systems/auth/twitch/bot/callback
ngrok http 9000 is the simpler alternative when you do not need a stable hostname.
Do not start a second local dev server on another port unless http://localhost:9000 and https://dev.itsaunix.systems are both unavailable or you intentionally need a separate instance.
Do not test bot commands against the same broadcaster/channel in both local and production unless that overlap is intentional.
Two failure modes matter:
- same broadcaster + same bot account: one environment can effectively own the shared chat subscription
- same broadcaster + different bot accounts: both environments can receive and act on the same chat command
Safe default:
- use a separate test broadcaster
- use a separate test bot account
- do not keep local and production EventSub subscriptions active for the same broadcaster during debugging
The default workflow is:
git switch -c codex/my-change
git add -A
git commit
git pushDo not commit or push on main. If you start on main, create a feature branch first. Stage the full worktree before every commit unless you intentionally need to exclude something.
Run the push-time gate yourself with:
npm run check:prepushRun extra checks only when they fit the change:
npm run lintnpm run lint:fullnpm run check:shipnpm run buildnpm run test:e2e
The repo hooks already run staged Biome fixes/checks on commit, including staged JSON under src, tests, and scripts, and they run generated-file checks, i18n coverage, lint, typecheck, and tests on push.