video-accessibility/docs/project/infrastructure.md
Vadym Samoilenko 2f4925353a feat(pause-insert): adaptive buffer, forward-snap, timeline drag + share link fix
Backend (Phase A):
- A1: Adaptive silence buffer — natural_gap_ms persisted per cue; renderer computes
  per-cue silence_before/silence_after instead of fixed 500ms; per-cue silence files
- A2: Forward-preferred snap — snap_pause_point prefers boundaries up to 4s ahead
  over boundaries within 1.5s behind, reducing mid-scene cuts
- A3: Min-gap validation — pause points with < 200ms gap trigger forward search
  to the next acceptable gap
- natural_gap_ms added to PausePointData model and api.ts type
- New config fields: whisper_snap_forward_window, whisper_snap_backward_window,
  ad_silence_buffer_default, ad_silence_buffer_min_after, ad_min_acceptable_gap
- Tests: test_whisper_snap.py (13 tests), test_video_renderer_buffers.py

Frontend (Phase B):
- B1: Drag pause-point markers — pointer state machine with 3px move threshold,
  clamp to min/max bounds, click-without-move still opens PausePointEditor
- B2: Drag freeze blocks — orange blocks translate with linked pause point
- B3: Time tooltip visible during drag, hidden on release
- Tests: TimelinePreview.drag.test.tsx (10 tests)

Fixes:
- Share link pointed to ai-sandbox.oliver.solutions — added app_url to Settings
  with correct optical-dev.oliver.solutions default; share_url now configurable
  via APP_URL env var
- Removed all ai-sandbox.oliver.solutions references from docker-compose,
  apache config, docs, and scripts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 16:09:09 +01:00

172 lines
6.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Infrastructure — Accessible Video Processing Platform
<!-- SCOPE: Declarative inventory of what is deployed and where — servers, services, ports, external dependencies. No procedures (see runbook.md). -->
<!-- DOC_KIND: explanation -->
<!-- DOC_ROLE: canonical -->
<!-- READ_WHEN: Read when you need to know what runs where, which ports are exposed, or which external services are used. -->
<!-- SKIP_WHEN: Skip when you need deployment steps → runbook.md; API contracts → api_spec.md. -->
<!-- PRIMARY_SOURCES: docker-compose.yml, backend/app/core/config.py -->
**Generated:** 2026-05-01
---
## Quick Navigation
- [Docs Hub](../README.md)
- [Runbook](runbook.md)
- [Architecture](architecture.md)
- [Tech Stack](tech_stack.md)
## Agent Entry
| Signal | Value |
|--------|-------|
| Purpose | Inventory of servers, Docker services, ports, and external dependencies |
| Read When | You need to know what runs where, port mappings, or external service dependencies |
| Skip When | You need how-to deploy → runbook.md; API contracts → api_spec.md |
| Canonical | Yes |
| Next Docs | [Runbook](runbook.md), [Architecture](architecture.md) |
| Primary Sources | `docker-compose.yml`, `.env.example` |
---
## Server Inventory
| Server | Role | Environment |
|--------|------|-------------|
| `optical-web-1` | Production host — runs all Docker services | Production |
| Local machine | Developer workstation — Docker Compose local stack | Development |
**Production URL:** `https://optical-dev.oliver.solutions/video-accessibility`
**Production API URL:** `https://optical-dev.oliver.solutions/video-accessibility-back`
---
## Docker Services
All services are defined in `docker-compose.yml` and share the `accessible-video-network` bridge network.
| Service | Image / Build | Container Name | Purpose |
|---------|--------------|----------------|---------|
| `mongodb` | `mongo:7.0` | `accessible-video-mongodb` | Primary database |
| `redis` | `redis:7-alpine` | `accessible-video-redis` | Celery broker + result backend |
| `api` | `./backend` (target: `api`) | `accessible-video-api` | FastAPI REST + WebSocket |
| `worker` | `./backend` (target: `worker`) | `accessible-video-worker` | Celery: default, ingest, notify, render queues |
| `tts-worker` | `./backend` (target: `worker`) | `accessible-video-tts-worker` | Celery: tts queue |
| `ffmpeg-worker` | `./backend` (target: `worker`) | `accessible-video-ffmpeg-worker` | Celery: ffmpeg queue |
| `whisper-worker` | `./backend` (target: `whisper-worker`) | `accessible-video-whisper-worker` | Celery: whisper queue |
---
## Port Allocation
| Service | Internal Port | External Port | Notes |
|---------|--------------|---------------|-------|
| `api` | 8000 | **8012** | Exposed to host |
| `mongodb` | 27017 | — | Internal only |
| `redis` | 6379 | — | Internal only |
| Workers | — | — | No HTTP port |
Production: nginx reverse-proxies `optical-web-1:8012``https://optical-dev.oliver.solutions/video-accessibility-back`.
---
## Worker Configuration
| Worker | Celery Queues | Concurrency | Memory Limit | Notes |
|--------|--------------|-------------|--------------|-------|
| `worker` | `default, ingest, notify, render` | `${WORKER_CONCURRENCY:-8}` | — | General pipeline |
| `tts-worker` | `tts` | `${TTS_WORKER_CONCURRENCY:-2}` | — | Configurable via env |
| `ffmpeg-worker` | `ffmpeg` | `${FFMPEG_WORKER_CONCURRENCY:-1}` | — | CPU-bound; 1 local, higher in Cloud Run mode |
| `whisper-worker` | `whisper` | `${WHISPER_WORKER_CONCURRENCY:-1}` | **8 GB** (4 GB reserved) | RAM-bound; Whisper large-v3 needs ~46 GB |
Cloud Run offload: when `FFMPEG_SERVICE_URL` or `WHISPER_SERVICE_URL` are set, the respective workers delegate to Cloud Run HTTP endpoints instead of running locally.
---
## Volumes
| Volume Name | Mounted In | Purpose |
|-------------|-----------|---------|
| `accessible-video-mongodb-data` | mongodb `/data/db` | MongoDB data |
| `accessible-video-mongodb-config` | mongodb `/data/configdb` | MongoDB config |
| `accessible-video-redis-data` | redis `/data` | Redis AOF persistence |
| `accessible-video-api-logs` | api `/app/logs` | API log files |
| `accessible-video-worker-logs` | worker `/app/logs` | Worker log files |
| `accessible-video-tts-worker-logs` | tts-worker `/app/logs` | TTS worker logs |
| `accessible-video-ffmpeg-worker-logs` | ffmpeg-worker `/app/logs` | FFmpeg worker logs |
| `accessible-video-whisper-worker-logs` | whisper-worker `/app/logs` | Whisper worker logs |
| `accessible-video-shared-tmp` | worker, tts/ffmpeg/whisper workers `/shared-tmp` | Shared temp dir for FFmpeg operations |
| `./secrets` (bind mount) | all services `/secrets:ro` | GCP credentials JSON |
---
## External Dependencies
| Service | Purpose | Config Key |
|---------|---------|------------|
| Google Cloud Storage | Video files, VTT, MP3, rendered video | `GCS_BUCKET`, `GOOGLE_APPLICATION_CREDENTIALS` |
| MongoDB Atlas | Production database (can also run local container) | `MONGODB_URI`, `MONGODB_DB` |
| Gemini 2.5 Pro | VTT generation, translation | `GEMINI_API_KEY` |
| Google Cloud Translate | Language translation | `TRANSLATE_API_KEY` |
| Google Cloud TTS | Audio description synthesis | `GOOGLE_TTS_CREDENTIALS` |
| ElevenLabs | Premium TTS synthesis | `ELEVENLABS_API_KEY` |
| SendGrid | Transactional email (notifications, delivery) | `SENDGRID_API_KEY` |
| Azure AD / Microsoft MSAL | SSO authentication | `AZURE_CLIENT_ID`, `AZURE_AUTHORITY`, `AZURE_REDIRECT_URI` |
| Sentry | Error tracking and alerting | `SENTRY_DSN` |
| OpenTelemetry / OTLP | Distributed tracing | `OTEL_EXPORTER_OTLP_ENDPOINT` |
| AI Cost Tracker | Cross-project AI cost tracking (optical-dev) | `COST_TRACKER_BASE_URL`, `COST_TRACKER_API_KEY` |
| Google Cloud Run (optional) | Offload FFmpeg and Whisper workloads | `FFMPEG_SERVICE_URL`, `WHISPER_SERVICE_URL` |
---
## Health Checks
| Service | Check | Interval |
|---------|-------|---------|
| `mongodb` | TCP port 27017 check | 60s (10s timeout, 3 retries) |
| `redis` | `redis-cli ping` | 30s (10s timeout, 3 retries) |
| `api` | Depends on mongodb + redis healthy | — |
| Workers | Depend on mongodb + redis healthy | — |
Admin health endpoint: `GET /api/v1/admin/health/detailed` (requires admin Bearer token).
---
## Redis Configuration
```text
maxmemory 2gb
maxmemory-policy allkeys-lru
appendonly yes
```
---
## Log Rotation
All services use Docker `json-file` logging:
```text
max-size: 10m
max-file: 3
```
---
## Maintenance
**Last Updated:** 2026-05-01
**Update Triggers:**
- New service added to `docker-compose.yml`
- Port mapping changes
- New external dependency added
- Worker queue or concurrency configuration changes
**Verification:**
- [ ] All services in `docker-compose.yml` listed
- [ ] Port table matches `ports:` sections in compose file
- [ ] External dependencies match env vars in `.env.example`
- [ ] Volume names match `volumes:` section in compose file