# S02: Transcript Ingestion API — UAT

**Milestone:** M001
**Written:** 2026-03-29T22:19:19.537Z

## UAT: S02 — Transcript Ingestion API

### Preconditions
- PostgreSQL running on `localhost:5433` (via `docker compose up -d chrysopedia-db`)
- Test database `chrysopedia_test` exists: `docker exec chrysopedia-db psql -U chrysopedia -c "CREATE DATABASE chrysopedia_test;"`
- Backend dependencies installed: `cd backend && pip install -r requirements.txt`
- Working directory: `backend/`

---

### Test 1: Happy-Path Ingestion
**Steps:**
1. Run `python -m pytest tests/test_ingest.py::test_ingest_creates_creator_and_video -v`

**Expected:**
- Test passes
- Response status 200
- Response JSON contains: `video_id` (UUID), `creator_id` (UUID), `creator_name` = "Skope", `segments_stored` = 5, `processing_status` = "transcribed", `is_reupload` = false
- Creator record exists in DB with `folder_name` = "Skope", `slug` = "skope"
- SourceVideo record exists with correct creator linkage
- 5 TranscriptSegment rows with `segment_index` 0–4

### Test 2: Creator Reuse
**Steps:**
1. Run `python -m pytest tests/test_ingest.py::test_ingest_reuses_existing_creator -v`

**Expected:**
- Test passes
- When a Creator with `folder_name` = "Skope" already exists, ingesting a transcript with `creator_folder` = "Skope" reuses the existing Creator (same ID)
- Only 1 Creator row in the database (not duplicated)

### Test 3: Idempotent Re-upload
**Steps:**
1. Run `python -m pytest tests/test_ingest.py::test_ingest_idempotent_reupload -v`

**Expected:**
- Test passes
- Uploading the same transcript file twice returns `is_reupload` = true on second upload
- Same `video_id` returned both times
- Still only 5 TranscriptSegment rows (old segments deleted, new ones inserted)
- Only 1 SourceVideo row exists

### Test 4: Raw JSON Persistence
**Steps:**
1. Run `python -m pytest tests/test_ingest.py::test_ingest_saves_json_to_disk -v`

**Expected:**
- Test passes
- Raw JSON file saved at `{transcript_storage_path}/Skope/{source_file}.json`
- File content is valid JSON matching the uploaded payload

### Test 5: Invalid JSON Rejection
**Steps:**
1. Run `python -m pytest tests/test_ingest.py::test_ingest_rejects_invalid_json -v`

**Expected:**
- Test passes
- Uploading a file with invalid JSON syntax returns HTTP 400 or 422
- No Creator, SourceVideo, or TranscriptSegment records created

### Test 6: Missing Fields Rejection
**Steps:**
1. Run `python -m pytest tests/test_ingest.py::test_ingest_rejects_missing_fields -v`

**Expected:**
- Test passes
- Uploading JSON without required `creator_folder` field returns HTTP 400 or 422
- No partial records created in the database

### Test 7: Full Suite
**Steps:**
1. Run `cd backend && python -m pytest tests/test_ingest.py -v`

**Expected:**
- All 6 tests pass
- Total runtime under 10 seconds

### Test 8: Endpoint Wiring Smoke Test
**Steps:**
1. Run `cd backend && python3 -c "from main import app; print([r.path for r in app.routes if 'ingest' in r.path])"`

**Expected:**
- Output includes `/api/v1/ingest`

### Edge Case: Docker Compose Compatibility
**Steps:**
1. Run `docker compose config > /dev/null` from project root

**Expected:**
- Exits 0 (no regression from S02 changes)
