Architecture overview
High-level
flowchart LR Browser[Browser] Vercel[Vercel_Nextjs] PG[Postgres] R2[Cloudflare_R2_MP3] PH[PostHog] Browser --> Vercel Browser --> R2 Vercel --> PG Browser --> PH
- Next.js (App Router) on Vercel serves HTML and API-less server components.
- Postgres stores catalog metadata (
audio_resources,tags, junction table). - R2 (or any HTTPS URL) stores bytes; the browser loads audio directly from
audio_url. - PostHog (optional) receives client-side product analytics events.
Route groups
(marketing)— Public shell with header/footer: home, library, lesson[slug], tags, search, docs.(embed)— Minimal chrome for/embed/[slug]KB iframes; CSPframe-ancestorsrestricts embedding.
Data access
Raw SQL via @vercel/postgres (sql tagged templates). Migrations live in src/lib/db/migrations/; run pnpm migrate.
Analytics
posthog-js initializes from NEXT_PUBLIC_POSTHOG_*. Events are captured from AudioPlayer (playback milestones, speed) and library UI (search, tag filter). Admin pages can query PostHog with POSTHOG_PERSONAL_API_KEY + POSTHOG_PROJECT_ID (server-only).
Errors
Optional Sentry via @sentry/nextjs when NEXT_PUBLIC_SENTRY_DSN / SENTRY_DSN are set. global-error.tsx reports uncaught root errors.
Reserved slugs
Avoid published lesson slugs that collide with static routes: library, search, docs, tags, embed, admin, etc.