mirror of
https://github.com/Monadical-SAS/reflector.git
synced 2025-12-21 20:59:05 +00:00
490 lines
15 KiB
Markdown
490 lines
15 KiB
Markdown
# Daily.co Implementation Guide
|
|
|
|
## Overview
|
|
Implement multi-provider video platform support (Whereby + Daily.co) following PLAN.md.
|
|
|
|
## Reference Code Location
|
|
- **Reference branch:** `origin/igor/feat-dailyco` (on remote)
|
|
- **Worktree location:** `./reflector-dailyco-reference/`
|
|
- **Status:** Reference only - DO NOT merge or copy directly
|
|
|
|
## What Exists in Reference Branch (For Inspiration)
|
|
|
|
### ✅ Can Use As Reference (Well-Implemented)
|
|
```
|
|
server/reflector/video_platforms/
|
|
├── base.py ← Platform abstraction (good design, copy-safe)
|
|
├── models.py ← Data models (copy-safe)
|
|
├── registry.py ← Registry pattern (copy-safe)
|
|
├── factory.py ← Factory pattern (needs settings updates)
|
|
├── whereby.py ← Whereby client (needs adaptation)
|
|
├── daily.py ← Daily.co client (needs adaptation)
|
|
└── mock.py ← Mock client (copy-safe for tests)
|
|
|
|
server/reflector/views/daily.py ← Webhook handler (needs adaptation)
|
|
server/tests/test_video_platforms.py ← Tests (good reference)
|
|
server/tests/test_daily_webhook.py ← Tests (good reference)
|
|
|
|
www/app/[roomName]/components/
|
|
├── RoomContainer.tsx ← Platform router (needs React Query)
|
|
├── DailyRoom.tsx ← Daily component (needs React Query)
|
|
└── WherebyRoom.tsx ← Whereby extraction (needs React Query)
|
|
```
|
|
|
|
### ⚠️ Needs Significant Changes (Use Logic Only)
|
|
- `server/reflector/db/rooms.py` - Reference removed calendar/webhook fields that main has
|
|
- `server/reflector/db/meetings.py` - Same issue (missing user_id handling differences)
|
|
- `server/reflector/views/rooms.py` - Main has calendar integration, webhooks, ICS sync
|
|
- `server/reflector/worker/process.py` - Main has different recording flow
|
|
- Migration files - Must regenerate against current main schema
|
|
|
|
### ❌ Do NOT Use (Outdated/Incompatible)
|
|
- `package.json`/`pnpm-lock.yaml` - Main uses different dependency versions
|
|
- Frontend API client calls - Main uses React Query (reference uses old OpenAPI client)
|
|
- Database migrations - Must create new ones from scratch
|
|
- Any files that delete features present in main (search, calendar, webhooks)
|
|
|
|
## Key Differences: Reference vs Current Main
|
|
|
|
| Aspect | Reference Branch | Current Main | Action Required |
|
|
|--------|------------------|--------------|-----------------|
|
|
| **API client** | Old OpenAPI generated | React Query hooks | Rewrite all API calls |
|
|
| **Database schema** | Simplified (removed features) | Has calendar, webhooks, full-text search | Merge carefully, preserve main features |
|
|
| **Settings** | Aug 2025 structure | Current structure | Adapt carefully |
|
|
| **Migrations** | Branched from Aug 1 | Current main (91+ commits ahead) | Regenerate from scratch |
|
|
| **Frontend deps** | `@daily-co/daily-js@0.81.0` | Check current versions | Update to compatible versions |
|
|
| **Package manager** | yarn | pnpm (maybe both?) | Use what main uses |
|
|
|
|
## Branch Divergence Analysis
|
|
|
|
**The reference branch is 91 commits behind main and severely diverged:**
|
|
- Reference: 8 commits, 3,689 insertions, 425 deletions
|
|
- Main since divergence: 320 files changed, 45,840 insertions, 16,827 deletions
|
|
- **Main has 12x more changes**
|
|
|
|
**Major features in main that reference lacks:**
|
|
1. Calendar integration (ICS sync with rooms)
|
|
2. Self-hosted GPU API infrastructure
|
|
3. Frontend OpenAPI React Query migration
|
|
4. Full-text search (backend + frontend)
|
|
5. Webhook system for room events
|
|
6. Environment variable migration
|
|
7. Security fixes and auth improvements
|
|
8. Docker production frontend
|
|
9. Meeting user ID removal (schema change)
|
|
10. NextJS version upgrades
|
|
|
|
**High conflict risk files:**
|
|
- `server/reflector/views/rooms.py` - 12x more changes in main
|
|
- `server/reflector/db/rooms.py` - Main added 7+ fields
|
|
- `www/package.json` - NextJS major version bump
|
|
- Database migrations - 20+ new migrations in main
|
|
|
|
## Implementation Approach
|
|
|
|
### Phase 1: Copy Clean Abstractions (1-2 hours)
|
|
|
|
**Files to copy directly from reference:**
|
|
```bash
|
|
# Core abstraction (review but mostly safe to copy)
|
|
cp -r reflector-dailyco-reference/server/reflector/video_platforms/ \
|
|
server/reflector/
|
|
|
|
# BUT review each file for:
|
|
# - Import paths (make sure they match current main)
|
|
# - Settings references (adapt to current settings.py)
|
|
# - Type imports (ensure no circular dependencies)
|
|
```
|
|
|
|
**After copying, immediately:**
|
|
```bash
|
|
cd server
|
|
# Check for issues
|
|
uv run ruff check reflector/video_platforms/
|
|
# Fix any import errors or type issues
|
|
```
|
|
|
|
### Phase 2: Adapt to Current Main (2-3 hours)
|
|
|
|
**2.1 Settings Integration**
|
|
|
|
File: `server/reflector/settings.py`
|
|
|
|
Add at the appropriate location (near existing Whereby settings):
|
|
|
|
```python
|
|
# Daily.co API Integration (NEW)
|
|
DAILY_API_KEY: str | None = None
|
|
DAILY_WEBHOOK_SECRET: str | None = None
|
|
DAILY_SUBDOMAIN: str | None = None
|
|
AWS_DAILY_S3_BUCKET: str | None = None
|
|
AWS_DAILY_S3_REGION: str = "us-west-2"
|
|
AWS_DAILY_ROLE_ARN: str | None = None
|
|
|
|
# Platform Migration Feature Flags (NEW)
|
|
DAILY_MIGRATION_ENABLED: bool = False # Conservative default
|
|
DAILY_MIGRATION_ROOM_IDS: list[str] = []
|
|
DEFAULT_VIDEO_PLATFORM: Literal["whereby", "daily"] = "whereby"
|
|
```
|
|
|
|
**2.2 Database Migration**
|
|
|
|
⚠️ **CRITICAL: Do NOT copy migration from reference**
|
|
|
|
Generate new migration:
|
|
```bash
|
|
cd server
|
|
uv run alembic revision -m "add_platform_support"
|
|
```
|
|
|
|
Edit the generated migration file to add `platform` column:
|
|
```python
|
|
def upgrade():
|
|
with op.batch_alter_table("room", schema=None) as batch_op:
|
|
batch_op.add_column(
|
|
sa.Column("platform", sa.String(), nullable=False, server_default="whereby")
|
|
)
|
|
|
|
with op.batch_alter_table("meeting", schema=None) as batch_op:
|
|
batch_op.add_column(
|
|
sa.Column("platform", sa.String(), nullable=False, server_default="whereby")
|
|
)
|
|
```
|
|
|
|
**2.3 Update Database Models**
|
|
|
|
File: `server/reflector/db/rooms.py`
|
|
|
|
Add platform field (preserve all existing fields from main):
|
|
```python
|
|
from typing import TYPE_CHECKING
|
|
|
|
if TYPE_CHECKING:
|
|
from reflector.video_platforms.models import Platform
|
|
|
|
class Room:
|
|
# ... ALL existing fields from main (calendar, webhooks, etc.) ...
|
|
|
|
# NEW: Platform field
|
|
platform: "Platform" = sqlalchemy.Column(
|
|
sqlalchemy.String,
|
|
nullable=False,
|
|
server_default="whereby",
|
|
)
|
|
```
|
|
|
|
File: `server/reflector/db/meetings.py`
|
|
|
|
Same approach - add platform field, preserve everything from main.
|
|
|
|
**2.4 Integrate Platform Abstraction into rooms.py**
|
|
|
|
⚠️ **This is the most delicate part - main has calendar/webhook features**
|
|
|
|
File: `server/reflector/views/rooms.py`
|
|
|
|
Strategy:
|
|
1. Add imports at top
|
|
2. Modify meeting creation logic only
|
|
3. Preserve all calendar/webhook/ICS logic from main
|
|
|
|
```python
|
|
# Add imports
|
|
from reflector.video_platforms import (
|
|
create_platform_client,
|
|
get_platform_for_room,
|
|
)
|
|
|
|
# In create_meeting endpoint:
|
|
# OLD: Direct Whereby API calls
|
|
# NEW: Platform abstraction
|
|
|
|
# Find the meeting creation section and replace:
|
|
platform = get_platform_for_room(room.id)
|
|
client = create_platform_client(platform)
|
|
|
|
meeting_data = await client.create_meeting(
|
|
room_name_prefix=room.name,
|
|
end_date=meeting_data.end_date,
|
|
room=room,
|
|
)
|
|
|
|
# Then create Meeting record with meeting_data.platform, meeting_data.meeting_id, etc.
|
|
```
|
|
|
|
**2.5 Add Daily.co Webhook Handler**
|
|
|
|
Copy from reference, minimal changes needed:
|
|
```bash
|
|
cp reflector-dailyco-reference/server/reflector/views/daily.py \
|
|
server/reflector/views/
|
|
```
|
|
|
|
Register in `server/reflector/app.py`:
|
|
```python
|
|
from reflector.views import daily
|
|
|
|
app.include_router(daily.router, prefix="/v1/daily", tags=["daily"])
|
|
```
|
|
|
|
**2.6 Add Recording Processing Task**
|
|
|
|
File: `server/reflector/worker/process.py`
|
|
|
|
Add the `process_recording_from_url` task from reference (copy the function).
|
|
|
|
### Phase 3: Frontend Adaptation (3-4 hours)
|
|
|
|
**3.1 Determine Current API Client Pattern**
|
|
|
|
First, check how main currently makes API calls:
|
|
```bash
|
|
cd www
|
|
grep -r "api\." app/ | head -20
|
|
# Look for patterns like: api.v1Something()
|
|
```
|
|
|
|
**3.2 Create Components**
|
|
|
|
Copy component structure from reference but **rewrite all API calls**:
|
|
|
|
```bash
|
|
mkdir -p www/app/[roomName]/components
|
|
```
|
|
|
|
Files to create:
|
|
- `RoomContainer.tsx` - Platform router (mostly copy-safe, just fix imports)
|
|
- `DailyRoom.tsx` - Needs React Query API calls
|
|
- `WherebyRoom.tsx` - Extract current room page logic
|
|
|
|
**Example React Query pattern** (adapt to your actual API):
|
|
```typescript
|
|
import { api } from '@/app/api/client'
|
|
|
|
// In DailyRoom.tsx
|
|
const handleConsent = async () => {
|
|
try {
|
|
await api.v1MeetingAudioConsent({
|
|
path: { meeting_id: meeting.id },
|
|
body: { consent: true },
|
|
})
|
|
// ...
|
|
} catch (error) {
|
|
// ...
|
|
}
|
|
}
|
|
```
|
|
|
|
**3.3 Add Daily.co Dependency**
|
|
|
|
Check current package manager:
|
|
```bash
|
|
cd www
|
|
ls package-lock.json yarn.lock pnpm-lock.yaml
|
|
```
|
|
|
|
Then install:
|
|
```bash
|
|
# If using pnpm
|
|
pnpm add @daily-co/daily-js@^0.81.0
|
|
|
|
# If using yarn
|
|
yarn add @daily-co/daily-js@^0.81.0
|
|
```
|
|
|
|
**3.4 Update TypeScript Types**
|
|
|
|
After backend changes, regenerate types:
|
|
```bash
|
|
cd www
|
|
pnpm openapi # or yarn openapi
|
|
```
|
|
|
|
This should pick up the new `platform` field on Meeting type.
|
|
|
|
### Phase 4: Testing (2-3 hours)
|
|
|
|
**4.1 Copy Test Structure**
|
|
|
|
```bash
|
|
cp reflector-dailyco-reference/server/tests/test_video_platforms.py \
|
|
server/tests/
|
|
|
|
cp reflector-dailyco-reference/server/tests/test_daily_webhook.py \
|
|
server/tests/
|
|
```
|
|
|
|
**4.2 Fix Test Imports and Fixtures**
|
|
|
|
Update imports to match current test infrastructure:
|
|
- Check `server/tests/conftest.py` for fixture patterns
|
|
- Update database access patterns if changed
|
|
- Fix any import errors
|
|
|
|
**4.3 Run Tests**
|
|
|
|
```bash
|
|
cd server
|
|
# Run with environment variables for Mac
|
|
REDIS_HOST=localhost \
|
|
CELERY_BROKER_URL=redis://localhost:6379/1 \
|
|
CELERY_RESULT_BACKEND=redis://localhost:6379/1 \
|
|
uv run pytest tests/test_video_platforms.py -v
|
|
```
|
|
|
|
### Phase 5: Environment Configuration
|
|
|
|
**Update `server/env.example`:**
|
|
|
|
Add at the end:
|
|
```bash
|
|
# Daily.co API Integration
|
|
DAILY_API_KEY=your-daily-api-key
|
|
DAILY_WEBHOOK_SECRET=your-daily-webhook-secret
|
|
DAILY_SUBDOMAIN=your-subdomain
|
|
AWS_DAILY_S3_BUCKET=your-daily-bucket
|
|
AWS_DAILY_S3_REGION=us-west-2
|
|
AWS_DAILY_ROLE_ARN=arn:aws:iam::ACCOUNT:role/DailyRecording
|
|
|
|
# Platform Selection
|
|
DAILY_MIGRATION_ENABLED=false # Master switch
|
|
DAILY_MIGRATION_ROOM_IDS=[] # Specific room IDs
|
|
DEFAULT_VIDEO_PLATFORM=whereby # Default platform
|
|
```
|
|
|
|
## Decision Tree: Copy vs Adapt vs Rewrite
|
|
|
|
```
|
|
┌─ Is it pure abstraction logic? (base.py, registry.py, models.py)
|
|
│ YES → Copy directly, review imports
|
|
│ NO → Continue ↓
|
|
│
|
|
├─ Does it touch database models?
|
|
│ YES → Adapt carefully, preserve main's fields
|
|
│ NO → Continue ↓
|
|
│
|
|
├─ Does it make API calls on frontend?
|
|
│ YES → Rewrite using React Query
|
|
│ NO → Continue ↓
|
|
│
|
|
├─ Is it a database migration?
|
|
│ YES → Generate fresh from current schema
|
|
│ NO → Continue ↓
|
|
│
|
|
└─ Does it touch rooms.py or core business logic?
|
|
YES → Merge carefully, preserve calendar/webhooks
|
|
NO → Safe to adapt from reference
|
|
```
|
|
|
|
## Verification Checklist
|
|
|
|
After each phase, verify:
|
|
|
|
**Phase 1 (Abstraction Layer):**
|
|
- [ ] `uv run ruff check server/reflector/video_platforms/` passes
|
|
- [ ] No circular import errors
|
|
- [ ] Can import `from reflector.video_platforms import create_platform_client`
|
|
|
|
**Phase 2 (Backend Integration):**
|
|
- [ ] `uv run ruff check server/` passes
|
|
- [ ] Migration file generated (not copied)
|
|
- [ ] Room and Meeting models have platform field
|
|
- [ ] rooms.py still has calendar/webhook features
|
|
|
|
**Phase 3 (Frontend):**
|
|
- [ ] `pnpm lint` passes
|
|
- [ ] No TypeScript errors
|
|
- [ ] No `@ts-ignore` for platform field
|
|
- [ ] API calls use React Query patterns
|
|
|
|
**Phase 4 (Testing):**
|
|
- [ ] Tests can be collected: `pytest tests/test_video_platforms.py --collect-only`
|
|
- [ ] Database fixtures work
|
|
- [ ] Mock platform works
|
|
|
|
**Phase 5 (Config):**
|
|
- [ ] env.example has Daily.co variables
|
|
- [ ] settings.py has all new variables
|
|
- [ ] No duplicate variable definitions
|
|
|
|
## Common Pitfalls
|
|
|
|
### 1. Database Schema Conflicts
|
|
**Problem:** Reference removed fields that main has (calendar, webhooks)
|
|
**Solution:** Always preserve main's fields, only add platform field
|
|
|
|
### 2. Migration Conflicts
|
|
**Problem:** Reference migration has wrong `down_revision`
|
|
**Solution:** Always generate fresh migration from current main
|
|
|
|
### 3. Frontend API Calls
|
|
**Problem:** Reference uses old API client patterns
|
|
**Solution:** Check current main's API usage, replicate that pattern
|
|
|
|
### 4. Import Errors
|
|
**Problem:** Circular imports with TYPE_CHECKING
|
|
**Solution:** Use `if TYPE_CHECKING:` for Room/Meeting imports in video_platforms
|
|
|
|
### 5. Test Database Issues
|
|
**Problem:** Tests fail with "could not translate host name 'postgres'"
|
|
**Solution:** Use environment variables: `REDIS_HOST=localhost DATABASE_URL=...`
|
|
|
|
### 6. Preserved Features Broken
|
|
**Problem:** Calendar/webhook features stop working
|
|
**Solution:** Carefully review rooms.py diff, only change meeting creation, not calendar logic
|
|
|
|
## File Modification Summary
|
|
|
|
**New files (can copy):**
|
|
- `server/reflector/video_platforms/*.py` (entire directory)
|
|
- `server/reflector/views/daily.py`
|
|
- `server/tests/test_video_platforms.py`
|
|
- `server/tests/test_daily_webhook.py`
|
|
- `www/app/[roomName]/components/RoomContainer.tsx`
|
|
- `www/app/[roomName]/components/DailyRoom.tsx`
|
|
- `www/app/[roomName]/components/WherebyRoom.tsx`
|
|
|
|
**Modified files (careful merging):**
|
|
- `server/reflector/settings.py` - Add Daily.co settings
|
|
- `server/reflector/db/rooms.py` - Add platform field
|
|
- `server/reflector/db/meetings.py` - Add platform field
|
|
- `server/reflector/views/rooms.py` - Integrate platform abstraction
|
|
- `server/reflector/worker/process.py` - Add process_recording_from_url
|
|
- `server/reflector/app.py` - Register daily router
|
|
- `server/env.example` - Add Daily.co variables
|
|
- `www/app/[roomName]/page.tsx` - Use RoomContainer
|
|
- `www/package.json` - Add @daily-co/daily-js
|
|
|
|
**Generated files (do not copy):**
|
|
- `server/migrations/versions/XXXXXX_add_platform_support.py` - Generate fresh
|
|
|
|
## Success Metrics
|
|
|
|
Implementation is complete when:
|
|
- [ ] All tests pass (including new platform tests)
|
|
- [ ] Linting passes (ruff, pnpm lint)
|
|
- [ ] Migration applies cleanly: `uv run alembic upgrade head`
|
|
- [ ] Can create Whereby meeting (existing flow unchanged)
|
|
- [ ] Can create Daily.co meeting (with env vars set)
|
|
- [ ] Frontend loads without TypeScript errors
|
|
- [ ] No features from main were accidentally removed
|
|
|
|
## Getting Help
|
|
|
|
**Reference documentation locations:**
|
|
- Implementation plan: `PLAN.md`
|
|
- Reference implementation: `./reflector-dailyco-reference/`
|
|
- Current main codebase: `./ ` (current directory)
|
|
|
|
**Compare implementations:**
|
|
```bash
|
|
# Compare specific files
|
|
diff reflector-dailyco-reference/server/reflector/video_platforms/base.py \
|
|
server/reflector/video_platforms/base.py
|
|
|
|
# See what changed in rooms.py between reference branch point and now
|
|
git log --oneline --since="2025-08-01" -- server/reflector/views/rooms.py
|
|
```
|
|
|
|
**Key insight:** The reference branch validates the approach and provides working code patterns, but you're implementing fresh against current main to avoid merge conflicts and preserve all new features.
|