Leon Serfaty cd1d6a1a28 Add brand logo + favicon across app surfaces
Ship the Podcast Distribution AI wordmark as real assets and replace the
Mic-tile + text placeholder everywhere it appeared.

- public/logo-dark.png (dark wordmark, for light backgrounds) and
  public/logo-light.png (light wordmark, for dark backgrounds)
- New <Logo> component swaps the two via Tailwind dark: variants, so the
  dark logo shows on all non-themed surfaces (marketing, auth, admin,
  public share) and the light logo only in dark-mode app surfaces
- Wire <Logo> into the marketing header/footer, auth layout, app header
  (default branch only - white-label org logos untouched), admin header
  (+ Admin badge), and the public share page
- Favicon via App Router file convention: app/icon.png + app/apple-icon.png

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 20:58:37 -04:00

🎙️ Podcast Distribution AI

An all-in-one AI platform that takes you from a topic idea to a finished, publishable podcast episode in minutes — it writes the script (GPT-4), records realistic multi-voice audio (ElevenLabs), and designs the cover art (DALL·E), then lets you fine-tune, download, and repurpose the result.

Stack

Concern Choice
Framework Next.js (App Router) + TypeScript
UI Tailwind CSS + shadcn/ui + Recharts
Database PostgreSQL + Prisma
Auth Better Auth (email/password + Google, admin + organization plugins)
Queue pg-boss (Postgres-backed, no Redis) + a separate worker process
Storage Local disk on a persistent volume (swappable StorageProvider → S3/R2)
AI OpenAI (GPT-4 + DALL·E), ElevenLabs (TTS + dialogue)
Billing Stripe and PayPal → one unified Subscription model
Email Resend
Deploy Dokploy (Docker Compose + Traefik) — see deploy/README.md

Architecture

Browser ──► Next.js web (PM2)  ──enqueue──►  Postgres (app data + pgboss queue)
                │  SSE status                      ▲ claim job (SKIP LOCKED)
                ▼                                   │
          /api/assets (private mp3)          Worker (PM2, ffmpeg)
                                              script → segment → ElevenLabs
                                              → ffmpeg stitch → DALL·E → save → meter
                                                       │
                                                       ▼
                                              Local disk  storage/{mp3,art}

Local development

npm install
cp .env.example .env        # fill DATABASE_URL, BETTER_AUTH_SECRET, OPENAI_API_KEY, ELEVENLABS_API_KEY…
npx prisma migrate dev      # create tables
npm run db:seed             # seed the plan catalog

# Two processes:
npm run dev                 # web (http://localhost:3000)
npm run worker:dev          # generation worker (needs ffmpeg on PATH)

ffmpeg must be installed and on PATH for audio stitching (brew install ffmpeg / apt install ffmpeg / choco install ffmpeg).

Make yourself an admin after signing up:

npm run make-admin you@email.com   # then visit /admin

Key directories

app/(marketing)   public landing + pricing
app/(auth)        sign-in / sign-up / password reset
app/(app)         user dashboard (episodes, wizard, usage, billing, team, api-keys, settings)
app/(admin)       admin dashboard (users, subscriptions, AI cost, moderation, health, flags, audit)
app/api           auth, webhooks/{stripe,paypal}, episodes/[id]/stream (SSE), assets, v1 (API)
lib/ai            provider abstraction + pipeline (generate-episode, segment, stitch, repurpose)
lib/billing       plans, stripe, paypal, catalog, unified subscription writer, webhooks
lib/queue         pg-boss client + job definitions
lib/storage       StorageProvider interface + local-disk impl
worker/           pg-boss consumer (runs the generation pipeline)

How generation works

  1. The 3-step wizard creates an Episode (QUEUED) + speaker config, then enqueues a pg-boss job (after enforceLimit checks the plan).
  2. The worker runs the pipeline, updating Episode.status at each stage.
  3. The episode page subscribes to /api/episodes/[id]/stream (SSE) and shows a live stepper, then renders the script editor, audio player, and cover art when READY.

Long scripts are chunked to stay under ElevenLabs' ~2k-char dialogue limit, synthesized per segment, then concatenated and loudness-normalized with ffmpeg.

Deployment

Containerized for Dokploy (Docker Compose: web + worker, Traefik for domain/TLS/SSE, a persistent storage volume). See deploy/README.md for the full runbook (env, domain, migrations-on-boot, webhooks, backups).

S
Description
No description provided
Readme 454 KiB
Languages
TypeScript 98.8%
JavaScript 0.4%
CSS 0.4%
Dockerfile 0.4%