Spaces:
Running
Running
|
Download docs/deployment.md from Benaah/MicProtocol: direct link, hf CLI and curl.
- Browser
- Download file 7.67 kB
-
https://huggingface.co/spaces/Benaah/MicProtocol/resolve/main/docs/deployment.md
- Command line
-
hf download hf://spaces/Benaah/MicProtocol/docs/deployment.md
-
curl -L -o deployment.md https://huggingface.co/spaces/Benaah/MicProtocol/resolve/main/docs/deployment.md
7.67 kB
| # MicProtocol – Deployment & Scaling Strategy | |
| ## Deployment Architecture | |
| ```mermaid | |
| graph LR | |
| subgraph "Vercel Edge" | |
| WEB[Next.js Web App] | |
| PORTAL[Guest Portal] | |
| end | |
| subgraph "AWS ECS/Fargate" | |
| API[NestJS API] | |
| WORKER[Background Workers] | |
| CLIP_SCORER[CLIP Scorer<br/>Python + ML] | |
| end | |
| subgraph "Managed Services" | |
| DB[RDS PostgreSQL] | |
| CACHE[ElastiCache Redis] | |
| SEARCH[Meilisearch Cloud] | |
| OBJ[Cloudflare R2] | |
| end | |
| subgraph "CI/CD" | |
| GHA[GitHub Actions] | |
| TURBO[Turborepo Cache] | |
| end | |
| GHA -->|Docker Build| API | |
| GHA -->|Deploy| WEB | |
| WEB -->|tRPC| API | |
| API --> DB | |
| WORKER --> DB | |
| WORKER --> CACHE | |
| WORKER -->|subprocess| CLIP_SCORER | |
| CLIP_SCORER --> DB | |
| ``` | |
| ## Production Stacks (Coolify / Render) | |
| Beyond the ECS layout above, the repo ships two ready-to-deploy production | |
| blueprints that include the Erlang/OTP real-time engine (`mic-realtime`). | |
| ### Coolify (`docker-compose.coolify.yml`) | |
| Full self-hosted stack: Postgres, Redis, API, worker, **mic-realtime**, web, | |
| admin, and the self-hosted integration fleet. Caddy terminates TLS (wildcard | |
| cert via DNS-01) and routes: | |
| | Host | Upstream | | |
| |---|---| | |
| | `<root>` / `*.` (workspace subdomains) | web :3000 | | |
| | `api.<root>` | api :4000 | | |
| | `admin.<root>` | admin :3000 | | |
| | `realtime.<root>` | mic-realtime :4001 (WebSocket) | | |
| ### Render (`render.yaml`) | |
| Backend-only blueprint (web + admin deploy on Vercel): | |
| - `micprotocol-api` — NestJS API | |
| - `micprotocol-redis` — Redis add-on | |
| - `micprotocol-realtime` — Erlang/OTP engine (`env: docker`, | |
| `rootDir: services/mic-realtime`, health at `/healthz`) | |
| ### Real-time engine & required secrets | |
| The `mic-realtime` service is a first-class citizen of both stacks and ships | |
| **fail-closed**: both it and the API (`RealtimeClient` in | |
| `apps/api/src/chat/realtime.client.ts`) refuse to boot in production when the | |
| secrets are missing or equal to the known defaults. | |
| | Env var | Required | Notes | | |
| |---|---|---| | |
| | `MIC_REALTIME_INTERNAL_TOKEN` | ✅ | Bearer used by the API to publish events via `/internal/dispatch` | | |
| | `MIC_REALTIME_SHARED_SECRET` | ✅ | HMAC secret for WebSocket auth tokens | | |
| | `MIC_REALTIME_PUBLIC_URL` | ✅ | Browser-facing `wss://realtime.<root>` URL; forwarded to web/admin as `NEXT_PUBLIC_MIC_REALTIME_URL` | | |
| | `MIC_REALTIME_URL` | API only | API→realtime base URL (Coolify default `http://mic-realtime:4001`) | | |
| Generate both secrets with `openssl rand -hex 32` and set | |
| `MIC_REALTIME_PUBLIC_URL` to a `wss://` URL **before first boot** — the | |
| services will not start with missing or default values. | |
| ## Environment Strategy | |
| | Environment | Web Frontend | API Backend | Database | | |
| |-------------|-------------|-------------|----------| | |
| | **Development** | `localhost:3000` | `localhost:4000` | Local PostgreSQL | | |
| | **Preview** | Vercel Preview | ECS Staging | RDS Staging | | |
| | **Production** | Vercel Edge | ECS Production | RDS Multi-AZ | | |
| ## Scaling Triggers | |
| ### < 1,000 Podcasts (Startup Phase) | |
| - Single ECS task for API + Workers | |
| - Shared Redis instance (ElastiCache `t3.micro`) | |
| - Cloudflare R2 for all media storage | |
| - Single PostgreSQL instance (RDS `db.t3.medium`) | |
| ### > 1,000 Podcasts (Growth Phase) | |
| - Split Workers into separate ECS service | |
| - Dedicated Redis for BullMQ vs. caching | |
| - Read replicas for PostgreSQL | |
| - CDN for static assets | |
| - Migrate complex workflows to **Temporal.io** | |
| ### > 10,000 Podcasts (Scale Phase) | |
| - Extract Outreach Domain into standalone microservice | |
| - Outreach gets own MongoDB cluster (high write volume on email events) | |
| - Event bus (AWS SNS/SQS) for cross-service communication | |
| - Meilisearch cluster for search scaling | |
| - Multi-region deployment for global guest portal latency | |
| ## CI/CD Pipeline | |
| ```mermaid | |
| flowchart TD | |
| PUSH[Git Push] --> LINT[Lint & Type Check] | |
| LINT --> TEST[Unit Tests] | |
| TEST --> BUILD[Turbo Build] | |
| BUILD --> |Main Branch| DEPLOY_STAGING[Deploy to Staging] | |
| BUILD --> |Release Tag| DEPLOY_PROD[Deploy to Production] | |
| BUILD --> |PR| PREVIEW[Vercel Preview] | |
| DEPLOY_STAGING --> INTEGRATION[Integration Tests] | |
| INTEGRATION --> |Pass| PROMOTE[Promote to Production] | |
| DEPLOY_PROD --> MIGRATE[Run DB Migrations] | |
| MIGRATE --> HEALTH[Health Checks] | |
| HEALTH --> |Healthy| COMPLETE([Deployment Complete]) | |
| HEALTH --> |Unhealthy| ROLLBACK[Automatic Rollback] | |
| ``` | |
| ## Infrastructure Configuration | |
| ### Docker (API) | |
| ```dockerfile | |
| FROM node:20-alpine AS base | |
| RUN corepack enable && corepack prepare pnpm@9.15.0 --activate | |
| FROM base AS deps | |
| WORKDIR /app | |
| COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./ | |
| COPY apps/api/package.json apps/api/ | |
| COPY packages/shared-types/package.json packages/shared-types/ | |
| RUN pnpm install --frozen-lockfile | |
| FROM base AS build | |
| WORKDIR /app | |
| COPY --from=deps /app/node_modules ./node_modules | |
| COPY . . | |
| RUN pnpm --filter @micprotocol/api prisma generate | |
| RUN pnpm --filter @micprotocol/api build | |
| FROM base AS runtime | |
| WORKDIR /app | |
| COPY --from=build /app/apps/api/dist ./dist | |
| COPY --from=build /app/node_modules ./node_modules | |
| COPY --from=build /app/apps/api/prisma ./prisma | |
| RUN apk add --no-cache ffmpeg | |
| EXPOSE 4000 | |
| CMD ["node", "dist/main.js"] | |
| ``` | |
| ### Docker (CLIP Scorer) | |
| Canonical source of truth is `services/clip-scorer/Dockerfile`. It builds a one-shot CLI image: | |
| ```dockerfile | |
| FROM python:3.11-slim AS base | |
| RUN apt-get update && apt-get install -y --no-install-recommends ffmpeg && rm -rf /var/lib/apt/lists/* | |
| COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv | |
| WORKDIR /app | |
| RUN uv venv /opt/venv \ | |
| && VIRTUAL_ENV=/opt/venv uv pip install --index-url https://download.pytorch.org/whl/cpu "torch>=2.0.0" \ | |
| && VIRTUAL_ENV=/opt/venv uv pip install "open-clip-torch>=2.20.0" "transformers>=4.30.0" "Pillow>=10.0.0" "soundfile>=0.12.0" "pyloudnorm>=0.1.0" "numpy>=1.24.0" | |
| ENV PATH="/opt/venv/bin:$PATH" | |
| RUN python3 -c "import open_clip; open_clip.create_model_and_transforms('ViT-B-32', pretrained='laion2b_s34b_b79k')" | |
| COPY scoring/ scoring/ | |
| COPY pipeline.py . | |
| ENTRYPOINT ["python3", "pipeline.py"] | |
| ``` | |
| In production the same Python stack is baked into the **worker** image (`apps/api/Dockerfile`), where the BullMQ clip-scoring processor executes the pipeline via `execFile`. | |
| ### Docker Compose Configuration | |
| The worker service requires `ipc: host` for `/dev/shm` access (needed by ffmpeg shared memory). CLIP scoring runs inside the worker as a subprocess of the processor — there is no separate clip-scorer container or shared volume: | |
| ```yaml | |
| worker: | |
| container_name: micprotocol-worker | |
| command: node /app/apps/api/dist/main.js | |
| ipc: host | |
| deploy: | |
| resources: | |
| limits: | |
| cpus: "2" | |
| memory: 2G | |
| ``` | |
| ### Scaling Considerations for CLIP Scorer | |
| | Metric | Value | Notes | | |
| |--------|-------|-------| | |
| | CPU per clip | ~0.5 cores | ~30–120s for CLIP inference (CPU) | | |
| | Memory per clip | ~1.5GB | CLIP model + frame buffers | | |
| | Concurrent clips | 2 per worker (set in processor) | Bump cautiously — Python ML is memory-heavy | | |
| | Horizontal scaling | Add worker containers | Each container handles 2 concurrent clips | | |
| | GPU acceleration | Optional | CLIP runs on CPU by default; GPU cuts time by 5-10x | | |
| ## Security | |
| - **GDPR/CCPA**: Right-to-erasure cascading through all related records | |
| - **Email Compliance**: CAN-SPAM footer injection, automatic unsubscribe | |
| - **Data Isolation**: Row-level scoping through workspace → podcast hierarchy | |
| - **Upload Security**: Presigned URLs (15-min expiry), MIME verification, virus scanning | |
| - **Auth**: Clerk JWT verification with workspace-scoped claims | |