Spaces:
Sleeping
Sleeping
| # MediaRouter production deployment gate | |
| ## Deployment contract | |
| The only backend production target is a Hugging Face Docker Space. The root | |
| README declares `sdk: docker` and `app_port: 7860`; the single production | |
| `Dockerfile` uses `python:3.10-slim`, installs the pinned `requirements.txt`, | |
| runs as UID 1000, exposes port 7860, and starts one Uvicorn process on | |
| `0.0.0.0:7860`. Android/Termux Python is not part of this contract. | |
| `APP_ENVIRONMENT=production` is set by the image. Production configuration is | |
| validated when FastAPI is imported, before a database engine starts serving | |
| requests. Local development retains the existing SQLite defaults because it | |
| uses `APP_ENVIRONMENT=development`. | |
| ## Required Hugging Face configuration | |
| Configure secrets in the Space settings, never in source or Docker layers. | |
| Values below are illustrative and are not usable credentials. | |
| ```env | |
| DATABASE_URL=postgresql+asyncpg://<security-role>:<password>@<host>/<database> | |
| SECURITY_DATABASE_ROLE=mediarouter_security_service | |
| SECURITY_ENFORCE_RLS=true | |
| SECURITY_AUTO_MIGRATE=false | |
| AUTH_ENABLED=true | |
| CORS_ALLOWED_ORIGINS=https://<vercel-project>.vercel.app | |
| BASE_URL=https://<owner>-<space>.hf.space | |
| SOCIAL_AUTO_MIGRATE=false | |
| ``` | |
| `DATABASE_URL` must be external PostgreSQL/Supabase and must authenticate as | |
| the configured backend-only security role. SQLite and localhost database URLs | |
| are rejected in production. The security role must have the role attributes | |
| required by the existing forced-RLS execution-boundary check. | |
| When `SOCIAL_ENABLED=true`, also configure the existing separated RLS roles: | |
| ```env | |
| SOCIAL_DATABASE_URL=postgresql+asyncpg://<tenant-role>:<password>@<host>/<database> | |
| SOCIAL_TENANT_DATABASE_ROLE=mediarouter_tenant | |
| SOCIAL_WORKER_DATABASE_URL=postgresql+asyncpg://<worker-role>:<password>@<host>/<database> | |
| SOCIAL_WORKER_DATABASE_ROLE=mediarouter_social_worker | |
| SOCIAL_ENFORCE_RLS=true | |
| ``` | |
| The tenant connection must be non-owner/non-superuser/non-`BYPASSRLS`; the | |
| worker connection must be the explicitly named backend-only `BYPASSRLS` role. | |
| Set `SOCIAL_ENABLED=false` when deploying only core/project APIs and those | |
| social database boundaries have not been provisioned. Missing YouTube, Meta, | |
| TikTok, X, LinkedIn, Telegram, or WhatsApp provider credentials do not prevent | |
| startup. Their adapters report controlled unavailability when invoked. | |
| WAN and FLUX are also optional. Leaving their URL/token pairs empty keeps them | |
| unavailable. Invalid optional worker identity/readiness never makes a model | |
| available and does not stop FastAPI. | |
| `CORS_ALLOWED_ORIGINS` is a comma-separated list of exact origins. Production | |
| requires HTTPS and rejects `*`, credentials embedded in URLs, paths, query | |
| strings, and fragments. Add every Vercel origin that is allowed to call the | |
| backend directly. The normal frontend path remains its same-origin server-side | |
| BFF, so backend keys are never exposed to browsers. | |
| ## Explicit migration order | |
| Normal application startup never applies PostgreSQL migrations. Use a | |
| controlled administrative migration connection and apply the additive files | |
| in this dependency order before starting the Space: | |
| 1. `app/security/migrations/0001_api_key_security.sql` | |
| 2. `app/security/migrations/0002_authoritative_tenancy_postgres.sql` | |
| 3. `app/projects/migrations/0001_projects_foundation.sql` | |
| 4. `app/security/migrations/0003_generation_domain_postgres.sql` | |
| 5. `app/security/migrations/0004_generation_provider_runtime_postgres.sql` | |
| 6. `app/projects/migrations/0002_project_resources.sql` | |
| 7. `app/projects/migrations/0003_editor_persistence_rendering.sql` | |
| 8. `app/projects/migrations/0004_ai_studio.sql` | |
| 9. `app/projects/migrations/0005_ai_copilot.sql` | |
| 10. `app/projects/migrations/0006_template_marketplace.sql` | |
| 11. `app/social/migrations/0001_social_foundation_postgres.sql` | |
| 12. `app/social/migrations/0002_social_rls.sql` | |
| 13. `app/social/migrations/0003_social_integrity_postgres.sql` | |
| 14. `app/social/migrations/0004_youtube_media_assets.sql` | |
| 15. `app/social/migrations/0005_x_text_posts.sql` | |
| 16. `app/social/migrations/0006_linkedin_oauth_account_type.sql` | |
| 17. `app/social/migrations/0007_tenant_asset_and_rls_hardening.sql` | |
| Keep `SECURITY_AUTO_MIGRATE=false` and `SOCIAL_AUTO_MIGRATE=false`. The | |
| security startup gate checks tables and safety indexes. It then verifies the | |
| configured PostgreSQL execution role before generation, projects, workers, or | |
| social scheduling can serve traffic. | |
| ## Health, readiness, and startup failure behavior | |
| `GET /health` is public and process-level. It reports only safe dependency | |
| availability and version metadata; external AI credentials are not required. | |
| The Docker health check calls it over `127.0.0.1:7860` from inside the | |
| container. | |
| The authoritative security database and complete migrated security/project | |
| schema are required for startup. A missing connection, missing schema object, | |
| or invalid RLS role produces a clear startup failure. Social database/provider | |
| failures are contained by the existing social readiness boundary; social APIs | |
| then return controlled unavailability. Generation providers are initialized | |
| lazily by the bounded background dispatcher. Cleanup, generation, and social | |
| workers respect cancellation, catch iteration failures, and cannot enter tight | |
| retry loops. | |
| ## Filesystem lifecycle | |
| `TEMP_DIR` and `OUTPUT_DIR` contain bounded working files and expiring media | |
| outputs. They are not durable merely because their metadata is in PostgreSQL. | |
| The cleanup service removes them after `CLEANUP_MINUTES`, and container rebuilds | |
| may remove them sooner. If an installation needs media bytes beyond that | |
| lifecycle, attach Hugging Face persistent storage and point the directories at | |
| its mounted path, or implement/configure an authoritative object-storage | |
| adapter in a separate storage phase. The current deployment gate does not | |
| claim durable object storage. | |
| ## Docker smoke gate | |
| Create a non-committed production env file whose database has already received | |
| the migrations, then run: | |
| ```bash | |
| scripts/docker_deployment_gate.sh /absolute/path/production.env | |
| ``` | |
| Optionally pass a disposable API key as the second argument to validate an | |
| authenticated `GET /v1/auth/context`. Without a key, the smoke test requires | |
| that endpoint to fail closed with HTTP 401. The gate: | |
| 1. builds the actual root Dockerfile; | |
| 2. starts it with the supplied production environment; | |
| 3. waits for Docker health; | |
| 4. checks `/health` and `/openapi.json`; | |
| 5. verifies every project and project-resource operation in runtime OpenAPI; | |
| 6. verifies social and generation route families; | |
| 7. verifies authentication middleware; and | |
| 8. proves that the container remains alive. | |
| The HTTP portion can also target a deployed Space: | |
| ```bash | |
| python3 scripts/deployment_smoke.py \ | |
| --base-url https://<owner>-<space>.hf.space \ | |
| --api-key '<disposable-test-key>' | |
| ``` | |
| The script never prints the key. Do not use a production administrator key in | |
| shared CI logs or shell history. | |
| ## Vercel frontend | |
| Set the Vercel server-only `MEDIAROUTER_API_URL` to the Space HTTPS origin. | |
| `MEDIAROUTER_MCP_URL` may use the same origin. In Vercel production, | |
| `backendBaseUrl()` rejects HTTP and loopback/localhost upstreams. Browser calls | |
| continue to use `/api/backend/*`, where the authenticated BFF attaches only a | |
| server-side role credential. OpenAPI project capability discovery therefore | |
| uses the real runtime backend and requires no frontend override. | |
| ## Operator acceptance gate | |
| Do not mark the Space ready from source inspection alone. Acceptance requires | |
| an actual Docker build, live container startup, `0.0.0.0:7860` binding, health | |
| response, and runtime OpenAPI response using production Python 3.10/Linux. A | |
| host without Docker and an accessible migrated PostgreSQL database must report | |
| these checks as blocked, not passed. | |