{
  "schema": "smmods.publishing-backend-contract.v1",
  "schemaUrl": "https://smmods.com/api/v1/publishing/backend-contract.schema.json",
  "generatedAt": "2026-05-29T05:43:00Z",
  "status": "planned-static-contract",
  "live": false,
  "baseUrl": "https://smmods.com",
  "summary": "Backend API surface required before SMMODS can enable account creation, authenticated uploads, moderation decisions, automatic catalog publication, and live audit trails.",
  "security": {
    "requiresHttps": true,
    "sessionCookie": "smmods_session",
    "csrfHeader": "x-smmods-csrf",
    "authenticationPolicy": "free accounts use verified email plus passwordless magic-link sessions, CSRF-protected browser sessions, API keys for fast manager downloads, and moderator/admin role assignment",
    "emailDeliveryPolicy": "POST /api/v1/accounts requires a configured verification email webhook outside developer token-return or auto-verify modes. Without delivery configuration it returns email_delivery_unavailable before creating an account.",
    "adminBootstrapPolicy": "SMMODS_BOOTSTRAP_ADMIN_EMAILS grants admin to matching accounts at creation so protected role management can take over after the first verified admin exists.",
    "rateLimitPolicy": "In-process per-IP limits protect account creation, email verification, magic-link requests, and session creation. Per-account limits protect API-key lifecycle, upload creation, and authenticated mutation routes for role changes, logout, upload cancellation, moderation decisions, and catalog publication."
  },
  "roles": [
    "player",
    "modder",
    "moderator",
    "admin"
  ],
  "endpoints": [
    {
      "id": "backend_health",
      "method": "GET",
      "path": "/api/v1/backend/health",
      "status": "planned",
      "authRequired": false,
      "roles": [],
      "summary": "Return backend process health and whether live uploads are currently enabled."
    },
    {
      "id": "create_account",
      "method": "POST",
      "path": "/api/v1/accounts",
      "status": "planned",
      "authRequired": false,
      "roles": [],
      "summary": "Create a free player or modder account and start email verification through the configured SMMODS email webhook."
    },
    {
      "id": "verify_account",
      "method": "POST",
      "path": "/api/v1/accounts/{accountId}/verify-email",
      "status": "planned",
      "authRequired": false,
      "roles": [],
      "summary": "Verify an account email address using the one-time verification token."
    },
    {
      "id": "request_magic_link",
      "method": "POST",
      "path": "/api/v1/auth/magic-link/request",
      "status": "planned",
      "authRequired": false,
      "roles": [],
      "summary": "Request a one-time magic-link email for a verified account without enumerating whether the email exists."
    },
    {
      "id": "list_accounts",
      "method": "GET",
      "path": "/api/v1/accounts",
      "status": "planned",
      "authRequired": true,
      "roles": [
        "admin"
      ],
      "summary": "List accounts for administrator role review and moderation staffing."
    },
    {
      "id": "update_account_roles",
      "method": "PUT",
      "path": "/api/v1/accounts/{accountId}/roles",
      "status": "planned",
      "authRequired": true,
      "roles": [
        "admin"
      ],
      "allowedRoles": [
        "player",
        "modder",
        "moderator",
        "admin"
      ],
      "summary": "Assign or remove account roles with CSRF protection, verified-account checks for privileged roles, last-admin protection, and audit logging."
    },
    {
      "id": "confirm_magic_link",
      "method": "POST",
      "path": "/api/v1/auth/magic-link/confirm",
      "status": "planned",
      "authRequired": false,
      "roles": [],
      "summary": "Exchange a one-time magic-link token for an authenticated session cookie and CSRF token."
    },
    {
      "id": "current_session",
      "method": "GET",
      "path": "/api/v1/auth/session",
      "status": "planned",
      "authRequired": true,
      "roles": [
        "player",
        "modder",
        "moderator",
        "admin"
      ],
      "summary": "Return the current account id, role set, display name, and CSRF token."
    },
    {
      "id": "delete_session",
      "method": "DELETE",
      "path": "/api/v1/auth/session",
      "status": "planned",
      "authRequired": true,
      "roles": [
        "player",
        "modder",
        "moderator",
        "admin"
      ],
      "summary": "End the current authenticated session."
    },
    {
      "id": "create_api_key",
      "method": "POST",
      "path": "/api/v1/auth/api-keys",
      "status": "planned",
      "authRequired": true,
      "roles": [
        "player",
        "modder",
        "moderator",
        "admin"
      ],
      "summary": "Create an account-scoped API key for manager fast-download requests. The plaintext key is returned only once."
    },
    {
      "id": "list_api_keys",
      "method": "GET",
      "path": "/api/v1/auth/api-keys",
      "status": "planned",
      "authRequired": true,
      "roles": [
        "player",
        "modder",
        "moderator",
        "admin"
      ],
      "summary": "List non-secret API-key metadata for the current account."
    },
    {
      "id": "revoke_api_key",
      "method": "DELETE",
      "path": "/api/v1/auth/api-keys/{apiKeyId}",
      "status": "planned",
      "authRequired": true,
      "roles": [
        "player",
        "modder",
        "moderator",
        "admin"
      ],
      "summary": "Revoke one account API key and reject later fast-download use of that secret."
    },
    {
      "id": "api_key_mod_download",
      "method": "GET",
      "path": "/api/v1/downloads/mods/{modId}/{version}/{fileName}",
      "status": "planned",
      "authRequired": true,
      "roles": [
        "player",
        "modder",
        "moderator",
        "admin"
      ],
      "summary": "Serve a published, download-enabled mod ZIP through the API-key fast-download lane while preserving immutable artifact hashes."
    },
    {
      "id": "create_upload",
      "method": "POST",
      "path": "/api/v1/uploads",
      "status": "planned",
      "authRequired": true,
      "roles": [
        "modder",
        "admin"
      ],
      "contentType": "multipart/form-data",
      "requiredFields": [
        "package",
        "metadata"
      ],
      "metadataSchema": "smmods.mod-release-submission.v1",
      "summary": "Create an immutable staged submission from a mod ZIP plus sidecar metadata. The backend rejects this route with uploads_disabled until SMMODS_LIVE_UPLOADS=1."
    },
    {
      "id": "upload_status",
      "method": "GET",
      "path": "/api/v1/uploads/{submissionId}",
      "status": "planned",
      "authRequired": true,
      "roles": [
        "modder",
        "moderator",
        "admin"
      ],
      "summary": "Return validation state, validation logs, review state, artifact hash, and publication links for one submission."
    },
    {
      "id": "cancel_upload",
      "method": "POST",
      "path": "/api/v1/uploads/{submissionId}/cancel",
      "status": "planned",
      "authRequired": true,
      "roles": [
        "modder",
        "admin"
      ],
      "summary": "Cancel a draft, uploaded, or failed submission that has not been approved."
    },
    {
      "id": "moderation_queue",
      "method": "GET",
      "path": "/api/v1/moderation/releases",
      "status": "planned",
      "authRequired": true,
      "roles": [
        "moderator",
        "admin"
      ],
      "summary": "List pending, failed, approved, hidden, and superseded release submissions for review."
    },
    {
      "id": "moderation_decision",
      "method": "POST",
      "path": "/api/v1/moderation/releases/{submissionId}/decision",
      "status": "planned",
      "authRequired": true,
      "roles": [
        "moderator",
        "admin"
      ],
      "allowedDecisions": [
        "approve",
        "reject",
        "request_changes",
        "hide",
        "unhide"
      ],
      "summary": "Record a moderation decision with reviewer notes and transition the release state."
    },
    {
      "id": "publish_catalog",
      "method": "POST",
      "path": "/api/v1/catalog/publish",
      "status": "planned",
      "authRequired": true,
      "roles": [
        "admin"
      ],
      "summary": "Atomically publish approved releases into immutable downloads plus catalog, detail, and versions JSON."
    },
    {
      "id": "audit_events",
      "method": "GET",
      "path": "/api/v1/audit/events",
      "status": "planned",
      "authRequired": true,
      "roles": [
        "admin"
      ],
      "summary": "Read immutable audit events for account, upload, validation, moderation, and publication actions."
    }
  ],
  "dataContracts": {
    "account": {
      "requiredFields": [
        "id",
        "email",
        "displayName",
        "roles",
        "createdAt",
        "verifiedAt"
      ]
    },
    "uploadSubmission": {
      "schema": "smmods.upload-submission.v1",
      "schemaUrl": "https://smmods.com/api/v1/publishing/upload-submission.schema.json",
      "requiredFields": [
        "submissionId",
        "ownerAccountId",
        "modId",
        "version",
        "state",
        "packageSha256",
        "validationChecks",
        "review",
        "createdAt",
        "updatedAt"
      ],
      "states": [
        "draft",
        "uploaded",
        "validating",
        "validation_failed",
        "cancelled",
        "pending_review",
        "changes_requested",
        "approved",
        "published",
        "rejected",
        "hidden",
        "superseded"
      ]
    },
    "auditEvent": {
      "requiredFields": [
        "id",
        "actorAccountId",
        "action",
        "targetType",
        "targetId",
        "createdAt",
        "metadata"
      ]
    }
  },
  "storage": {
    "stagingPathTemplate": "uploads/staging/{submissionId}/{fileName}",
    "publicArtifactPathTemplate": "downloads/mods/{modId}/{version}/{fileName}",
    "immutablePublicArtifacts": true,
    "maxPackageBytes": 104857600,
    "liveUploadGate": "POST /api/v1/uploads returns uploads_disabled unless SMMODS_LIVE_UPLOADS=1 is active for the backend process."
  },
  "validationWorker": {
    "queue": "mod-validation",
    "frameworkValidationContractUrl": "https://smmods.com/api/v1/publishing/starminer-publishing-validation.v1.json",
    "frameworkValidationContractSchemaUrl": "https://smmods.com/api/v1/publishing/starminer-publishing-validation.schema.json",
    "requiredChecks": [
      "sidecar_schema",
      "manifest_schema",
      "manifest_identity",
      "semantic_version",
      "target_game_build",
      "dependency_contract",
      "zip_path_safety",
      "antivirus_scan",
      "file_signature",
      "archive_content_policy",
      "entrypoint_presence",
      "mod_config_contract",
      "artifact_hash",
      "detail_page",
      "manager_catalog_parse"
    ]
  },
  "catalogPublisher": {
    "outputs": [
      "/downloads/mods/{modId}/{version}/{fileName}",
      "/api/v1/catalog.json",
      "/api/v1/mods/index.json",
      "/api/v1/mods/{modId}/index.json",
      "/api/v1/mods/{modId}/versions.json"
    ],
    "atomicPublication": true,
    "postPublishSmokeRequired": true
  },
  "goLiveChecks": [
    "All endpoints above are implemented behind HTTPS with session and CSRF protection where authRequired is true.",
    "Production account creation has a real verification email delivery provider configured and returns email_delivery_unavailable rather than creating unverifiable accounts when delivery is missing.",
    "Backend write routes enforce rate_limit_exceeded responses with Retry-After for account creation, email verification, magic-link requests, session creation, API-key lifecycle, upload creation, and authenticated mutations.",
    "Uploads are stored privately until validation and moderation approve publication.",
    "SMMODS_LIVE_UPLOADS=0 rejects authenticated upload creation before package bytes are accepted; SMMODS_LIVE_UPLOADS=1 is required for the upload go-live step.",
    "The validation worker runs every required check, including antivirus_scan, file_signature, and archive_content_policy, and records durable logs visible to the modder and moderators.",
    "The catalog publisher computes SHA256 from the exact immutable public artifact and refuses replacement of existing artifact URLs.",
    "The audit log records every account, magic-link, API-key, upload, validation, moderation, and publish action.",
    "Public smoke fetches live routes, validates readiness and workflow JSON, downloads artifacts, verifies hashes, and runs manager URL readers."
  ],
  "manualFallback": {
    "active": true,
    "workflowUrl": "https://smmods.com/api/v1/publishing/workflow.json",
    "runbook": "docs/manual-publishing.md",
    "tool": "tools/Import-ModRelease.ps1"
  }
}
