# S01: Docker Compose + Database + Whisper Script

**Goal:** Deployable infrastructure: Docker Compose project with PostgreSQL (full schema), FastAPI skeleton, and desktop Whisper transcription script
**Demo:** After this: docker compose up -d starts all services on ub01; Whisper script transcribes a sample video to JSON

## Tasks
- [x] **T01: Created full Docker Compose project (xpltd_chrysopedia) with PostgreSQL 16, Redis, FastAPI API, Celery worker, and React web services plus directory scaffolding** — 1. Create project directory structure:
   - backend/ (FastAPI app)
   - frontend/ (React app, placeholder)
   - whisper/ (desktop transcription script)
   - docker/ (Dockerfiles)
   - prompts/ (editable prompt templates)
   - config/ (canonical tags, settings)
2. Write docker-compose.yml with services:
   - chrysopedia-api (FastAPI, Uvicorn)
   - chrysopedia-web (React, nginx)
   - chrysopedia-db (PostgreSQL 16)
   - chrysopedia-worker (Celery)
   - chrysopedia-redis (Redis for Celery broker)
3. Follow XPLTD conventions: bind mounts, project naming xpltd_chrysopedia, dedicated bridge network
4. Create .env.example with all required env vars
5. Write Dockerfiles for API and web services
  - Estimate: 2-3 hours
  - Files: docker-compose.yml, .env.example, docker/Dockerfile.api, docker/Dockerfile.web, backend/main.py, backend/requirements.txt
  - Verify: docker compose config validates without errors
- [x] **T02: Created SQLAlchemy models for all 7 entities, Alembic async migration infrastructure, and initial migration with full PostgreSQL schema; fixed docker compose config validation failure** — 1. Create SQLAlchemy models for all 7 entities:
   - Creator (id, name, slug, genres, folder_name, view_count, timestamps)
   - SourceVideo (id, creator_id FK, filename, file_path, duration, content_type enum, transcript_path, processing_status enum, timestamps)
   - TranscriptSegment (id, source_video_id FK, start_time, end_time, text, segment_index, topic_label)
   - KeyMoment (id, source_video_id FK, technique_page_id FK nullable, title, summary, start/end time, content_type enum, plugins, review_status enum, raw_transcript, timestamps)
   - TechniquePage (id, creator_id FK, title, slug, topic_category, topic_tags, summary, body_sections JSONB, signal_chains JSONB, plugins, source_quality enum, view_count, review_status enum, timestamps)
   - RelatedTechniqueLink (id, source_page_id FK, target_page_id FK, relationship enum)
   - Tag (id, name, category, aliases)
2. Set up Alembic for migrations
3. Create initial migration
4. Add seed data for canonical tags (6 top-level categories)
  - Estimate: 2-3 hours
  - Files: backend/models.py, backend/database.py, alembic.ini, alembic/versions/*.py, config/canonical_tags.yaml
  - Verify: alembic upgrade head succeeds; all 7 tables exist with correct columns and constraints
- [x] **T03: Built FastAPI app with DB-connected health check, Pydantic schemas for all 7 entities, creators/videos CRUD endpoints, structured logging, and pydantic-settings config** — 1. Set up FastAPI app with:
   - CORS middleware
   - Database session dependency
   - Health check endpoint (/health)
   - API versioning prefix (/api/v1)
2. Create Pydantic schemas for all entities
3. Implement basic CRUD endpoints:
   - GET /api/v1/creators
   - GET /api/v1/creators/{slug}
   - GET /api/v1/videos
   - GET /api/v1/health
4. Add structured logging
5. Configure environment variable loading from .env
  - Estimate: 1-2 hours
  - Files: backend/main.py, backend/schemas.py, backend/routers/__init__.py, backend/routers/health.py, backend/routers/creators.py, backend/config.py
  - Verify: curl http://localhost:8000/health returns 200; curl http://localhost:8000/api/v1/creators returns empty list
- [x] **T04: Created desktop Whisper transcription script with single-file/batch modes, resumability, spec-compliant JSON output, and ffmpeg validation** — 1. Create Python script whisper/transcribe.py that:
   - Accepts video file path (or directory for batch mode)
   - Extracts audio via ffmpeg (subprocess)
   - Runs Whisper large-v3 with segment-level and word-level timestamps
   - Outputs JSON matching the spec format (source_file, creator_folder, duration, segments with words)
   - Supports resumability: checks if output JSON already exists, skips
2. Create whisper/requirements.txt (openai-whisper, ffmpeg-python)
3. Write output to a configurable output directory
4. Add CLI arguments: --input, --output-dir, --model (default large-v3), --device (default cuda)
5. Include progress logging for long transcriptions
  - Estimate: 1-2 hours
  - Files: whisper/transcribe.py, whisper/requirements.txt, whisper/README.md
  - Verify: python whisper/transcribe.py --help shows usage; script validates ffmpeg is available
- [x] **T05: Created comprehensive README.md with architecture diagram, setup instructions, and env var docs; created sample transcript JSON fixture with 5 segments and 106 words matching Whisper output format** — 1. Write README.md with:
   - Project overview
   - Architecture diagram (text)
   - Setup instructions (Docker Compose + desktop Whisper)
   - Environment variable documentation
   - Development workflow
2. Verify Docker Compose stack starts with: docker compose up -d
3. Verify PostgreSQL schema with: alembic upgrade head
4. Verify API health check responds
5. Create sample transcript JSON for testing subsequent slices
  - Estimate: 1 hour
  - Files: README.md, tests/fixtures/sample_transcript.json
  - Verify: docker compose config validates; README covers all setup steps; sample transcript JSON is valid
