---
estimated_steps: 43
estimated_files: 2
skills_used: []
---

# T01: Add VideoConsent + ConsentAuditLog models and Alembic migration

Add the consent data model to the codebase: a mutable `VideoConsent` table (current consent state per video) and an append-only `ConsentAuditLog` table (versioned per-field change history). Create Alembic migration `017_add_consent_tables.py`.

## Steps

1. Read `backend/models.py` to see existing patterns (`_uuid_pk()`, `_now()`, `sa_relationship`, enum patterns).
2. Add `ConsentField` enum to `backend/models.py`: `kb_inclusion`, `training_usage`, `public_display`.
3. Add `VideoConsent` model:
   - UUID PK via `_uuid_pk()`
   - `source_video_id`: UUID FK → `source_videos.id`, unique constraint (one consent record per video)
   - `creator_id`: UUID FK → `creators.id` (denormalized for fast queries)
   - `kb_inclusion`: bool, default False
   - `training_usage`: bool, default False  
   - `public_display`: bool, default True
   - `updated_by`: UUID FK → `users.id`
   - `created_at`, `updated_at`: datetime via `_now()`
   - Relationships: `source_video`, `creator`, `audit_entries`
4. Add `ConsentAuditLog` model:
   - UUID PK via `_uuid_pk()`
   - `video_consent_id`: UUID FK → `video_consents.id`
   - `version`: Integer (auto-incrementing per video_consent_id, assigned in application code)
   - `field_name`: String (which consent field changed)
   - `old_value`: Boolean, nullable
   - `new_value`: Boolean
   - `changed_by`: UUID FK → `users.id`
   - `ip_address`: String(45), nullable
   - `created_at`: datetime via `_now()`
5. Create `alembic/versions/017_add_consent_tables.py` — follow the pattern from `016_add_users_and_invite_codes.py`. Create both tables with proper FKs and the unique constraint on `source_video_id`.
6. Verify: import the models in a Python shell and confirm no import errors. Check that the migration file has valid `upgrade()` and `downgrade()` functions.

## Must-Haves

- [ ] `VideoConsent` model with unique constraint on `source_video_id`
- [ ] `ConsentAuditLog` model with `version` column
- [ ] `ConsentField` enum for field name validation
- [ ] Alembic migration `017` with upgrade and downgrade
- [ ] All timestamps use `_now()` helper (KNOWLEDGE: asyncpg rejects timezone-aware datetimes)

## Verification

- `cd backend && python -c "from models import VideoConsent, ConsentAuditLog, ConsentField; print('OK')"` exits 0
- `python -c "import importlib.util; spec = importlib.util.spec_from_file_location('m', 'alembic/versions/017_add_consent_tables.py'); mod = importlib.util.module_from_spec(spec)"` — migration file is valid Python

## Negative Tests

- **Boundary conditions**: unique constraint on `source_video_id` prevents duplicate consent records per video

## Inputs

- `backend/models.py` — existing model patterns to follow
- `alembic/versions/016_add_users_and_invite_codes.py` — migration pattern to follow

## Expected Output

- `backend/models.py` — updated with VideoConsent, ConsentAuditLog, ConsentField
- `alembic/versions/017_add_consent_tables.py` — new migration file

## Inputs

- `backend/models.py`
- `alembic/versions/016_add_users_and_invite_codes.py`

## Expected Output

- `backend/models.py`
- `alembic/versions/017_add_consent_tables.py`

## Verification

cd backend && python -c "from models import VideoConsent, ConsentAuditLog, ConsentField; print('OK')"
