Complete deployment guide

Deploy the full YouChannel stack.

This page is the practical entry point for running YouChannel end to end: the learner-facing web app, Supabase Auth/Postgres, YouTube OAuth, Gemini analysis and Live practice, async jobs, admin tooling, and the OpenAPI analysis endpoint.

Repository map

Three repos make the full product.

Use the user app repository as the source of truth for the complete Supabase schema. The service repository runs the async backend and admin console. The OpenAPI docs repository documents the external analysis API.

larry-xue/youchannel

User-facing web app, Supabase migrations, YouTube OAuth, library, learning UI, live practice, quota display, and Fly config.

larry-xue/youchannel-service

Fastify jobs API, pg-boss workers, Gemini video analysis, admin API, admin console, and OpenAPI ingestion endpoint.

Prerequisites

Prepare these before you deploy.

YouChannel is not a static-only app. The complete version needs a database, OAuth configuration, long-running workers, and provider secrets.

Runtime and tools

Node.js 22 for the user app, Node.js 20+ for the service, pnpm 9+, Docker, Supabase CLI 2+, Fly CLI, and GitHub access to the repos.

Cloud accounts

A hosted Supabase project, a Google Cloud OAuth client with YouTube Data API enabled, a Gemini API key, and a Fly.io account.

Domains

One domain for the user app and one domain for the service/admin console. The Google redirect URI must end with /playlists.

Local setup

Run the full stack locally first.

Local development uses Supabase CLI, the jobs service on port 4000, the admin console on port 5173, and the user app on port 3000.

1

Clone the repositories side by side

The relative paths in the docs assume this layout.

git clone https://github.com/larry-xue/youchannel.git
git clone https://github.com/larry-xue/youchannel-service.git
git clone https://github.com/larry-xue/youchannel-openapi-analysis-docs.git
2

Start Supabase and apply the complete schema

Use the youchannel repo migrations as the canonical schema.

cd youchannel
pnpm install
supabase start
supabase db reset
supabase status
3

Configure and run the jobs service

Copy the sample env files, fill Supabase, Postgres, shared key, and Gemini values, then start jobs and admin.

cd ../youchannel-service
pnpm install
cp apps/jobs/.env.example apps/jobs/.env
cp apps/admin/.env.example apps/admin/.env
pnpm -C apps/jobs dev
pnpm -C apps/admin dev
4

Configure and run the user-facing web app

Set OPENAPI_BASE_URL=http://localhost:4000 and use the same OPENAPI_SHARED_KEY as the jobs service.

cd ../youchannel
cp .env.example .env
pnpm dev

Production

Deploy the complete hosted version.

The current documented production path is Fly.io for both Node services and hosted Supabase for Auth/Postgres. A Cloudflare-native rewrite would need different worker and queue architecture.

1

Create hosted Supabase and push migrations

Run this from the user app repo after creating a Supabase project.

cd youchannel
supabase link --project-ref <project-ref>
supabase db push
2

Configure Google OAuth and YouTube Data API

Create a Google OAuth client, enable the YouTube Data API, and add the exact production redirect URI.

https://<your-app-domain>/playlists
3

Deploy the jobs service and admin console

The service container serves both the Fastify API and the built admin SPA.

cd youchannel-service
fly apps create youchannel-service
fly secrets set \
  DATABASE_URL='<supabase postgres url>' \
  SUPABASE_URL='https://<project-ref>.supabase.co' \
  SUPABASE_SERVICE_ROLE_KEY='<supabase service role key>' \
  OPENAPI_SHARED_KEY='<shared key>' \
  GEMINI_API_KEY='<gemini key>' \
  GEMINI_MODEL='gemini-2.5-flash' \
  ADMIN_ORIGIN='https://<your-service-domain>'
fly deploy \
  --build-arg VITE_SUPABASE_URL=https://<project-ref>.supabase.co \
  --build-arg VITE_SUPABASE_ANON_KEY=<supabase anon key>
4

Bootstrap the first admin user

Create or confirm a Supabase Auth user, then grant admin access in SQL.

insert into public.admin_users (user_id)
select id from auth.users
where email = 'admin@your-domain.example'
on conflict (user_id) do nothing;
5

Deploy the user-facing web app

Runtime secrets stay in Fly. Public client values are passed as Docker build args.

cd youchannel
fly apps create youchannel
fly secrets set \
  VITE_BASE_URL=https://<your-app-domain> \
  SUPABASE_URL=https://<project-ref>.supabase.co \
  SUPABASE_ANON_KEY=<supabase anon key> \
  SUPABASE_SERVICE_ROLE_KEY=<supabase service role key> \
  GOOGLE_API_KEY=<gemini key> \
  GOOGLE_LIVE_API_KEY=<gemini live key> \
  GEMINI_MODEL=gemini-2.5-flash \
  GOOGLE_OAUTH_CLIENT_ID=<google oauth client id> \
  GOOGLE_OAUTH_CLIENT_SECRET=<google oauth client secret> \
  GOOGLE_OAUTH_REDIRECT_URI=https://<your-app-domain>/playlists \
  OPENAPI_BASE_URL=https://<your-service-domain> \
  OPENAPI_SHARED_KEY=<shared key>
fly deploy \
  --build-arg VITE_SUPABASE_URL=https://<project-ref>.supabase.co \
  --build-arg VITE_SUPABASE_ANON_KEY=<supabase anon key> \
  --build-arg VITE_GOOGLE_OAUTH_CLIENT_ID=<google oauth client id>
6

Update Supabase Auth URLs

Set the production Site URL and include local plus production redirect URLs.

Site URL: https://<your-app-domain>
Additional redirects:
  http://localhost:3000
  http://localhost:3000/playlists
  https://<your-app-domain>
  https://<your-app-domain>/playlists

Environment map

Keep public and private values separate.

VITE_* values are exposed to the browser or build. Service role keys, database URLs, OAuth client secrets, and provider keys must stay in deployment secrets.

Area Required values Where to set them
User app build VITE_SUPABASE_URL, VITE_SUPABASE_ANON_KEY, VITE_GOOGLE_OAUTH_CLIENT_ID Fly deploy build args.
User app runtime SUPABASE_SERVICE_ROLE_KEY, Gemini keys, Google OAuth secret, OPENAPI_SHARED_KEY Fly secrets for the youchannel app.
Jobs service DATABASE_URL, SUPABASE_SERVICE_ROLE_KEY, GEMINI_API_KEY, OPENAPI_SHARED_KEY Fly secrets for the youchannel-service app.
Admin console VITE_SUPABASE_URL, VITE_SUPABASE_ANON_KEY Build args when deploying the service container.

Smoke test

Verify the product, not just the deploy.

A deploy is only complete when sign-in, YouTube connection, analysis enqueueing, workers, quotas, and admin visibility all work together.

Need the product/architecture story rather than deployment commands? Read the full postmortem on larryxue.dev.