Generated App Deployment Contract¶
Purpose¶
This document defines the provider-neutral deployment artifact contract for generated apps.
For the separate repo-local OSS infra/ boundary and the first-party factory_app/ deployment story, see docs/architecture/deployment/oss-infra-and-generated-app-deployment.md.
The OSS mozaiks repo owns this contract. Hosted-product policy, approvals, provider adapters, and secret orchestration remain outside this repo.
The contract answers "how does this generated app run?" It does not answer "where should the hosted product operate it?" or "which provider adapter should mutate infrastructure?" Hosted products convert the contract into their own records, approvals, provider calls, and status surfaces.
Staging Terminology¶
Use these terms precisely:
- Artifact review staging is the Mozaiks/Studio Refinement Engine stage where generated or refined files are held for validation, review,
ArtifactVersionacceptance, and explicit promotion into an app workspace. - Environment staging is an operator or hosted deployment target used to prove a promoted/exported app before production, for example a GitHub
stagingenvironment, preview container, or hosted staging URL.
Generated deployment artifacts may include environment-staging workflows, but they do not replace artifact review staging. Generation remains non-mutating; promotion remains explicit.
Production Boundary¶
Generated apps use a repo-per-app (workspace-per-app) boundary.
This keeps deployment ownership, environments, CI history, and secret boundaries isolated per app.
Contract Models¶
The contract is represented by two typed models in AppGenerator structured outputs.
DeployTargetSpecDeploymentTemplateManifestDeploymentBuildOutput
DeployTargetSpec¶
Provider-neutral target definition.
Required shape:
target_idtarget_kind:container | compose | external_adapterruntimecontainer_porthealth_pathstart_command(optional)artifact_outputsDockerfile(optional)docker-compose.yml(optional).github/workflows/readiness.yml(optional; forced by production profiles).github/workflows/deploy.yml(optional).env.example.env.staging.example.env.production.exampledeployment.manifest.jsonenvironmentrequired_variablesoptional_variablessecret_variablespublic_variablesauthrequiredproviderruntime_required_variablesruntime_optional_variablespublic_variablesimageimage_nametag_strategychecksbuildsmokehealthprovider_profile- generic metadata only in OSS
readiness_requirements- provider-neutral checks that name required runtime env and evidence stamps
Optional shape:
ci_secret_requirementsrequiredoptionalworkflow_inputs
DeploymentTemplateManifest¶
Deterministic output manifest for generated deployment artifacts.
Required shape:
schema_versionapp_iddeployment_profilegenerated_filesrequired_envsecret_envpublic_envauthexposed_portshealthcheckci_workflowreadiness_workflow(optional)ci_secret_requirements(optional)readiness_requirementsdockerfilecomposevalidation_statusdeploy_target_specbuild_output_contract(optional)
Production-oriented generated apps should use deployment_profile=production_container. That profile forces the root Dockerfile, .env.example, .env.staging.example, .env.production.example, deployment.manifest.json, and .github/workflows/readiness.yml handoff even when the app is not asking the OSS generator to emit a provider-specific deploy workflow.
Readiness Requirements¶
Generated deployment manifests carry a names-only readiness section under readiness_requirements. This is the OSS first-class contract for production evidence without coupling generated apps to a hosted product, cloud provider, or payment provider.
Suggested shape:
checksidcategorylabelimplemented_scorerequired_envrequired_evidencecanonical_pathsnotes(optional)
Default generated checks are provider-neutral:
runtime_environment- requires
OPENAI_API_KEYandMONGO_URI container_smoke- requires evidence stamp
APP_IMAGE_SMOKE_VERIFIED_AT healthcheck- requires evidence stamp
APP_HEALTHCHECK_VERIFIED_AT auth_configuration- emitted only when
app.json.authRequired=true - requires
AUTH_ENABLEDandAUTH_PROVIDER - requires evidence stamp
APP_AUTH_SMOKE_VERIFIED_AT
Rules:
- Readiness requirements carry names only, never values.
required_envandrequired_evidenceuse uppercase env-style names.- Evidence stamps should contain an ISO timestamp, run id, ticket URL, or change record only after the named check has passed.
- Readiness checks are provider-neutral; they must not mention Azure, AWS, payment provider, MozaiksPay, Cloudflare, registrar adapters, or hosted-product policy.
- Hosted products may add product-specific checks outside generated app bundles, then evaluate both layers with the OSS
mozaiksai.core.runtime.readinessprimitive.
The generated environment-staging readiness workflow also runs a live provider-neutral runtime preflight before the container smoke:
MONGO_URImust authenticate and respond to a MongoDBping- auth-enabled apps must have either reachable OIDC discovery metadata or a reachable explicit
AUTH_JWKS_URLwithAUTH_ISSUER
The workflow reports only safe metadata such as check ids, status, public host names, and exception type. It must not print connection strings, API keys, passwords, tokens, or provider secrets.
Authenticated App Contract¶
Generated apps declare whether their runtime requires login through app.json.authRequired.
When authRequired=true, AppGenerator emits a provider-neutral JWT/OIDC auth contract in deployment.manifest.json:
auth.required=trueauth.provider=jwtby default- backend required env handles:
AUTH_ENABLED,AUTH_PROVIDER - backend optional env handles for issuer, JWKS, discovery, audience, scopes, and claim mapping
- public frontend env handles:
VITE_OIDC_AUTHORITY,VITE_OIDC_DISCOVERY_URL,VITE_OIDC_CLIENT_ID,VITE_OIDC_SCOPE, andVITE_OIDC_REDIRECT_URI
The generated app bundle carries names only. It does not carry tenant ids, client secrets, provider credentials, hosted-product auth policy, Keycloak-only paths, Entra-only paths, or Mozaiks hosted product auth adapters.
At deploy time, a host or self-host operator configures one real OIDC/JWT provider by setting either discovery/authority values or explicit AUTH_ISSUER plus AUTH_JWKS_URL. The OSS runtime validates tokens through the configured auth adapter; generated app modules continue to enforce permissions and entitlement gates through declarative module contracts.
CI Workflow Secret Requirements¶
Generated deployment workflows may declare a names-only CI contract under ci_secret_requirements.
Suggested shape:
requirednamepurpose(optional)used_by(optional)optionalnamepurpose(optional)used_by(optional)workflow_inputsnamerequiredpurpose(optional)
Rules:
- Entries carry names only, never values.
- Secret names must use safe identifiers.
- Workflow input names must use safe identifiers.
- Generated workflow files may reference those names, for example
${{ secrets.NAME }}or${{ inputs.name }}, but must never embed secret values. - Hosts and adapters provision real secret values outside generated artifacts. The generated app bundle only describes expected names.
Build Output Contract¶
DeploymentBuildOutput is the provider-neutral handoff contract from repo/export/build systems to deployment providers/hosts.
It carries build/export output metadata and does not execute builds.
Suggested shape:
repo_url(optional)commit_sha(optional)build_status:pending | running | succeeded | failedimage_ref(required when status issucceeded)artifact_digest(optional,sha256:prefix)workflow_run_url(optional)logs_url(optional)safe_details(optional, non-secret metadata only)error_code(optional)
Provider-neutral examples:
repo_url:https://repo.example.invalid/demo-appimage_ref:registry.example.invalid/demo-app:abc123artifact_digest:sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
Validation rules:
build_statusmust be one of pending/running/succeeded/failed.image_refis required whenbuild_statusis succeeded.artifact_digest, if present, usessha256:prefix.- URL fields are URL-shaped when present.
- Raw secrets and secret-shaped keys are not allowed in
safe_details. - No provider-specific required fields.
Artifact Contract¶
When deployment artifacts are requested by scaffold/export flags, AppGenerator emits deterministic outputs from the provider-neutral contract:
Dockerfile(optional)docker-compose.yml(optional).github/workflows/readiness.yml(optional; forced by production profiles).github/workflows/deploy.yml(optional).env.example.env.staging.example.env.production.exampledeployment.manifest.json
These artifacts live at the generated app bundle root. They are not emitted from app/services/, and AppGenerator build tasks must not claim them as service_foundation, api_surface, or helper-file outputs.
When .github/workflows/deploy.yml is emitted, the manifest may also carry a concrete ci_secret_requirements section describing the names-only secret and workflow-input contract used by that generated workflow.
Env and Secrets Rules¶
.env.example,.env.staging.example, and.env.production.examplemay include variable names and placeholders only.- Secret variables are declared by name only and must not contain real values.
ci_secret_requirementsis names-only and must not contain real values.- Generated workflow files may reference secret names but never secret values.
- Generated artifacts must not include:
- cloud tenant ids
- provider credentials
- registry passwords
- GitHub tokens
- hosted-product policy secrets
- Real secrets are injected by deployment adapters (CI secret stores / cloud secret stores), not committed in app repos.
AppGenerator and Adapter Split¶
OSS AppGenerator emits and validates:
- deployment contract schema
- deterministic artifact rendering
- artifact validation rules
- provider-neutral build output handoff contract
- names-only CI workflow secret requirements contract
- provider-neutral readiness requirements contract
- optional readiness workflow scaffolding for environment-staging proof
Adapter layers outside AppGenerator handle:
- provider-specific deployment execution
- hosted policy/approval gates
- hosted lifecycle state transitions
- secret delivery and rotation
- persistence of build outputs in host deployment records
- mapping names-only CI secret requirements to provider-specific secret stores
- mapping generated readiness requirements into hosted staging gates
- async deployment status polling (see below)
Async Provider Deployment Status¶
Some deployment providers (for example Azure Container Apps) return status="deploying" with no hosted_url on the initial deploy() call. The hosted product must poll the provider until the deployment completes or fails.
The canonical DeploymentProviderAdapter protocol for hosted products exposes two lifecycle methods:
deploy(request) → DeploymentProviderResult
status: "hosted" | "deploying" | "failed"
hosted_url: str | None # present only when status == "hosted"
provider_deployment_id: str | None
get_status(provider_deployment_id, ...) → DeploymentProviderResult
(same shape as deploy())
Rules:
- When
deploy()returnsstatus="deploying", do not mark the app as hosted. Persist theprovider_deployment_idand let the polling loop callget_status(). - When
get_status()returnsstatus="hosted", mark the app hosted and record the URL. - When
get_status()returnsstatus="failed", record the failure and stop polling. - The polling loop is owned by the hosted product module (a startup service helper), not by the adapter. Adapters are stateless per-call; the hosted module owns lifecycle state.
- Adapters that deploy synchronously may return
status="hosted"directly fromdeploy(). The hosted module must handle both synchronous and asynchronous adapters uniformly.
For Mozaiks-hosted apps, the generated bundle may include Dockerfile, .env.example, .env.staging.example, .env.production.example, .github/workflows/readiness.yml, .github/workflows/deploy.yml, and deployment.manifest.json, but it must not include hosted product provider adapters such as DNS, registrar, cloud deployment, wallet, billing, or hosted policy implementations. The hosted product owns those adapters and consumes the generated contract through platform records/APIs.
E2B Role¶
E2B in AppGenerator is pre-deploy validation/preview only.
It is not a production runtime or hosting target.
Self-Host Mode¶
This contract supports self-hosting through the same generic artifact outputs:
- local Docker
- local Compose
- generic container platform deployment
Self-host users consume generated artifacts and provide their own infrastructure and secret stores. They can evaluate the manifest readiness section with mozaiksai.core.runtime.readiness.evaluate_readiness_requirements.
Hosted Product Handoff¶
Hosted products (for example mozaiks-app) consume this contract but own hosted-specific behavior:
- Host With Us UX
- policy/approval gates
- provider adapters and defaults
- deployment status and operations surfaces
App Zero dogfooding follows the same handoff as any tenant app: the mozaiks-app bundle can be registered and operated through hosted product records, but infrastructure changes still flow through the product modules and provider adapters rather than direct adapter imports from the app bundle.