# Generation foundation MediaRouter has a provider-neutral generation domain for image and video workers. The audited optional WAN 2.2 and FLUX.2 Klein integrations are documented in [`generation-wan.md`](generation-wan.md) and [`generation-flux.md`](generation-flux.md). Each remains unavailable until its trusted worker configuration and live readiness verification succeed. Other models remain unregistered. ## Architecture ```text REST / MCP / SDK / n8n (future transports) | GenerationService | GenerationProviderRegistry (verified adapters only) | GenerationRepository + authoritative tenancy + RLS | CanonicalMediaAsset references ``` `GenerationService` is the single transport-neutral orchestration boundary. Provider adapters must supply strict typed validation and worker submission; transports must not accept arbitrary provider payloads or worker URLs. ## Data and tenancy The security database migration [`0003_generation_domain_postgres.sql`](../app/security/migrations/0003_generation_domain_postgres.sql) adds these workspace-scoped tables: - `generation_requests`: immutable validated intent and its idempotency fingerprint. - `generation_jobs`: exactly one durable logical execution per request. - `generation_job_attempts`: retry audit history, without creating a new job. Input and output media are opaque IDs referencing `media_assets`. Client paths, local paths, direct object-store URLs, and provider credentials are never accepted or returned. Database triggers ensure request input assets and job outputs belong to the same workspace as the request/job. PostgreSQL RLS uses the already-established `app.workspace_id` and `app.user_id` session context. [`0004_generation_provider_runtime_postgres.sql`](../app/security/migrations/0004_generation_provider_runtime_postgres.sql) adds a unique provider/external-job binding so a remote worker identity cannot be attached to jobs in more than one workspace. ## API All endpoints require MediaRouter authentication and an authoritative active workspace membership. | Method | Endpoint | Scope | Purpose | |---|---|---|---| | `GET` | `/v1/generation/providers` | `generation:providers:read` | Capability discovery; no unavailable provider is advertised as usable. | | `GET` | `/v1/generation/providers/{provider}` | `generation:providers:read` | One provider's public capabilities. | | `GET` | `/v1/generation/models` | `generation:providers:read` | Server-owned model discovery; availability requires verified worker readiness. | | `GET` | `/v1/generation/providers/{provider}/models/{model_id}` | `generation:providers:read` | One registered provider model. | | `POST` | `/v1/generation/requests` | `generation:requests:create` | Create a durable job once an available adapter exists. Requires `Idempotency-Key`. | | `GET` | `/v1/generation/requests` | `generation:requests:read` | List only caller-workspace requests. | | `GET` | `/v1/generation/requests/{id}` | `generation:requests:read` | Read one caller-workspace request and job. | | `GET` | `/v1/generation/jobs/{id}` | `generation:requests:read` | Read one caller-workspace job. | | `POST` | `/v1/generation/jobs/{id}/cancel` | `generation:jobs:cancel` | Cancel queued work or request cancellation for active work. | The strict foundation request envelope is: ```json { "provider": "future-provider", "model_id": "verified-model-id", "modality": "image", "prompt": "A production-safe prompt", "input_asset_id": "optional-canonical-media-asset-uuid" } ``` Unknown JSON fields are rejected. Provider-specific controls are deliberately not accepted unless the relevant adapter supplies a reviewed typed schema. WAN uses the closed `wan` schema documented in [`generation-wan.md`](generation-wan.md); FLUX uses the closed `flux` schema documented in [`generation-flux.md`](generation-flux.md). ## Job semantics The state machine is `queued → submitting → running → succeeded`, with `retrying`, `failed`, `cancel_requested`, and `cancelled` paths. A retry continues the original `generation_jobs` row; it never creates another logical generation. Queued jobs cancel immediately. Active jobs become `cancel_requested` until the configured provider confirms cancellation, so the API does not make a false cancellation claim. An `Idempotency-Key` is required for every submission. The database enforces one key per workspace; MediaRouter fingerprints the normalized request and returns `GENERATION_IDEMPOTENCY_CONFLICT` when a caller reuses a key with a different payload. ## Deployment For local SQLite development, metadata is created with the rest of the security schema. PostgreSQL deployments must apply all security migrations in order, including `0003_generation_domain_postgres.sql` and `0004_generation_provider_runtime_postgres.sql`, before startup. Relevant configuration: ```env GENERATION_ENABLED=true GENERATION_JOB_RETRY_LIMIT=3 AI_WORKER_CONNECT_TIMEOUT_SECONDS=10 AI_WORKER_REQUEST_TIMEOUT_SECONDS=60 AI_WORKER_READ_TIMEOUT_SECONDS=300 AI_WORKER_MAX_RETRIES=3 AI_WORKER_RETRY_BACKOFF_SECONDS=0.5 ``` These settings provide shared worker transport defaults only. Provider URLs and tokens stay backend-only and are documented with each verified provider. The provider-runtime contract, worker transport, output handoff, and future adapter requirements are documented in [`generation-providers.md`](generation-providers.md). WAN and FLUX have separately reviewed optional adapters.