{
  "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",
    "passwordPolicy": "free accounts with verified email, password reset, 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, and session creation. Per-account limits protect 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": "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": "create_session",
      "method": "POST",
      "path": "/api/v1/auth/session",
      "status": "planned",
      "authRequired": false,
      "roles": [],
      "summary": "Create an authenticated session cookie for a verified account."
    },
    {
      "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_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",
      "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, session creation, 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 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, 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"
  }
}
