larry-xue/youchannel
User-facing web app, Supabase migrations, YouTube OAuth, library, learning UI, live practice, quota display, and Fly config.
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
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.
User-facing web app, Supabase migrations, YouTube OAuth, library, learning UI, live practice, quota display, and Fly config.
Fastify jobs API, pg-boss workers, Gemini video analysis, admin API, admin console, and OpenAPI ingestion endpoint.
Scalar documentation for POST /openapi/analysis, including request shape, auth headers, and response fields.
Prerequisites
YouChannel is not a static-only app. The complete version needs a database, OAuth configuration, long-running workers, and provider secrets.
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.
A hosted Supabase project, a Google Cloud OAuth client with YouTube Data API enabled, a Gemini API key, and a Fly.io account.
One domain for the user app and one domain for the service/admin console. The Google redirect URI must end with /playlists.
Local setup
Local development uses Supabase CLI, the jobs service on port 4000, the admin console on port 5173, and the user app on port 3000.
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
Use the youchannel repo migrations as the canonical schema.
cd youchannel
pnpm install
supabase start
supabase db reset
supabase status
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
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
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.
Run this from the user app repo after creating a Supabase project.
cd youchannel
supabase link --project-ref <project-ref>
supabase db push
Create a Google OAuth client, enable the YouTube Data API, and add the exact production redirect URI.
https://<your-app-domain>/playlists
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>
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;
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>
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
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
A deploy is only complete when sign-in, YouTube connection, analysis enqueueing, workers, quotas, and admin visibility all work together.
https://<service-domain>/health and confirm the jobs service is healthy./playlists.POST /openapi/analysis with the shared key.Need the product/architecture story rather than deployment commands? Read the full postmortem on larryxue.dev.