This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
AI-powered podcast tracking and analysis system for manosphere-related content. Monitors RSS feeds, downloads audio, transcribes via Cloudflare AI, and generates episode-level and weekly cross-podcast trend analyses.
- Runtime: Cloudflare Workers (D1 for SQLite, R2 for audio storage, AI for transcription/analysis)
- Frontend: React 19 + TanStack Router (file-based routing) + TanStack React Start (full-stack meta-framework)
- Styling: Tailwind CSS 4
- Database: Drizzle ORM over Cloudflare D1
- Build: Vite 7 with Cloudflare, React, and TanStack plugins
- Package manager: pnpm
pnpm dev # Local dev server (uses Wrangler miniflare for D1/R2/AI bindings)
pnpm build # Vite build + tsc --noEmit type checking
pnpm deploy # Build then wrangler deploy
# Database
pnpm db:generate # Generate Drizzle migration from schema changes
pnpm db:migrate:local # Apply migrations to local D1
pnpm db:migrate:remote # Apply migrations to production D1
# Types
pnpm cf-typegen # Regenerate Cloudflare binding types (worker-configuration.d.ts)No test suite or linter is configured.
- Cron trigger (every 6 hours) calls
pollAllFeeds()insrc/lib/rss.ts - New episodes are created with status
pendingand a Cloudflare Workflow is dispatched - The workflow (
src/workflows/episode-processing.ts) progresses through: download → transcribe → analyse → persist - Episode status moves through:
pending→downloading→transcribing→analyzing→complete(orerror)
src/server.ts– Worker entry point; handles scheduled events, exports the workflow classsrc/lib/server-fns.ts– All client-server RPC viacreateServerFn()from TanStack React Start. Mutations checkassertNotDemo()for demo mode safetysrc/lib/rss.ts– RSS feed fetching and parsing. Resolves Apple Podcasts URLs to RSS via iTunes APIsrc/lib/analysis.ts– AI prompt construction and response parsing. Truncates transcripts at 50k charssrc/lib/timestamp.ts– Groups word-level transcript data into semantic segments (15-word target, breaks at sentence punctuation)src/db/schema.ts– Drizzle schema (5 tables: podcasts, episodes, transcript_segments, episode_analyses, weekly_analyses). Usesnanoid()for IDs
File-based routes in src/routes/:
/– Homepage with podcast list and latest weekly analysis/podcasts/$podcastId– Podcast detail with episode list/episodes/$episodeId– Episode detail with synchronised audio player and transcript/admin– Admin panel for feed management, polling, episode reset, weekly analysis generation/api/audio.$episodeId– Audio streaming endpoint with HTTP Range request support
Defined in wrangler.jsonc and typed in src/env.d.ts:
DB– D1 databaseAUDIO_BUCKET– R2 bucket for audio filesAI– Cloudflare AI bindingEPISODE_WORKFLOW– Workflow binding for episode processingIS_DEMO– Environment variable controlling read-only demo mode
- Cloudflare Workers have a 128MB memory limit – audio transcription uses sequential 5MB chunks (not parallel) to stay within bounds
- Workflow instance IDs are stored on episodes so running jobs can be cancelled from the admin panel
- Weekly analysis is cached for 24 hours unless force-refreshed
- Path alias
~/*maps tosrc/*(configured in tsconfig and vite) cn()utility insrc/lib/utils.tscombinesclsx+tailwind-mergefor conditional class names- Dark mode supported via
dark:Tailwind prefixes throughout - Database access via
getDb(env)helper fromsrc/db/index.ts - All IDs are nanoid-generated strings, timestamps are UNIX integers