openapi: 3.1.0
info:
  title: AppKernia API
  version: 0.1.0
  license:
    name: MIT
    identifier: MIT
servers:
  - url: /
tags:
  - name: platform-health
    description: Platform health
    x-displayName: Platform health
    x-appkernia-i18n-key: api_reference.module.platform_health
  - name: public-app
    description: App public capabilities
    x-displayName: App public capabilities
    x-appkernia-i18n-key: api_reference.module.public_app
  - name: public-content
    description: Public content
    x-displayName: Public content
    x-appkernia-i18n-key: api_reference.module.public_content
  - name: public-dictionary
    description: Public dictionaries
    x-displayName: Public dictionaries
    x-appkernia-i18n-key: api_reference.module.public_dictionary
  - name: api-client-auth
    description: API Client authentication
    x-displayName: API Client authentication
    x-appkernia-i18n-key: api_reference.module.api_client_auth
  - name: mobile-auth
    description: Authentication
    x-displayName: Authentication
    x-appkernia-i18n-key: api_reference.module.mobile_auth
  - name: mobile-profile
    description: Profile and preferences
    x-displayName: Profile and preferences
    x-appkernia-i18n-key: api_reference.module.mobile_profile
  - name: mobile-devices-sessions
    description: Devices and sessions
    x-displayName: Devices and sessions
    x-appkernia-i18n-key: api_reference.module.mobile_devices_sessions
  - name: mobile-notifications
    description: Notifications
    x-displayName: Notifications
    x-appkernia-i18n-key: api_reference.module.mobile_notifications
  - name: mobile-security
    description: Security events
    x-displayName: Security events
    x-appkernia-i18n-key: api_reference.module.mobile_security
  - name: mobile-content
    description: Bookmarks and legal consent
    x-displayName: Bookmarks and legal consent
    x-appkernia-i18n-key: api_reference.module.mobile_content
  - name: admin-auth-profile
    description: Authentication and profile
    x-displayName: Authentication and profile
    x-appkernia-i18n-key: api_reference.module.admin_auth_profile
  - name: admin-dashboard
    description: Dashboard
    x-displayName: Dashboard
    x-appkernia-i18n-key: api_reference.module.admin_dashboard
  - name: admin-app-management
    description: App management
    x-displayName: App management
    x-appkernia-i18n-key: api_reference.module.admin_app_management
  - name: admin-releases
    description: Upgrade center
    x-displayName: Upgrade center
    x-appkernia-i18n-key: api_reference.module.admin_releases
  - name: admin-app-content
    description: App content
    x-displayName: App content
    x-appkernia-i18n-key: api_reference.module.admin_app_content
  - name: admin-app-communications
    description: App notifications
    x-displayName: App notifications
    x-appkernia-i18n-key: api_reference.module.admin_app_communications
  - name: admin-app-users
    description: App users
    x-displayName: App users
    x-appkernia-i18n-key: api_reference.module.admin_app_users
  - name: admin-organization
    description: Organization
    x-displayName: Organization
    x-appkernia-i18n-key: api_reference.module.admin_organization
  - name: admin-tenants
    description: Tenants
    x-displayName: Tenants
    x-appkernia-i18n-key: api_reference.module.admin_tenants
  - name: admin-users
    description: Users
    x-displayName: Users
    x-appkernia-i18n-key: api_reference.module.admin_users
  - name: admin-access-control
    description: Permissions
    x-displayName: Permissions
    x-appkernia-i18n-key: api_reference.module.admin_access_control
  - name: admin-system-settings
    description: System settings
    x-displayName: System settings
    x-appkernia-i18n-key: api_reference.module.admin_system_settings
  - name: admin-storage
    description: Files
    x-displayName: Files
    x-appkernia-i18n-key: api_reference.module.admin_storage
  - name: admin-content
    description: Content
    x-displayName: Content
    x-appkernia-i18n-key: api_reference.module.admin_content
  - name: admin-notifications
    description: Notifications
    x-displayName: Notifications
    x-appkernia-i18n-key: api_reference.module.admin_notifications
  - name: admin-jobs
    description: Jobs
    x-displayName: Jobs
    x-appkernia-i18n-key: api_reference.module.admin_jobs
  - name: admin-api-clients
    description: API Clients
    x-displayName: API Clients
    x-appkernia-i18n-key: api_reference.module.admin_api_clients
  - name: admin-webhooks
    description: Webhooks
    x-displayName: Webhooks
    x-appkernia-i18n-key: api_reference.module.admin_webhooks
  - name: admin-audit-security
    description: Audit and security
    x-displayName: Audit and security
    x-appkernia-i18n-key: api_reference.module.admin_audit_security
  - name: admin-operations
    description: Online sessions and runtime
    x-displayName: Online sessions and runtime
    x-appkernia-i18n-key: api_reference.module.admin_operations
x-tagGroups:
  - name: Platform and Public APIs
    x-appkernia-i18n-key: api_reference.surface.platform_public
    tags:
      - platform-health
      - public-app
      - public-content
      - public-dictionary
      - api-client-auth
  - name: Mobile APIs
    x-appkernia-i18n-key: api_reference.surface.mobile
    tags:
      - mobile-auth
      - mobile-profile
      - mobile-devices-sessions
      - mobile-notifications
      - mobile-security
      - mobile-content
  - name: Admin APIs
    x-appkernia-i18n-key: api_reference.surface.admin
    tags:
      - admin-auth-profile
      - admin-dashboard
      - admin-app-management
      - admin-releases
      - admin-app-content
      - admin-app-communications
      - admin-app-users
      - admin-organization
      - admin-tenants
      - admin-users
      - admin-access-control
      - admin-system-settings
      - admin-storage
      - admin-content
      - admin-notifications
      - admin-jobs
      - admin-api-clients
      - admin-webhooks
      - admin-audit-security
      - admin-operations

paths:
  /internal/v1/health/live:
    get:
      summary: Check API process liveness
      operationId: getLiveness
      tags: [platform-health]
      security: []
      responses:
        "200":
          description: Process is alive.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HealthResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
  /internal/v1/health/ready:
    get:
      summary: Check required dependency readiness
      operationId: getReadiness
      tags: [platform-health]
      security: []
      responses:
        "200":
          description: Required dependencies are ready.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HealthResponse"
        "503":
          description: A required dependency is unavailable.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
  /api/v1/public/config:
    get:
      summary: Read public mobile application configuration
      operationId: getAppPublicConfig
      tags: [public-app]
      security: []
      parameters:
        - $ref: "#/components/parameters/AcceptLanguage"
        - $ref: "#/components/parameters/AppID"
      responses:
        "200":
          description: Public application configuration. Database-backed settings include only active global records where is_public is true and is_secret is false.
          headers:
            Cache-Control:
              schema: {type: string, example: "public, max-age=60"}
            Content-Language:
              schema:
                $ref: "#/components/schemas/SupportedLocale"
            Vary:
              schema:
                type: string
                const: Accept-Language, X-AppID
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AppPublicConfigResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "503":
          description: Public configuration storage is unavailable.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/public/startup-assets/{file_id}:
    get:
      summary: Read the active App icon or one image from its current published onboarding revision
      operationId: getAppStartupAsset
      tags: [public-app]
      security: []
      parameters:
        - $ref: "#/components/parameters/AppID"
        - {name: file_id, in: path, required: true, schema: {type: string, format: uuid}}
      responses:
        "200":
          description: A scanned JPEG, PNG, or WebP startup asset scoped to the active App.
          headers:
            Cache-Control: {schema: {type: string, const: "public, max-age=31536000, immutable"}}
            ETag: {schema: {type: string}}
            X-App-Onboarding-Version: {schema: {type: integer, minimum: 0}}
            X-Content-Type-Options: {schema: {type: string, const: nosniff}}
          content:
            image/jpeg: {schema: {type: string, format: binary}}
            image/png: {schema: {type: string, format: binary}}
            image/webp: {schema: {type: string, format: binary}}
        "404": {$ref: "#/components/responses/NotFound"}
  /api/v1/public/legal/{document_type}:
    get:
      summary: Read a published App legal document with locale fallback
      operationId: getAppLegalDocument
      tags: [public-app]
      security: []
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}, {$ref: "#/components/parameters/AppID"}, {name: document_type, in: path, required: true, schema: {type: string, enum: [privacy-policy, terms-of-service]}}]
      responses: {"200": {description: Published legal document and immutable revision hash., content: {application/json: {schema: {$ref: "#/components/schemas/AppPublicPageResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}}
  /api/v1/public/pages/{slug}:
    get:
      summary: Read one published App single page
      operationId: getAppPublicPage
      tags: [public-app]
      security: []
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}, {$ref: "#/components/parameters/AppID"}, {name: slug, in: path, required: true, schema: {type: string, pattern: '^[a-z0-9]+(?:-[a-z0-9]+)*$'}}]
      responses: {"200": {description: Published App page and immutable revision hash., content: {application/json: {schema: {$ref: "#/components/schemas/AppPublicPageResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}}
  /api/v1/me/legal-consents:
    post:
      summary: Record acceptance of the currently published App legal revision
      operationId: acceptAppLegalDocument
      tags: [mobile-content]
      parameters: [{$ref: "#/components/parameters/AppID"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AppLegalConsentRequest"}}}}
      responses: {"200": {description: Consent was recorded idempotently., content: {application/json: {schema: {$ref: "#/components/schemas/BooleanSuccessResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /api/v1/regions:
    parameters: [{$ref: "#/components/parameters/AppID"}]
    get:
      summary: Lazily list active public regions
      operationId: listAppRegions
      tags: [public-app]
      security: []
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}, {name: q, in: query, schema: {type: string, maxLength: 160}}, {name: parent_code, in: query, schema: {type: string, maxLength: 32}}, {name: level, in: query, schema: {type: integer, minimum: 0, maximum: 10}}, {name: limit, in: query, schema: {type: integer, minimum: 1, maximum: 200, default: 100}}]
      responses: {"200": {description: Active region nodes; roots are returned when parent_code and q are absent., content: {application/json: {schema: {$ref: "#/components/schemas/RegionListResponse"}}}}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /api/v1/public/app-version:
    get:
      summary: Read the public mobile application upgrade policy
      operationId: getMobileAppVersion
      tags: [public-app]
      security: []
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}, {$ref: "#/components/parameters/AppID"}, {name: platform, in: query, required: true, schema: {type: string, enum: [android, ios, harmony]}}, {name: package_type, in: query, schema: {type: string, enum: [native_app, wgt], default: native_app}}]
      responses: {"200": {description: Localized current version and upgrade policy without administrative fields., content: {application/json: {schema: {$ref: "#/components/schemas/MobileAppVersionResponse"}}}}, "422": {$ref: "#/components/responses/ValidationFailed"}, "503": {description: No active release policy exists for this platform., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}}
  /api/v1/public/app-version/download/{release_id}/{file_id}:
    get:
      summary: Download a published internal package with a short-lived App/version/file-bound signature
      operationId: downloadMobileAppVersionPackage
      tags: [public-app]
      security: []
      parameters: [{$ref: "#/components/parameters/AppID"}, {name: release_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: file_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: expires, in: query, required: true, schema: {type: integer, format: int64}}, {name: signature, in: query, required: true, schema: {type: string}}]
      responses: {"200": {description: Private package bytes with no-store cache policy., content: {application/octet-stream: {schema: {type: string, format: binary}}}}, "404": {$ref: "#/components/responses/NotFound"}}
  /api/v1/auth/login/password:
    parameters: [{$ref: "#/components/parameters/AppID"}]
    post:
      summary: Sign in to the mobile application with a password
      operationId: mobilePasswordLogin
      tags: [mobile-auth]
      security: []
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}, {name: X-AK-Device-Key, in: header, required: true, description: A random UUID identifying this mobile installation. It is not an authentication factor., schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/MobilePasswordLoginRequest"}}}}
      responses: {"200": {description: Bearer access token plus one-time opaque refresh token for secure platform storage., content: {application/json: {schema: {$ref: "#/components/schemas/MobileTokenResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /api/v1/auth/register:
    post:
      summary: Register an App user and start App-configured email verification
      operationId: registerAppUser
      tags: [mobile-auth]
      security: []
      parameters: [{$ref: "#/components/parameters/AppID"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AppRegistrationRequest"}}}}
      responses: {"202": {description: Generic accepted response; does not reveal whether an account already exists., content: {application/json: {schema: {$ref: "#/components/schemas/AppAcceptedResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /api/v1/auth/registration/verify-email:
    post:
      summary: Verify a registration email OTP for the current App
      operationId: verifyAppRegistrationEmail
      tags: [mobile-auth]
      security: []
      parameters: [{$ref: "#/components/parameters/AppID"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AppEmailOTPRequest"}}}}
      responses: {"200": {description: Membership activated, content: {application/json: {schema: {$ref: "#/components/schemas/BooleanSuccessResponse"}}}}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /api/v1/auth/registration/resend-code:
    post:
      summary: Resend a registration OTP subject to the App email cooldown
      operationId: resendAppRegistrationEmail
      tags: [mobile-auth]
      security: []
      parameters: [{$ref: "#/components/parameters/AppID"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AppEmailRequest"}}}}
      responses: {"202": {description: Generic accepted response with resend cooldown., content: {application/json: {schema: {$ref: "#/components/schemas/AppAcceptedResponse"}}}}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /api/v1/auth/password/forgot:
    post:
      summary: Start an App-scoped password-reset email OTP flow
      operationId: forgotAppPassword
      tags: [mobile-auth]
      security: []
      parameters: [{$ref: "#/components/parameters/AppID"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AppEmailRequest"}}}}
      responses: {"202": {description: Generic accepted response to prevent account enumeration., content: {application/json: {schema: {$ref: "#/components/schemas/AppAcceptedResponse"}}}}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /api/v1/auth/password/reset:
    post:
      summary: Reset an App user's password with a one-time email OTP
      operationId: resetAppPassword
      tags: [mobile-auth]
      security: []
      parameters: [{$ref: "#/components/parameters/AppID"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AppPasswordResetRequest"}}}}
      responses: {"200": {description: Password reset and current App mobile sessions revoked., content: {application/json: {schema: {$ref: "#/components/schemas/BooleanSuccessResponse"}}}}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /api/v1/auth/token/refresh:
    parameters: [{$ref: "#/components/parameters/AppID"}]
    post:
      summary: Rotate a mobile refresh token
      operationId: mobileRefreshToken
      tags: [mobile-auth]
      security: []
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/MobileRefreshRequest"}}}}
      responses: {"200": {description: Refresh token rotated; old token is consumed., content: {application/json: {schema: {$ref: "#/components/schemas/MobileTokenResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}}
  /api/v1/auth/logout:
    parameters: [{$ref: "#/components/parameters/AppID"}]
    post:
      summary: Revoke the current mobile session
      operationId: mobileLogout
      tags: [mobile-auth]
      responses: {"200": {description: Session revoked, content: {application/json: {schema: {$ref: "#/components/schemas/BooleanSuccessResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}}
  /api/v1/auth/context:
    parameters: [{$ref: "#/components/parameters/AppID"}]
    get:
      summary: Get the authenticated mobile identity context
      operationId: mobileAuthContext
      tags: [mobile-auth]
      responses: {"200": {description: Authenticated mobile context, content: {application/json: {schema: {$ref: "#/components/schemas/MobileContextResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}}
  /api/v1/auth/password/change:
    parameters: [{$ref: "#/components/parameters/AppID"}]
    post:
      summary: Change the current mobile user's password and revoke other sessions
      operationId: mobileChangePassword
      tags: [mobile-auth]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/SelfPasswordChangeRequest"}}}}
      responses: {"200": {description: Password changed, content: {application/json: {schema: {$ref: "#/components/schemas/BooleanSuccessResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /api/v1/me:
    parameters: [{$ref: "#/components/parameters/AppID"}]
    get:
      summary: Get the current mobile user profile
      operationId: getMobileMe
      tags: [mobile-profile]
      responses: {"200": {description: Current profile, content: {application/json: {schema: {$ref: "#/components/schemas/SelfProfileResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}}
    patch:
      summary: Update the current mobile user profile
      operationId: updateMobileMe
      tags: [mobile-profile]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/SelfProfileUpdateRequest"}}}}
      responses: {"200": {description: Updated profile, content: {application/json: {schema: {$ref: "#/components/schemas/SelfProfileResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /api/v1/me/sessions:
    parameters: [{$ref: "#/components/parameters/AppID"}]
    get:
      summary: List the current user's mobile sessions
      operationId: listMobileSelfSessions
      tags: [mobile-devices-sessions]
      responses: {"200": {description: Mobile sessions, content: {application/json: {schema: {$ref: "#/components/schemas/MobileSessionListResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}}
  /api/v1/me/sessions/{id}:
    parameters: [{$ref: "#/components/parameters/AppID"}]
    delete:
      summary: Revoke one current-user mobile session
      operationId: revokeMobileSelfSession
      tags: [mobile-devices-sessions]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: Session revoked, content: {application/json: {schema: {$ref: "#/components/schemas/BooleanSuccessResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "404": {$ref: "#/components/responses/NotFound"}}
  /api/v1/me/devices:
    parameters: [{$ref: "#/components/parameters/AppID"}]
    get:
      summary: List the current user's devices
      operationId: listMobileSelfDevices
      tags: [mobile-devices-sessions]
      responses: {"200": {description: Mobile devices, content: {application/json: {schema: {$ref: "#/components/schemas/MobileDeviceListResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}}
  /api/v1/me/devices/{id}:
    parameters: [{$ref: "#/components/parameters/AppID"}]
    delete:
      summary: Remove a current-user device and its sessions
      operationId: removeMobileSelfDevice
      tags: [mobile-devices-sessions]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: Device removed, content: {application/json: {schema: {$ref: "#/components/schemas/BooleanSuccessResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "404": {$ref: "#/components/responses/NotFound"}}
  /api/v1/me/preferences:
    parameters: [{$ref: "#/components/parameters/AppID"}]
    get:
      summary: Get current-user locale and appearance preferences
      operationId: getMobilePreferences
      tags: [mobile-profile]
      responses: {"200": {description: Current preferences, content: {application/json: {schema: {$ref: "#/components/schemas/MobilePreferencesResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}}
    patch:
      summary: Update current-user locale, appearance, and notification preferences
      operationId: updateMobilePreferences
      tags: [mobile-profile]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/MobilePreferencesUpdateRequest"}}}}
      responses: {"200": {description: Updated preferences, content: {application/json: {schema: {$ref: "#/components/schemas/MobilePreferencesResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /api/v1/me/notification-preferences:
    parameters: [{$ref: "#/components/parameters/AppID"}]
    get: {summary: Get current-user notification preferences, operationId: getMobileNotificationPreferences, tags: [mobile-notifications], responses: {"200": {description: Current notification preferences only., content: {application/json: {schema: {$ref: "#/components/schemas/MobileNotificationPreferencesResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}}}
    patch: {summary: Update current-user notification preferences, operationId: updateMobileNotificationPreferences, tags: [mobile-notifications], requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/MobileNotificationPreferencesUpdateRequest"}}}}, responses: {"200": {description: Updated notification preferences only., content: {application/json: {schema: {$ref: "#/components/schemas/MobileNotificationPreferencesResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "422": {$ref: "#/components/responses/ValidationFailed"}}}
  /api/v1/me/notifications/unread-count:
    parameters: [{$ref: "#/components/parameters/AppID"}]
    get: {summary: Count unread in-app notifications for the current user, operationId: getMobileUnreadNotificationCount, tags: [mobile-notifications], responses: {"200": {description: Unread count, content: {application/json: {schema: {$ref: "#/components/schemas/MobileUnreadCountResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}}}
  /api/v1/me/notifications:
    parameters: [{$ref: "#/components/parameters/AppID"}]
    get:
      summary: List delivered current-user in-app notifications with an opaque cursor
      operationId: listMobileNotifications
      tags: [mobile-notifications]
      parameters: [{name: cursor, in: query, schema: {type: string}}, {name: limit, in: query, schema: {type: integer, minimum: 1, maximum: 100, default: 20}}]
      responses: {"200": {description: Delivered notifications visible only to the authenticated tenant member., content: {application/json: {schema: {$ref: "#/components/schemas/MobileNotificationPageResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /api/v1/me/notifications/{id}/read:
    parameters: [{$ref: "#/components/parameters/AppID"}]
    patch:
      summary: Mark one delivered current-user notification as read
      operationId: markMobileNotificationRead
      tags: [mobile-notifications]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: Notification read state updated, content: {application/json: {schema: {$ref: "#/components/schemas/BooleanSuccessResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "404": {$ref: "#/components/responses/NotFound"}}
  /api/v1/me/login-events:
    parameters: [{$ref: "#/components/parameters/AppID"}]
    get: {summary: List the current user's mobile login events, operationId: listMobileLoginEvents, tags: [mobile-security], responses: {"200": {description: Login events, content: {application/json: {schema: {$ref: "#/components/schemas/MobileLoginEventListResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}}}
  /api/v1/me/security-events:
    parameters: [{$ref: "#/components/parameters/AppID"}]
    get: {summary: List current-user security events, operationId: listMobileSecurityEvents, tags: [mobile-security], responses: {"200": {description: Security events, content: {application/json: {schema: {$ref: "#/components/schemas/MobileSecurityEventListResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}}}
  /admin-api/v1/mobile/releases:
    parameters: [{name: X-AppID, in: header, required: true, schema: {type: string, format: uuid}}]
    get:
      summary: List administrator-managed mobile release policies
      operationId: listAdminMobileReleases
      tags: [admin-releases]
      responses: {"200": {description: Global platform release policies, content: {application/json: {schema: {$ref: "#/components/schemas/AdminMobileReleaseListResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}}
    post:
      summary: Create a mobile release policy
      operationId: createAdminMobileRelease
      tags: [admin-releases]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminMobileReleaseRequest"}}}}
      responses: {"201": {description: Release policy created, content: {application/json: {schema: {$ref: "#/components/schemas/AdminMobileReleaseResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "403": {$ref: "#/components/responses/Forbidden"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /admin-api/v1/mobile/releases/{id}:
    parameters: [{name: X-AppID, in: header, required: true, schema: {type: string, format: uuid}}]
    get:
      summary: Read one mobile release through the compatibility entry
      operationId: getAdminMobileRelease
      tags: [admin-releases]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: Release detail, content: {application/json: {schema: {$ref: "#/components/schemas/AdminMobileReleaseResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "404": {$ref: "#/components/responses/NotFound"}}
    patch:
      summary: Update one mobile release policy using optimistic locking
      operationId: updateAdminMobileRelease
      tags: [admin-releases]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminMobileReleaseRequest"}}}}
      responses: {"200": {description: Release policy updated; platform is immutable and must match the stored record., content: {application/json: {schema: {$ref: "#/components/schemas/AdminMobileReleaseResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "403": {$ref: "#/components/responses/Forbidden"}, "409": {$ref: "#/components/responses/Conflict"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
    delete:
      summary: Delete one never-published release draft through the compatibility entry
      operationId: deleteAdminMobileRelease
      tags: [admin-releases]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: Draft deleted, content: {application/json: {schema: {$ref: "#/components/schemas/BooleanSuccessResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "409": {$ref: "#/components/responses/Conflict"}}
  /admin-api/v1/mobile/releases/batch-delete:
    post:
      summary: Atomically delete compatibility-entry release drafts
      operationId: batchDeleteAdminMobileReleases
      tags: [admin-releases]
      parameters: [{name: X-AppID, in: header, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/UUIDBatchRequest"}}}}
      responses: {"200": {description: Drafts deleted, content: {application/json: {schema: {$ref: "#/components/schemas/BooleanSuccessResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "409": {$ref: "#/components/responses/Conflict"}}
  /admin-api/v1/mobile/releases/{id}/publish:
    post:
      summary: Publish a release through the compatibility entry
      operationId: publishAdminMobileRelease
      tags: [admin-releases]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}, {name: X-AppID, in: header, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/LockVersionRequest"}}}}
      responses: {"200": {description: Release published, content: {application/json: {schema: {$ref: "#/components/schemas/AdminMobileReleaseResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "409": {$ref: "#/components/responses/Conflict"}}
  /admin-api/v1/mobile/releases/{id}/unpublish:
    post:
      summary: Unpublish a release through the compatibility entry
      operationId: unpublishAdminMobileRelease
      tags: [admin-releases]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}, {name: X-AppID, in: header, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/LockVersionRequest"}}}}
      responses: {"200": {description: Release unpublished, content: {application/json: {schema: {$ref: "#/components/schemas/AdminMobileReleaseResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "409": {$ref: "#/components/responses/Conflict"}}
  /admin-api/v1/apps:
    get:
      summary: List Apps scoped to the authenticated Admin tenant
      operationId: listAdminApps
      tags: [admin-app-management]
      security: [{adminBearer: []}]
      parameters: [{name: q, in: query, schema: {type: string, maxLength: 160}}, {name: app_type, in: query, schema: {type: string, enum: [uni_app, uni_app_x]}}, {name: status, in: query, schema: {type: string, enum: [active, disabled]}}, {name: page, in: query, schema: {type: integer, minimum: 1, default: 1}}, {name: page_size, in: query, schema: {type: integer, minimum: 1, maximum: 100, default: 20}}]
      responses: {"200": {description: Tenant Apps, content: {application/json: {schema: {$ref: "#/components/schemas/AdminAppListResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
    post:
      summary: Create a new App and its reserved single-page identities
      operationId: createAdminApp
      tags: [admin-app-management]
      security: [{adminBearer: []}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminAppRequest"}}}}
      responses: {"201": {description: App created, content: {application/json: {schema: {$ref: "#/components/schemas/AdminAppResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /admin-api/v1/apps/{app_id}:
    get:
      summary: Read one App scoped to the authenticated Admin tenant
      operationId: getAdminApp
      tags: [admin-app-management]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: App detail, content: {application/json: {schema: {$ref: "#/components/schemas/AdminAppResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "404": {$ref: "#/components/responses/NotFound"}}
    patch:
      summary: Update App registration and locale configuration with optimistic locking
      operationId: updateAdminApp
      tags: [admin-app-management]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminAppRequest"}}}}
      responses: {"200": {description: Updated App, content: {application/json: {schema: {$ref: "#/components/schemas/AdminAppResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "404": {$ref: "#/components/responses/NotFound"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
    delete:
      summary: Soft-delete one disabled non-default App
      operationId: deleteAdminApp
      tags: [admin-app-management]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: App soft-deleted., content: {application/json: {schema: {$ref: "#/components/schemas/BooleanSuccessResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "404": {$ref: "#/components/responses/NotFound"}, "409": {$ref: "#/components/responses/Conflict"}}
  /admin-api/v1/apps/batch-delete:
    post:
      summary: Atomically soft-delete up to 100 disabled non-default Apps
      operationId: batchDeleteAdminApps
      tags: [admin-app-management]
      security: [{adminBearer: []}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/UUIDBatchRequest"}}}}
      responses: {"200": {description: All Apps soft-deleted., content: {application/json: {schema: {$ref: "#/components/schemas/BooleanSuccessResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "409": {$ref: "#/components/responses/Conflict"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /admin-api/v1/apps/{app_id}/enable:
    post:
      summary: Enable an App using an optimistic-lock request body
      operationId: enableAdminApp
      tags: [admin-app-management]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminAppStatusRequest"}}}}
      responses: {"200": {description: Enabled App, content: {application/json: {schema: {$ref: "#/components/schemas/AdminAppResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "404": {$ref: "#/components/responses/NotFound"}, "409": {$ref: "#/components/responses/Conflict"}}
  /admin-api/v1/apps/{app_id}/disable:
    post:
      summary: Disable an App and reject subsequent mobile header resolution
      operationId: disableAdminApp
      tags: [admin-app-management]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminAppStatusRequest"}}}}
      responses: {"200": {description: Disabled App, content: {application/json: {schema: {$ref: "#/components/schemas/AdminAppResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "404": {$ref: "#/components/responses/NotFound"}, "409": {$ref: "#/components/responses/Conflict"}}
  /admin-api/v1/apps/{app_id}/startup/onboarding/publish:
    post:
      summary: Atomically publish an immutable onboarding revision
      operationId: publishAdminAppOnboarding
      tags: [admin-app-management]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminAppOnboardingPublishRequest"}}}}
      responses:
        "200": {description: Latest App startup configuration and published version., content: {application/json: {schema: {$ref: "#/components/schemas/AdminAppResponse"}}}}
        "403": {$ref: "#/components/responses/Forbidden"}
        "404": {$ref: "#/components/responses/NotFound"}
        "409": {description: The expected published version is stale., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}
        "422": {$ref: "#/components/responses/ValidationFailed"}
  /admin-api/v1/apps/{app_id}/mobile/releases:
    get:
      summary: List mobile release policies owned by the selected App
      operationId: listAdminAppMobileReleases
      tags: [admin-releases]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: q, in: query, schema: {type: string, maxLength: 160}}, {name: package_type, in: query, schema: {type: string, enum: [native_app, wgt]}}, {name: platform, in: query, schema: {type: string, enum: [android, ios, harmony]}}, {name: publish_status, in: query, schema: {type: string, enum: [draft, online, partial, offline]}}, {name: page, in: query, schema: {type: integer, minimum: 1, default: 1}}, {name: page_size, in: query, schema: {type: integer, minimum: 1, maximum: 100, default: 20}}]
      responses: {"200": {description: App release version history., content: {application/json: {schema: {$ref: "#/components/schemas/AdminMobileReleasePageResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "404": {$ref: "#/components/responses/NotFound"}}
    post:
      summary: Create a mobile release policy for the selected App
      operationId: createAdminAppMobileRelease
      tags: [admin-releases]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminMobileReleaseRequest"}}}}
      responses: {"201": {description: App release policy created., content: {application/json: {schema: {$ref: "#/components/schemas/AdminMobileReleaseResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /admin-api/v1/apps/{app_id}/mobile/releases/{id}:
    get:
      summary: Read one App release version
      operationId: getAdminAppMobileRelease
      tags: [admin-releases]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: Release detail., content: {application/json: {schema: {$ref: "#/components/schemas/AdminMobileReleaseResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "404": {$ref: "#/components/responses/NotFound"}}
    patch:
      summary: Update a mobile release policy owned by the selected App
      operationId: updateAdminAppMobileRelease
      tags: [admin-releases]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminMobileReleaseRequest"}}}}
      responses: {"200": {description: Updated App release policy., content: {application/json: {schema: {$ref: "#/components/schemas/AdminMobileReleaseResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "404": {$ref: "#/components/responses/NotFound"}, "409": {$ref: "#/components/responses/Conflict"}}
    delete:
      summary: Delete a never-published release draft
      operationId: deleteAdminAppMobileRelease
      tags: [admin-releases]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: Draft deleted., content: {application/json: {schema: {$ref: "#/components/schemas/BooleanSuccessResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "404": {$ref: "#/components/responses/NotFound"}, "409": {$ref: "#/components/responses/Conflict"}}
  /admin-api/v1/apps/{app_id}/mobile/releases/batch-delete:
    post:
      summary: Atomically delete up to 100 never-published release drafts
      operationId: batchDeleteAdminAppMobileReleases
      tags: [admin-releases]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/UUIDBatchRequest"}}}}
      responses: {"200": {description: Drafts deleted., content: {application/json: {schema: {$ref: "#/components/schemas/BooleanSuccessResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "409": {$ref: "#/components/responses/Conflict"}}
  /admin-api/v1/apps/{app_id}/mobile/releases/{id}/publish:
    post:
      summary: Atomically publish a release to every target platform
      operationId: publishAdminAppMobileRelease
      tags: [admin-releases]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/LockVersionRequest"}}}}
      responses: {"200": {description: Release published., content: {application/json: {schema: {$ref: "#/components/schemas/AdminMobileReleaseResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "409": {$ref: "#/components/responses/Conflict"}}
  /admin-api/v1/apps/{app_id}/mobile/releases/{id}/unpublish:
    post:
      summary: Remove this release from every current publication pointer
      operationId: unpublishAdminAppMobileRelease
      tags: [admin-releases]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/LockVersionRequest"}}}}
      responses: {"200": {description: Release taken offline., content: {application/json: {schema: {$ref: "#/components/schemas/AdminMobileReleaseResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "409": {$ref: "#/components/responses/Conflict"}}
  /admin-api/v1/apps/{app_id}/notices:
    get:
      summary: List App-scoped announcements
      operationId: listAdminAppNotices
      tags: [admin-app-communications]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: q, in: query, schema: {type: string, maxLength: 160}}, {name: status, in: query, schema: {type: string, enum: [draft, scheduled, published, cancelled]}}, {name: page, in: query, schema: {type: integer, minimum: 1, default: 1}}, {name: page_size, in: query, schema: {type: integer, minimum: 1, maximum: 100, default: 20}}]
      responses: {"200": {description: App notices., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationMessageListResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "404": {$ref: "#/components/responses/NotFound"}}
    post:
      summary: Create an App-scoped announcement draft
      operationId: createAdminAppNotice
      tags: [admin-app-communications]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationMessageRequest"}}}}
      responses: {"201": {description: App notice created., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationMessageResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /admin-api/v1/apps/{app_id}/notices/{id}:
    get:
      summary: Get an App-scoped announcement
      operationId: getAdminAppNotice
      tags: [admin-app-communications]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: App notice., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationMessageResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}}
    patch:
      summary: Update an App-scoped announcement
      operationId: updateAdminAppNotice
      tags: [admin-app-communications]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationMessageRequest"}}}}
      responses: {"200": {description: Updated App notice., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationMessageResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}, "409": {$ref: "#/components/responses/Conflict"}}
  /admin-api/v1/apps/{app_id}/notices/{id}/recipient-preview:
    post:
      summary: Preview recipients selected from the App membership set
      operationId: previewAdminAppNoticeRecipients
      tags: [admin-app-communications]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: App recipient preview., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationRecipientPreviewResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}}
  /admin-api/v1/apps/{app_id}/notices/{id}/{action}:
    post:
      summary: Publish or cancel an App-scoped announcement
      operationId: transitionAdminAppNotice
      tags: [admin-app-communications]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: id, in: path, required: true, schema: {type: string, format: uuid}}, {name: action, in: path, required: true, schema: {type: string, enum: [publish, cancel]}}]
      responses: {"200": {description: Transitioned App notice., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationMessageResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}, "409": {$ref: "#/components/responses/Conflict"}}
  /admin-api/v1/apps/{app_id}/notices/{id}/recipients:
    get:
      summary: Get App-scoped announcement recipient statistics
      operationId: getAdminAppNoticeRecipients
      tags: [admin-app-communications]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: App recipient statistics., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationRecipientStatsResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}}
  /admin-api/v1/apps/{app_id}/messages:
    get:
      summary: List App-scoped messages
      operationId: listAdminAppMessages
      tags: [admin-app-communications]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: q, in: query, schema: {type: string, maxLength: 160}}, {name: status, in: query, schema: {type: string, enum: [draft, scheduled, published, cancelled]}}, {name: message_type, in: query, schema: {type: string, enum: [system, private, marketing, security]}}, {name: page, in: query, schema: {type: integer, minimum: 1, default: 1}}, {name: page_size, in: query, schema: {type: integer, minimum: 1, maximum: 100, default: 20}}]
      responses: {"200": {description: App messages., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationMessageListResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "404": {$ref: "#/components/responses/NotFound"}}
    post:
      summary: Create an App-scoped message draft
      operationId: createAdminAppMessage
      tags: [admin-app-communications]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationMessageRequest"}}}}
      responses: {"201": {description: App message created., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationMessageResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /admin-api/v1/apps/{app_id}/messages/{id}:
    get:
      summary: Get an App-scoped message
      operationId: getAdminAppMessage
      tags: [admin-app-communications]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: App message., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationMessageResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}}
    patch:
      summary: Update an App-scoped message
      operationId: updateAdminAppMessage
      tags: [admin-app-communications]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationMessageRequest"}}}}
      responses: {"200": {description: Updated App message., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationMessageResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}, "409": {$ref: "#/components/responses/Conflict"}}
  /admin-api/v1/apps/{app_id}/messages/{id}/recipient-preview:
    post:
      summary: Preview recipients selected from the App membership set
      operationId: previewAdminAppMessageRecipients
      tags: [admin-app-communications]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: App recipient preview., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationRecipientPreviewResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}}
  /admin-api/v1/apps/{app_id}/messages/{id}/{action}:
    post:
      summary: Publish or cancel an App-scoped message
      operationId: transitionAdminAppMessage
      tags: [admin-app-communications]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: id, in: path, required: true, schema: {type: string, format: uuid}}, {name: action, in: path, required: true, schema: {type: string, enum: [publish, cancel]}}]
      responses: {"200": {description: Transitioned App message., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationMessageResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}, "409": {$ref: "#/components/responses/Conflict"}}
  /admin-api/v1/apps/{app_id}/messages/{id}/recipients:
    get:
      summary: Get App-scoped message recipient statistics
      operationId: getAdminAppMessageRecipients
      tags: [admin-app-communications]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: App recipient statistics., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationRecipientStatsResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}}
  /admin-api/v1/apps/{app_id}/content/categories:
    get:
      summary: List categories belonging only to the selected App
      operationId: listAdminAppContentCategories
      tags: [admin-app-content]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: q, in: query, schema: {type: string, maxLength: 160}}, {name: status, in: query, schema: {type: string, enum: [active, disabled]}}, {name: page, in: query, schema: {type: integer, minimum: 1, default: 1}}, {name: page_size, in: query, schema: {type: integer, minimum: 1, maximum: 100, default: 20}}]
      responses: {"200": {description: App category page., content: {application/json: {schema: {$ref: "#/components/schemas/AdminContentCategoryListResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "404": {$ref: "#/components/responses/NotFound"}}
    post:
      summary: Create a category owned by the selected App
      operationId: createAdminAppContentCategory
      tags: [admin-app-content]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminContentCategoryRequest"}}}}
      responses: {"201": {description: Created., content: {application/json: {schema: {$ref: "#/components/schemas/AdminContentCategoryResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "422": {$ref: "#/components/responses/ValidationFailed"}, "409": {$ref: "#/components/responses/Conflict"}}
  /admin-api/v1/apps/{app_id}/content/categories/{id}:
    get:
      summary: Read one category owned by the selected App
      operationId: getAdminAppContentCategory
      tags: [admin-app-content]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: Category., content: {application/json: {schema: {$ref: "#/components/schemas/AdminContentCategoryResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}}
    patch:
      summary: Update an App-owned category with optimistic locking
      operationId: updateAdminAppContentCategory
      tags: [admin-app-content]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminContentCategoryUpdateRequest"}}}}
      responses: {"200": {description: Updated., content: {application/json: {schema: {$ref: "#/components/schemas/AdminContentCategoryResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}, "409": {$ref: "#/components/responses/Conflict"}}
    delete:
      summary: Delete an unused App-owned category
      operationId: deleteAdminAppContentCategory
      tags: [admin-app-content]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: id, in: path, required: true, schema: {type: string, format: uuid}}, {name: lock_version, in: query, required: true, schema: {type: integer, minimum: 1}}]
      responses: {"200": {description: Deleted., content: {application/json: {schema: {$ref: "#/components/schemas/AdminDeleteResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}, "409": {$ref: "#/components/responses/Conflict"}}
  /admin-api/v1/apps/{app_id}/content/articles:
    get:
      summary: List articles belonging only to the selected App
      operationId: listAdminAppContentArticles
      tags: [admin-app-content]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: q, in: query, schema: {type: string, maxLength: 160}}, {name: category_id, in: query, schema: {type: string, format: uuid}}, {name: status, in: query, schema: {type: string, enum: [draft, published, archived]}}, {name: featured, in: query, schema: {type: boolean}}, {name: page, in: query, schema: {type: integer, minimum: 1, default: 1}}, {name: page_size, in: query, schema: {type: integer, minimum: 1, maximum: 100, default: 20}}]
      responses: {"200": {description: App article page., content: {application/json: {schema: {$ref: "#/components/schemas/AdminContentArticleListResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "404": {$ref: "#/components/responses/NotFound"}}
    post:
      summary: Create an App-owned draft article
      operationId: createAdminAppContentArticle
      tags: [admin-app-content]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminContentArticleRequest"}}}}
      responses: {"201": {description: Created., content: {application/json: {schema: {$ref: "#/components/schemas/AdminContentArticleResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "422": {$ref: "#/components/responses/ValidationFailed"}, "409": {$ref: "#/components/responses/Conflict"}}
  /admin-api/v1/apps/{app_id}/content/articles/{id}:
    get:
      summary: Read one App-owned article
      operationId: getAdminAppContentArticle
      tags: [admin-app-content]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: Article., content: {application/json: {schema: {$ref: "#/components/schemas/AdminContentArticleResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}}
    patch:
      summary: Update an App-owned article using lock_version
      operationId: updateAdminAppContentArticle
      tags: [admin-app-content]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminContentArticleUpdateRequest"}}}}
      responses: {"200": {description: Updated., content: {application/json: {schema: {$ref: "#/components/schemas/AdminContentArticleResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}, "409": {$ref: "#/components/responses/Conflict"}}
    delete:
      summary: Delete an App-owned draft article
      operationId: deleteAdminAppContentArticle
      tags: [admin-app-content]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: id, in: path, required: true, schema: {type: string, format: uuid}}, {name: lock_version, in: query, required: true, schema: {type: integer, minimum: 1}}]
      responses: {"200": {description: Deleted., content: {application/json: {schema: {$ref: "#/components/schemas/AdminDeleteResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}, "409": {$ref: "#/components/responses/Conflict"}}
  /admin-api/v1/apps/{app_id}/content/articles/{id}/{transition}:
    post:
      summary: Transition an App-owned article using its lifecycle action
      operationId: transitionAdminAppContentArticle
      tags: [admin-app-content]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: id, in: path, required: true, schema: {type: string, format: uuid}}, {name: transition, in: path, required: true, schema: {type: string, enum: [publish, unpublish, archive]}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminContentTransitionRequest"}}}}
      responses: {"200": {description: Transitioned., content: {application/json: {schema: {$ref: "#/components/schemas/AdminContentArticleResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}, "409": {$ref: "#/components/responses/Conflict"}}
  /admin-api/v1/apps/{app_id}/content/pages:
    get:
      summary: List App-scoped single pages and their current revisions
      operationId: listAdminAppPages
      tags: [admin-app-content]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: q, in: query, schema: {type: string, maxLength: 160}}, {name: status, in: query, schema: {type: string, enum: [draft, published, archived]}}, {name: page, in: query, schema: {type: integer, minimum: 1, default: 1}}, {name: page_size, in: query, schema: {type: integer, minimum: 1, maximum: 100, default: 20}}]
      responses: {"200": {description: Pages belonging only to the selected App., content: {application/json: {schema: {$ref: "#/components/schemas/AdminAppPageListResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "404": {$ref: "#/components/responses/NotFound"}}
    post:
      summary: Create a custom page or append a versioned revision to a reserved App page
      operationId: saveAdminAppPage
      tags: [admin-app-content]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminAppPageRequest"}}}}
      responses: {"200": {description: Versioned page saved; publish atomically updates current_revision_id., content: {application/json: {schema: {$ref: "#/components/schemas/AdminAppPageResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "404": {$ref: "#/components/responses/NotFound"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /admin-api/v1/apps/{app_id}/content/pages/{slug}:
    patch:
      summary: Save an App page draft revision without replacing the current published revision
      operationId: saveAdminAppPageDraft
      tags: [admin-app-content]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: slug, in: path, required: true, schema: {type: string, pattern: '^[a-z0-9]+(?:-[a-z0-9]+)*$'}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminAppPageRequest"}}}}
      responses: {"200": {description: Draft revision saved., content: {application/json: {schema: {$ref: "#/components/schemas/AdminAppPageResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "404": {$ref: "#/components/responses/NotFound"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
    delete:
      summary: Delete a custom App page; reserved legal and about pages are immutable
      operationId: deleteAdminAppPage
      tags: [admin-app-content]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: slug, in: path, required: true, schema: {type: string, pattern: '^[a-z0-9]+(?:-[a-z0-9]+)*$'}}, {name: lock_version, in: query, required: true, schema: {type: integer, minimum: 1}}]
      responses: {"200": {description: Custom page deleted., content: {application/json: {schema: {$ref: "#/components/schemas/AdminDeleteResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "404": {$ref: "#/components/responses/NotFound"}, "409": {$ref: "#/components/responses/Conflict"}}
  /admin-api/v1/apps/{app_id}/content/pages/{slug}/publish:
    post:
      summary: Publish the newest draft revision of an App page
      operationId: publishAdminAppPage
      tags: [admin-app-content]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: slug, in: path, required: true, schema: {type: string, pattern: '^[a-z0-9]+(?:-[a-z0-9]+)*$'}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminContentTransitionRequest"}}}}
      responses: {"200": {description: Draft published atomically., content: {application/json: {schema: {$ref: "#/components/schemas/AdminAppPageResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "404": {$ref: "#/components/responses/NotFound"}, "409": {$ref: "#/components/responses/Conflict"}}
  /admin-api/v1/apps/{app_id}/users:
    get:
      summary: List only users explicitly associated with the selected App
      operationId: listAdminAppUsers
      tags: [admin-app-users]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: q, in: query, schema: {type: string, maxLength: 160}}, {name: status, in: query, schema: {type: string, enum: [pending_verification, active, disabled]}}, {name: page, in: query, schema: {type: integer, minimum: 1, default: 1}}, {name: page_size, in: query, schema: {type: integer, minimum: 1, maximum: 100, default: 20}}]
      responses: {"200": {description: App memberships, content: {application/json: {schema: {$ref: "#/components/schemas/AdminAppUserListResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "404": {$ref: "#/components/responses/NotFound"}}
    post:
      summary: Create an App user identity and active App membership
      operationId: createAdminAppUser
      tags: [admin-app-users]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminAppUserCreateRequest"}}}}
      responses: {"201": {description: App user created, content: {application/json: {schema: {$ref: "#/components/schemas/AdminAppUserResponse"}}}}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /admin-api/v1/apps/{app_id}/users/{user_id}:
    get:
      summary: Read one explicit App membership
      operationId: getAdminAppUser
      tags: [admin-app-users]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: user_id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: App user detail, content: {application/json: {schema: {$ref: "#/components/schemas/AdminAppUserResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "404": {$ref: "#/components/responses/NotFound"}}
    patch:
      summary: Update permitted profile fields for an App user
      operationId: updateAdminAppUser
      tags: [admin-app-users]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: user_id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminAppUserUpdateRequest"}}}}
      responses: {"200": {description: Updated App user, content: {application/json: {schema: {$ref: "#/components/schemas/AdminAppUserResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}}
  /admin-api/v1/apps/{app_id}/users/{user_id}/enable:
    post:
      summary: Enable an App user membership without changing global IAM identity status
      operationId: enableAdminAppUser
      tags: [admin-app-users]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: user_id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminAppUserActionRequest"}}}}
      responses: {"200": {description: App membership enabled, content: {application/json: {schema: {$ref: "#/components/schemas/AdminAppUserResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "404": {$ref: "#/components/responses/NotFound"}, "409": {$ref: "#/components/responses/Conflict"}}
  /admin-api/v1/apps/{app_id}/users/{user_id}/disable:
    post:
      summary: Disable an App membership and revoke only that App's mobile sessions
      operationId: disableAdminAppUser
      tags: [admin-app-users]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: user_id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminAppUserActionRequest"}}}}
      responses: {"200": {description: App membership disabled, content: {application/json: {schema: {$ref: "#/components/schemas/AdminAppUserResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "404": {$ref: "#/components/responses/NotFound"}, "409": {$ref: "#/components/responses/Conflict"}}
  /admin-api/v1/apps/{app_id}/users/{user_id}/unlock:
    post:
      summary: Clear an App user's credential lock state
      operationId: unlockAdminAppUser
      tags: [admin-app-users]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: user_id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminAppUserActionRequest"}}}}
      responses: {"200": {description: User credential unlocked and membership lock incremented, content: {application/json: {schema: {$ref: "#/components/schemas/AdminAppUserResponse"}}}}, "409": {$ref: "#/components/responses/Conflict"}}
  /admin-api/v1/apps/{app_id}/users/{user_id}/reset-password:
    post:
      summary: Reset global credentials and revoke only the selected App mobile sessions
      operationId: resetAdminAppUserPassword
      tags: [admin-app-users]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: user_id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminAppPasswordResetRequest"}}}}
      responses: {"200": {description: Password reset and membership lock incremented, content: {application/json: {schema: {$ref: "#/components/schemas/AdminAppUserResponse"}}}}, "409": {$ref: "#/components/responses/Conflict"}}
  /admin-api/v1/apps/{app_id}/users/{user_id}/sessions/revoke:
    post:
      summary: Revoke active ak-mobile sessions belonging to the selected App only
      operationId: revokeAdminAppUserSessions
      tags: [admin-app-users]
      security: [{adminBearer: []}]
      parameters: [{name: app_id, in: path, required: true, schema: {type: string, format: uuid}}, {name: user_id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminAppUserActionRequest"}}}}
      responses: {"200": {description: Current App sessions revoked and membership lock incremented, content: {application/json: {schema: {$ref: "#/components/schemas/AdminAppUserResponse"}}}}, "409": {$ref: "#/components/responses/Conflict"}}
  /admin-api/v1/auth/login:
    post:
      summary: Sign in to the Admin application with a password
      operationId: adminLogin
      tags: [admin-auth-profile]
      security: []
      parameters:
        - $ref: "#/components/parameters/AcceptLanguage"
        - $ref: "#/components/parameters/AdminDeviceKey"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AdminLoginRequest"
      responses:
        "200":
          description: Signed in. The opaque refresh token is returned only as an HttpOnly cookie.
          headers:
            Cache-Control:
              schema: {type: string, const: no-store}
            Set-Cookie:
              schema: {type: string}
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminTokenResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "422":
          $ref: "#/components/responses/ValidationFailed"
  /api/v1/public/dictionaries/{code}:
    parameters: [{$ref: "#/components/parameters/AppID"}]
    get:
      summary: Resolve an active public dictionary using tenant-neutral locale fallback
      operationId: getPublicDictionary
      tags: [public-dictionary]
      security: []
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}, {name: code, in: path, required: true, schema: {type: string, pattern: "^[a-z][a-z0-9_.-]{1,159}$"}}]
      responses: {"200": {description: Public consumption fields only., content: {application/json: {schema: {$ref: "#/components/schemas/ResolvedDictionaryResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}}
  /admin-api/v1/auth/login/captcha:
    post:
      summary: Create a short-lived image CAPTCHA for an Admin login retry
      description: Creates a single-use PNG challenge bound to the normalized email, Admin audience, and request source. Creating a new challenge invalidates an earlier active challenge for the same scope.
      operationId: createAdminLoginCaptcha
      tags: [admin-auth-profile]
      security: []
      parameters:
        - $ref: "#/components/parameters/AcceptLanguage"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AdminLoginCaptchaRequest"
      responses:
        "200":
          description: A non-cacheable, short-lived, single-use PNG challenge.
          headers:
            Cache-Control:
              schema: {type: string, const: no-store}
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminLoginCaptchaResponse"
        "422":
          $ref: "#/components/responses/ValidationFailed"
  /admin-api/v1/auth/public-config:
    get:
      summary: Read public Admin authentication configuration
      operationId: getAdminPublicConfig
      tags: [admin-auth-profile]
      security: []
      parameters:
        - $ref: "#/components/parameters/AcceptLanguage"
      responses:
        "200":
          description: Public Admin locale and authentication feature flags.
          headers:
            Cache-Control:
              schema: {type: string, const: no-store}
            Content-Language:
              schema:
                $ref: "#/components/schemas/SupportedLocale"
            Vary:
              schema: {type: string, const: Accept-Language}
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PublicConfigResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
  /admin-api/v1/auth/register:
    post:
      summary: Request self-service registration in the configured Admin tenant
      operationId: registerAdminAccount
      tags: [admin-auth-profile]
      security: []
      parameters:
        - $ref: "#/components/parameters/AcceptLanguage"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AdminRegistrationRequest"
      responses:
        "202":
          description: Registration request accepted. Existing and newly created accounts use the same response.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminRegistrationResponse"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/ValidationFailed"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /admin-api/v1/auth/password/forgot:
    post:
      summary: Request an Admin password reset without revealing account existence
      operationId: requestAdminPasswordReset
      tags: [admin-auth-profile]
      security: []
      parameters:
        - $ref: "#/components/parameters/AcceptLanguage"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AdminForgotPasswordRequest"
      responses:
        "202":
          description: The generic recovery request was accepted for both known and unknown accounts.
          headers:
            Retry-After:
              schema: {type: integer, minimum: 1}
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminForgotPasswordResponse"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/ValidationFailed"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /admin-api/v1/auth/password/reset:
    post:
      summary: Consume a one-time Admin password reset token and revoke existing sessions
      operationId: resetAdminPassword
      tags: [admin-auth-profile]
      security: []
      parameters:
        - $ref: "#/components/parameters/AcceptLanguage"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AdminResetPasswordRequest"
      responses:
        "200":
          description: Password reset and existing session revocation completed transactionally.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminResetPasswordResponse"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/ValidationFailed"
  /admin-api/v1/auth/token/refresh:
    post:
      summary: Rotate the Admin refresh token and issue a new access token
      operationId: refreshAdminToken
      tags: [admin-auth-profile]
      security:
        - adminRefreshCookie: []
      parameters:
        - $ref: "#/components/parameters/AcceptLanguage"
        - $ref: "#/components/parameters/CSRFToken"
      responses:
        "200":
          description: Token family rotated successfully.
          headers:
            Cache-Control:
              schema: {type: string, const: no-store}
            Set-Cookie:
              schema: {type: string}
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminTokenResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
  /admin-api/v1/auth/logout:
    post:
      summary: Revoke the current Admin session
      operationId: adminLogout
      tags: [admin-auth-profile]
      security:
        - adminBearer: []
          adminRefreshCookie: []
      parameters:
        - $ref: "#/components/parameters/AcceptLanguage"
        - $ref: "#/components/parameters/CSRFToken"
      responses:
        "200":
          description: Current session revoked and cookies cleared.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminLogoutResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
  /admin-api/v1/auth/context:
    get:
      summary: Read the current Admin identity, tenant and authorization context
      operationId: getAdminAuthContext
      tags: [admin-auth-profile]
      security:
        - adminBearer: []
      parameters:
        - $ref: "#/components/parameters/AcceptLanguage"
      responses:
        "200":
          description: Current authorization context.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminAuthContextResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
  /admin-api/v1/auth/switch-tenant:
    post:
      summary: Switch the current Admin session to another available tenant
      operationId: switchAdminTenant
      tags: [admin-auth-profile]
      security:
        - adminBearer: []
      parameters:
        - $ref: "#/components/parameters/AcceptLanguage"
        - $ref: "#/components/parameters/AdminDeviceKey"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AdminSwitchTenantRequest"
      responses:
        "200":
          description: A new tenant-scoped session was issued and the previous session was revoked.
          headers:
            Cache-Control:
              schema: {type: string, const: no-store}
            Set-Cookie:
              schema: {type: string}
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminTokenResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/ValidationFailed"
  /admin-api/v1/me:
    get:
      summary: Read the current Admin user's profile
      operationId: getAdminMe
      tags: [admin-auth-profile]
      security:
        - adminBearer: []
      parameters:
        - $ref: "#/components/parameters/AcceptLanguage"
      responses:
        "200":
          description: Current self-scoped profile. No RBAC permission is required beyond an active Admin session.
          headers:
            Cache-Control:
              schema: {type: string, const: no-store}
            Content-Language:
              schema:
                $ref: "#/components/schemas/SupportedLocale"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminMeResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
    patch:
      summary: Update the current Admin user's basic profile settings
      operationId: updateAdminMe
      tags: [admin-auth-profile]
      security:
        - adminBearer: []
      parameters:
        - $ref: "#/components/parameters/AcceptLanguage"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AdminUpdateMeRequest"
      responses:
        "200":
          description: Profile updated and an immutable operation audit record written. This endpoint is self-scoped and does not use an RBAC permission code.
          headers:
            Cache-Control:
              schema: {type: string, const: no-store}
            Content-Language:
              schema:
                $ref: "#/components/schemas/SupportedLocale"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminMeResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "422":
          $ref: "#/components/responses/ValidationFailed"
  /admin-api/v1/me/avatar/upload-session:
    post:
      summary: Create a self-scoped avatar upload session
      description: Creates a short-lived upload target for the authenticated user's browser-cropped avatar. The server selects tenant, owner, configured local/S3/MinIO provider and random object key; the client cannot provide them or receive storage credentials.
      operationId: createAdminSelfAvatarUploadSession
      tags: [admin-auth-profile]
      security:
        - adminBearer: []
      parameters:
        - $ref: "#/components/parameters/AcceptLanguage"
      requestBody:
        required: true
        content:
          application/json:
            schema: {$ref: "#/components/schemas/AdminAvatarUploadRequest"}
      responses:
        "201":
          description: Short-lived upload session created.
          content:
            application/json:
              schema: {$ref: "#/components/schemas/AdminAvatarUploadSessionResponse"}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "404": {$ref: "#/components/responses/NotFound"}
        "422": {$ref: "#/components/responses/ValidationFailed"}
  /admin-api/v1/me/avatar/upload-sessions/{id}/content:
    put:
      summary: Upload and attach browser-cropped avatar content
      description: Uploads through the tenant's configured ObjectStore adapter (development local, S3, or MinIO), then validates MIME magic, dimensions, size and ownership before attaching the object to the current user.
      operationId: uploadAdminSelfAvatarContent
      tags: [admin-auth-profile]
      security:
        - adminBearer: []
      parameters:
        - $ref: "#/components/parameters/AcceptLanguage"
        - name: id
          in: path
          required: true
          schema: {type: string, format: uuid}
      requestBody:
        required: true
        content:
          image/jpeg: {schema: {type: string, format: binary}}
          image/png: {schema: {type: string, format: binary}}
          image/webp: {schema: {type: string, format: binary}}
      responses:
        "200":
          description: Content validated, stored, attached and audited transactionally.
          content:
            application/json:
              schema: {$ref: "#/components/schemas/AdminAvatarUploadCompleteResponse"}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "404": {$ref: "#/components/responses/NotFound"}
        "422": {$ref: "#/components/responses/ValidationFailed"}
  /admin-api/v1/me/avatar/content:
    get:
      summary: Read the current Admin user's private avatar
      operationId: getAdminSelfAvatarContent
      tags: [admin-auth-profile]
      security:
        - adminBearer: []
      responses:
        "200":
          description: Private avatar bytes after owner, tenant, status and scan gate checks.
          headers:
            ETag: {schema: {type: string}}
            Cache-Control: {schema: {type: string}}
          content:
            image/jpeg: {schema: {type: string, format: binary}}
            image/png: {schema: {type: string, format: binary}}
            image/webp: {schema: {type: string, format: binary}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "404": {$ref: "#/components/responses/NotFound"}
  /admin-api/v1/me/sessions:
    get:
      summary: List the current Admin user's active sessions
      operationId: listAdminSelfSessions
      tags: [admin-auth-profile]
      security:
        - adminBearer: []
      parameters:
        - $ref: "#/components/parameters/AcceptLanguage"
      responses:
        "200":
          description: Active sessions scoped to the authenticated user, tenant and Admin audience. No RBAC permission is required beyond an active Admin session.
          headers:
            Cache-Control:
              schema: {type: string, const: no-store}
            Content-Language:
              schema:
                $ref: "#/components/schemas/SupportedLocale"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminSelfSessionListResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
  /admin-api/v1/me/sessions/{id}:
    delete:
      summary: Revoke one of the current Admin user's sessions
      operationId: revokeAdminSelfSession
      tags: [admin-auth-profile]
      security:
        - adminBearer: []
      parameters:
        - $ref: "#/components/parameters/AcceptLanguage"
        - name: id
          in: path
          required: true
          schema: {type: string, format: uuid}
      responses:
        "200":
          description: The self-scoped session and its refresh token family were revoked and an immutable operation audit record was written.
          headers:
            Cache-Control:
              schema: {type: string, const: no-store}
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminSelfSessionRevokeResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/ValidationFailed"
  /admin-api/v1/me/devices:
    get:
      summary: List the current Admin user's registered Web devices
      operationId: listAdminSelfDevices
      tags: [admin-auth-profile]
      security:
        - adminBearer: []
      parameters:
        - $ref: "#/components/parameters/AcceptLanguage"
      responses:
        "200":
          description: Devices associated with this user, tenant and Admin audience. No RBAC permission is required beyond an active Admin session.
          headers:
            Cache-Control:
              schema: {type: string, const: no-store}
            Content-Language:
              schema:
                $ref: "#/components/schemas/SupportedLocale"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminSelfDeviceListResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
  /admin-api/v1/me/devices/{id}:
    delete:
      summary: Remove one of the current Admin user's registered devices
      operationId: removeAdminSelfDevice
      tags: [admin-auth-profile]
      security:
        - adminBearer: []
      parameters:
        - $ref: "#/components/parameters/AcceptLanguage"
        - name: id
          in: path
          required: true
          schema: {type: string, format: uuid}
      responses:
        "200":
          description: All sessions and refresh token families associated with the device were revoked, the device was removed, and an immutable operation audit record was written.
          headers:
            Cache-Control:
              schema: {type: string, const: no-store}
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminSelfDeviceRemoveResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/ValidationFailed"
  /admin-api/v1/me/password/change:
    post:
      summary: Change the current Admin user's password
      operationId: changeAdminSelfPassword
      tags: [admin-auth-profile]
      security:
        - adminBearer: []
      parameters:
        - $ref: "#/components/parameters/AcceptLanguage"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AdminSelfPasswordChangeRequest"
      responses:
        "200":
          description: Password changed, current session preserved, all other sessions and refresh token families revoked, and an immutable operation audit record written.
          headers:
            Cache-Control:
              schema: {type: string, const: no-store}
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminSelfPasswordChangeResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "409":
          description: Password was changed concurrently or the new password was used recently.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "422":
          $ref: "#/components/responses/ValidationFailed"
  /admin-api/v1/me/mfa:
    get:
      summary: Read the current Admin user's MFA status
      operationId: getAdminSelfMfa
      tags: [admin-auth-profile]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      responses:
        "200": {description: MFA status without secret material., content: {application/json: {schema: {$ref: "#/components/schemas/AdminMfaStatusResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
  /admin-api/v1/me/mfa/totp/enroll:
    post:
      summary: Start a one-time TOTP enrollment
      description: The plaintext secret and otpauth URI are returned only by this response and are never returned by status or list APIs.
      operationId: enrollAdminSelfTotp
      tags: [admin-auth-profile]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      responses:
        "201": {description: Pending enrollment created with one-time secret material., content: {application/json: {schema: {$ref: "#/components/schemas/AdminTotpEnrollmentResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "409": {description: TOTP is already active., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}
  /admin-api/v1/me/mfa/totp/verify:
    post:
      summary: Verify and activate a pending TOTP enrollment
      operationId: verifyAdminSelfTotp
      tags: [admin-auth-profile]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminTotpVerifyRequest"}}}}
      responses:
        "200": {description: TOTP activated and one-time recovery codes returned., content: {application/json: {schema: {$ref: "#/components/schemas/AdminRecoveryCodesResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "422": {$ref: "#/components/responses/ValidationFailed"}
  /admin-api/v1/me/mfa/totp:
    delete:
      summary: Disable TOTP after step-up confirmation
      operationId: disableAdminSelfTotp
      tags: [admin-auth-profile]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminStepUpRequest"}}}}
      responses:
        "200": {description: TOTP disabled and recovery codes invalidated., content: {application/json: {schema: {$ref: "#/components/schemas/AdminMfaDisableResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "404": {$ref: "#/components/responses/NotFound"}
  /admin-api/v1/me/mfa/recovery-codes/rotate:
    post:
      summary: Rotate recovery codes after step-up confirmation
      operationId: rotateAdminSelfRecoveryCodes
      tags: [admin-auth-profile]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminStepUpRequest"}}}}
      responses:
        "200": {description: Previous codes invalidated and replacement codes returned once., content: {application/json: {schema: {$ref: "#/components/schemas/AdminRecoveryCodesResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "409": {description: Recovery codes require an active TOTP factor., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}
  /admin-api/v1/me/oauth-accounts:
    get:
      summary: List the current Admin user's OAuth connections
      operationId: listAdminSelfOAuthAccounts
      tags: [admin-auth-profile]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      responses:
        "200": {description: Safe provider and account hints only., content: {application/json: {schema: {$ref: "#/components/schemas/AdminOAuthAccountListResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
  /admin-api/v1/me/oauth/{provider}/start:
    post:
      summary: Start an OAuth binding with state and S256 PKCE
      operationId: startAdminSelfOAuth
      tags: [admin-auth-profile]
      security: [{adminBearer: []}]
      parameters:
        - {$ref: "#/components/parameters/AcceptLanguage"}
        - {name: provider, in: path, required: true, schema: {type: string, pattern: "^[a-z][a-z0-9-]{1,62}$"}}
      responses:
        "201": {description: Short-lived provider authorization URL created., content: {application/json: {schema: {$ref: "#/components/schemas/AdminOAuthStartResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "503": {$ref: "#/components/responses/ServiceUnavailable"}
  /admin-api/v1/me/oauth/{provider}/callback:
    post:
      summary: Complete a self-service OAuth binding callback
      description: Consumes a single-use state and authorization code. Provider token material is never returned to the browser.
      operationId: completeAdminSelfOAuth
      tags: [admin-auth-profile]
      security: [{adminBearer: []}]
      parameters:
        - {$ref: "#/components/parameters/AcceptLanguage"}
        - {name: provider, in: path, required: true, schema: {type: string, pattern: "^[a-z][a-z0-9-]{1,62}$"}}
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminOAuthCallbackRequest"}}}}
      responses:
        "200": {description: OAuth account connected and challenge consumed., content: {application/json: {schema: {$ref: "#/components/schemas/AdminOAuthAccountResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "422": {$ref: "#/components/responses/ValidationFailed"}
  /admin-api/v1/me/oauth/{provider}:
    delete:
      summary: Unbind an OAuth account while preserving another login method
      operationId: deleteAdminSelfOAuth
      tags: [admin-auth-profile]
      security: [{adminBearer: []}]
      parameters:
        - {$ref: "#/components/parameters/AcceptLanguage"}
        - {name: provider, in: path, required: true, schema: {type: string, pattern: "^[a-z][a-z0-9-]{1,62}$"}}
      responses:
        "200": {description: OAuth account unbound and audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminOAuthUnbindResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "404": {$ref: "#/components/responses/NotFound"}
        "409": {description: Another login method is required before unbinding., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}
  /admin-api/v1/dashboard/summary:
    get:
      summary: Read permission-pruned Admin dashboard KPI metrics
      operationId: getAdminDashboardSummary
      tags: [admin-dashboard]
      security:
        - adminBearer: []
      parameters:
        - $ref: "#/components/parameters/AcceptLanguage"
        - $ref: "#/components/parameters/DashboardRange"
      responses:
        "200":
          description: Tenant-scoped KPI metrics. Metrics the caller cannot read are omitted rather than represented as zero.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminDashboardSummaryResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "422":
          $ref: "#/components/responses/ValidationFailed"
  /admin-api/v1/dashboard/trends:
    get:
      summary: Read permission-pruned Admin dashboard daily trends
      operationId: getAdminDashboardTrends
      tags: [admin-dashboard]
      security:
        - adminBearer: []
      parameters:
        - $ref: "#/components/parameters/AcceptLanguage"
        - $ref: "#/components/parameters/DashboardRange"
      responses:
        "200":
          description: Tenant-scoped daily series. Series the caller cannot read are omitted.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminDashboardTrendsResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "422":
          $ref: "#/components/responses/ValidationFailed"
  /admin-api/v1/dashboard/activity:
    get:
      summary: Read permission-pruned, redacted Admin dashboard activity
      operationId: getAdminDashboardActivity
      tags: [admin-dashboard]
      security:
        - adminBearer: []
      parameters:
        - $ref: "#/components/parameters/AcceptLanguage"
        - $ref: "#/components/parameters/DashboardRange"
      responses:
        "200":
          description: Up to ten recent records per permitted tenant-scoped activity category. Raw details, payloads and error messages are not returned.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminDashboardActivityResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "422":
          $ref: "#/components/responses/ValidationFailed"
  /admin-api/v1/org/units/tree:
    get:
      summary: Read the tenant-scoped organization unit tree
      operationId: listAdminOrgUnitTree
      tags: [admin-organization]
      security: [{adminBearer: []}]
      parameters:
        - $ref: "#/components/parameters/AcceptLanguage"
        - {name: q, in: query, schema: {type: string, maxLength: 160}}
        - {name: status, in: query, schema: {$ref: "#/components/schemas/OrgStatus"}}
      responses:
        "200": {description: Organization unit tree., content: {application/json: {schema: {$ref: "#/components/schemas/AdminOrgUnitTreeResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "422": {$ref: "#/components/responses/ValidationFailed"}
  /admin-api/v1/org/units:
    post:
      summary: Create an organization unit
      operationId: createAdminOrgUnit
      tags: [admin-organization]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminOrgUnitRequest"}}}}
      responses:
        "201": {description: Unit created and audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminOrgUnitResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "409": {description: Unit code already exists., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}
        "422": {$ref: "#/components/responses/ValidationFailed"}
  /admin-api/v1/org/units/{id}:
    parameters: [{$ref: "#/components/parameters/OrgResourceID"}]
    patch:
      summary: Update an organization unit without changing its parent
      operationId: updateAdminOrgUnit
      tags: [admin-organization]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminOrgUnitRequest"}}}}
      responses:
        "200": {description: Unit updated and audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminOrgUnitResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "404": {$ref: "#/components/responses/NotFound"}
        "409": {description: Unit code already exists., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}
        "422": {$ref: "#/components/responses/ValidationFailed"}
    delete:
      summary: Delete an empty organization unit
      operationId: deleteAdminOrgUnit
      tags: [admin-organization]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      responses:
        "200": {description: Unit soft-deleted and audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminDeleteResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "404": {$ref: "#/components/responses/NotFound"}
        "409": {description: Unit has child units or direct members. Counts are returned in error details., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}
  /admin-api/v1/org/units/{id}/move:
    parameters: [{$ref: "#/components/parameters/OrgResourceID"}]
    post:
      summary: Move an organization unit using an accessible keyboard-compatible form
      operationId: moveAdminOrgUnit
      tags: [admin-organization]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminOrgUnitMoveRequest"}}}}
      responses:
        "200": {description: Unit moved and audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminOrgUnitResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "404": {$ref: "#/components/responses/NotFound"}
        "409": {description: Move would create a cycle., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}
        "422": {$ref: "#/components/responses/ValidationFailed"}
  /admin-api/v1/org/positions:
    get:
      summary: List tenant-scoped positions
      operationId: listAdminOrgPositions
      tags: [admin-organization]
      security: [{adminBearer: []}]
      parameters:
        - $ref: "#/components/parameters/AcceptLanguage"
        - {name: q, in: query, schema: {type: string, maxLength: 120}}
        - {name: status, in: query, schema: {$ref: "#/components/schemas/OrgStatus"}}
        - {name: unit_id, in: query, description: Filter by position assignments in this unit., schema: {type: string, format: uuid}}
      responses:
        "200": {description: Position list with assignment occupancy., content: {application/json: {schema: {$ref: "#/components/schemas/AdminOrgPositionListResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "422": {$ref: "#/components/responses/ValidationFailed"}
    post:
      summary: Create a tenant-scoped position
      operationId: createAdminOrgPosition
      tags: [admin-organization]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminOrgPositionRequest"}}}}
      responses:
        "201": {description: Position created and audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminOrgPositionResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "409": {description: Position code already exists., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}
        "422": {$ref: "#/components/responses/ValidationFailed"}
  /admin-api/v1/org/positions/{id}:
    parameters: [{$ref: "#/components/parameters/OrgResourceID"}]
    patch:
      summary: Update a tenant-scoped position
      operationId: updateAdminOrgPosition
      tags: [admin-organization]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminOrgPositionRequest"}}}}
      responses:
        "200": {description: Position updated and audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminOrgPositionResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "404": {$ref: "#/components/responses/NotFound"}
        "409": {description: Position code already exists., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}
        "422": {$ref: "#/components/responses/ValidationFailed"}
    delete:
      summary: Delete an unassigned position
      operationId: deleteAdminOrgPosition
      tags: [admin-organization]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      responses:
        "200": {description: Position soft-deleted and audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminDeleteResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "404": {$ref: "#/components/responses/NotFound"}
        "409": {description: Position has assigned members. Count is returned in error details., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}
  /admin-api/v1/tenants:
    get:
      summary: List tenants visible in the current tenant scope
      operationId: listAdminTenants
      tags: [admin-tenants]
      security: [{adminBearer: []}]
      parameters:
        - {$ref: "#/components/parameters/AcceptLanguage"}
        - {name: q, in: query, schema: {type: string, maxLength: 120}}
        - {name: status, in: query, schema: {$ref: "#/components/schemas/AdminTenantStatus"}}
        - {name: page, in: query, schema: {type: integer, minimum: 1, default: 1}}
        - {name: page_size, in: query, schema: {type: integer, minimum: 1, maximum: 100, default: 20}}
        - {name: sort, in: query, schema: {type: string, enum: [created_desc]}}
      responses:
        "200": {description: Tenant list with server-enforced scope., content: {application/json: {schema: {$ref: "#/components/schemas/AdminTenantListResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "404": {$ref: "#/components/responses/NotFound"}
        "422": {$ref: "#/components/responses/ValidationFailed"}
    post:
      summary: Create a tenant and make the caller its first super administrator
      operationId: createAdminTenant
      tags: [admin-tenants]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminTenantCreateRequest"}}}}
      responses:
        "201": {description: "Tenant, membership, system role and grants created transactionally.", content: {application/json: {schema: {$ref: "#/components/schemas/AdminTenantResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "404": {$ref: "#/components/responses/NotFound"}
        "409": {description: Tenant code already exists., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}
        "422": {$ref: "#/components/responses/ValidationFailed"}
  /admin-api/v1/tenants/{id}:
    parameters: [{$ref: "#/components/parameters/TenantResourceID"}]
    get:
      summary: Read the current tenant detail
      operationId: getAdminTenant
      tags: [admin-tenants]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      responses:
        "200": {description: Current tenant detail., content: {application/json: {schema: {$ref: "#/components/schemas/AdminTenantResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "404": {$ref: "#/components/responses/NotFound"}
    patch:
      summary: Update the current tenant profile or status
      operationId: updateAdminTenant
      tags: [admin-tenants]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminTenantUpdateRequest"}}}}
      responses:
        "200": {description: Tenant updated and audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminTenantResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "404": {$ref: "#/components/responses/NotFound"}
        "422": {$ref: "#/components/responses/ValidationFailed"}
  /admin-api/v1/tenants/{id}/members:
    parameters: [{$ref: "#/components/parameters/TenantResourceID"}]
    get:
      summary: List members of the current tenant
      operationId: listAdminTenantMembers
      tags: [admin-tenants]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      responses:
        "200": {description: Current tenant members., content: {application/json: {schema: {$ref: "#/components/schemas/AdminTenantMemberListResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "404": {$ref: "#/components/responses/NotFound"}
    post:
      summary: Add an existing global identity to the current tenant
      operationId: addAdminTenantMember
      tags: [admin-tenants]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminTenantMemberAddRequest"}}}}
      responses:
        "201": {description: Membership created or reactivated and audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminTenantMemberResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "404": {$ref: "#/components/responses/NotFound"}
        "409": {description: Membership conflicts with current state., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}
        "422": {$ref: "#/components/responses/ValidationFailed"}
  /admin-api/v1/tenants/{id}/members/{user_id}:
    parameters:
      - {$ref: "#/components/parameters/TenantResourceID"}
      - {$ref: "#/components/parameters/TenantMemberUserID"}
    patch:
      summary: Change a current tenant member status
      operationId: updateAdminTenantMember
      tags: [admin-tenants]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminTenantMemberUpdateRequest"}}}}
      responses:
        "200": {description: "Membership status updated, sessions revoked when needed, and action audited.", content: {application/json: {schema: {$ref: "#/components/schemas/AdminTenantMemberResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "404": {$ref: "#/components/responses/NotFound"}
        "409": {description: The last active super administrator cannot be suspended or removed., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}
        "422": {$ref: "#/components/responses/ValidationFailed"}
    delete:
      summary: Mark a current tenant member as having left
      operationId: removeAdminTenantMember
      tags: [admin-tenants]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      responses:
        "200": {description: "Membership marked left, sessions revoked, and action audited.", content: {application/json: {schema: {$ref: "#/components/schemas/AdminTenantMemberResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "404": {$ref: "#/components/responses/NotFound"}
        "409": {description: The last active super administrator cannot be removed., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}
  /admin-api/v1/roles:
    get:
      summary: List tenant-scoped roles and their separate permission, menu and data-scope assignments
      operationId: listAdminRoles
      tags: [admin-access-control]
      security: [{adminBearer: []}]
      parameters:
        - {$ref: "#/components/parameters/AcceptLanguage"}
        - {name: q, in: query, schema: {type: string, maxLength: 160}}
        - {name: status, in: query, schema: {$ref: "#/components/schemas/AdminAccessStatus"}}
        - {name: role_type, in: query, schema: {$ref: "#/components/schemas/AdminRoleType"}}
        - {name: page, in: query, schema: {type: integer, minimum: 1, default: 1}}
        - {name: page_size, in: query, schema: {type: integer, minimum: 1, maximum: 100, default: 20}}
      responses:
        "200": {description: Tenant role page., content: {application/json: {schema: {$ref: "#/components/schemas/AdminRoleListResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "422": {$ref: "#/components/responses/ValidationFailed"}
    post:
      summary: Create a tenant custom role
      operationId: createAdminRole
      tags: [admin-access-control]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminRoleRequest"}}}}
      responses:
        "201": {description: Custom role created and audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminRoleResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "409": {description: Role code or parent conflicts., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}
        "422": {$ref: "#/components/responses/ValidationFailed"}
  /admin-api/v1/roles/{id}:
    parameters: [{$ref: "#/components/parameters/RoleResourceID"}]
    patch:
      summary: Update a tenant custom role; system roles are immutable
      operationId: updateAdminRole
      tags: [admin-access-control]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminRoleRequest"}}}}
      responses:
        "200": {description: Custom role updated and audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminRoleResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "404": {$ref: "#/components/responses/NotFound"}
        "409": {description: "System role, code or parent conflict.", content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}
        "422": {$ref: "#/components/responses/ValidationFailed"}
    delete:
      summary: Soft-delete an unassigned tenant custom role
      operationId: deleteAdminRole
      tags: [admin-access-control]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      responses:
        "200": {description: Custom role deleted and audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminDeleteResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "404": {$ref: "#/components/responses/NotFound"}
        "409": {description: System role or occupied role., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}
  /admin-api/v1/roles/{id}/permissions:
    parameters: [{$ref: "#/components/parameters/RoleResourceID"}]
    put:
      summary: Replace backend permissions for a tenant custom role independently from menus
      operationId: replaceAdminRolePermissions
      tags: [admin-access-control]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminRolePermissionsRequest"}}}}
      responses:
        "200": {description: Permission grants replaced and audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminRoleResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "404": {$ref: "#/components/responses/NotFound"}
        "409": {description: System role is immutable., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}
        "422": {$ref: "#/components/responses/ValidationFailed"}
  /admin-api/v1/roles/{id}/menus:
    parameters: [{$ref: "#/components/parameters/RoleResourceID"}]
    put:
      summary: Replace navigation menus for a tenant custom role independently from permissions
      operationId: replaceAdminRoleMenus
      tags: [admin-access-control]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminRoleMenusRequest"}}}}
      responses:
        "200": {description: Menu grants replaced and audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminRoleResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "404": {$ref: "#/components/responses/NotFound"}
        "409": {description: System role is immutable., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}
        "422": {$ref: "#/components/responses/ValidationFailed"}
  /admin-api/v1/roles/{id}/data-scope:
    parameters: [{$ref: "#/components/parameters/RoleResourceID"}]
    put:
      summary: Replace a tenant custom role data scope and tenant-scoped custom units
      operationId: replaceAdminRoleDataScope
      tags: [admin-access-control]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminRoleDataScopeRequest"}}}}
      responses:
        "200": {description: Data scope replaced and audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminRoleResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "404": {$ref: "#/components/responses/NotFound"}
        "409": {description: System role is immutable., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}
        "422": {$ref: "#/components/responses/ValidationFailed"}
  /admin-api/v1/permissions:
    get:
      summary: Read the global stable permission catalog
      operationId: listAdminPermissions
      tags: [admin-access-control]
      security: [{adminBearer: []}]
      parameters:
        - {$ref: "#/components/parameters/AcceptLanguage"}
        - {name: q, in: query, schema: {type: string, maxLength: 160}}
        - {name: module_code, in: query, schema: {type: string, maxLength: 64}}
        - {name: resource_name, in: query, schema: {type: string, maxLength: 96}}
        - {name: action_name, in: query, schema: {type: string, maxLength: 64}}
        - {name: permission_kind, in: query, schema: {$ref: "#/components/schemas/AdminPermissionKind"}}
        - {name: status, in: query, schema: {$ref: "#/components/schemas/AdminAccessStatus"}}
      responses:
        "200": {description: Read-only permission catalog., content: {application/json: {schema: {$ref: "#/components/schemas/AdminPermissionListResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "422": {$ref: "#/components/responses/ValidationFailed"}
  /admin-api/v1/menus/tree:
    get:
      summary: Read the core plus current-tenant menu tree
      operationId: listAdminMenus
      tags: [admin-access-control]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      responses:
        "200": {description: Menu tree with immutable core rows identified., content: {application/json: {schema: {$ref: "#/components/schemas/AdminMenuTreeResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
  /admin-api/v1/menus:
    post:
      summary: Create a current-tenant menu using a registered component key
      operationId: createAdminMenu
      tags: [admin-access-control]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminMenuRequest"}}}}
      responses:
        "201": {description: Tenant menu created and audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminMenuResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "404": {$ref: "#/components/responses/NotFound"}
        "409": {description: "Menu code, depth or hierarchy conflict.", content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}
        "422": {$ref: "#/components/responses/ValidationFailed"}
  /admin-api/v1/menus/{id}:
    parameters: [{$ref: "#/components/parameters/MenuResourceID"}]
    patch:
      summary: Update a current-tenant menu; core menus are immutable
      operationId: updateAdminMenu
      tags: [admin-access-control]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminMenuRequest"}}}}
      responses:
        "200": {description: Tenant menu updated and audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminMenuResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "404": {$ref: "#/components/responses/NotFound"}
        "409": {description: "Menu code, depth or hierarchy conflict.", content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}
        "422": {$ref: "#/components/responses/ValidationFailed"}
    delete:
      summary: Soft-delete an unoccupied current-tenant menu
      operationId: deleteAdminMenu
      tags: [admin-access-control]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      responses:
        "200": {description: Tenant menu deleted and audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminDeleteResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "404": {$ref: "#/components/responses/NotFound"}
        "409": {description: Menu has children or role assignments., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}
  /admin-api/v1/menus/{id}/move:
    parameters: [{$ref: "#/components/parameters/MenuResourceID"}]
    post:
      summary: Move a tenant menu with explicit keyboard-compatible parent and sort fields
      operationId: moveAdminMenu
      tags: [admin-access-control]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminMenuMoveRequest"}}}}
      responses:
        "200": {description: Tenant menu moved and audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminMenuResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "404": {$ref: "#/components/responses/NotFound"}
        "409": {description: Move would create a cycle or exceed three levels., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}
        "422": {$ref: "#/components/responses/ValidationFailed"}
  /admin-api/v1/audit/operations:
    get:
      summary: List tenant-scoped redacted operation audit records
      operationId: listAdminAuditOperations
      tags: [admin-audit-security]
      security: [{adminBearer: []}]
      parameters:
        - {$ref: "#/components/parameters/AcceptLanguage"}
        - {name: q, in: query, schema: {type: string, maxLength: 160}}
        - {name: module_code, in: query, schema: {type: string, maxLength: 64}}
        - {name: result, in: query, schema: {type: string, enum: [success, failure]}}
        - {name: from, in: query, schema: {type: string, format: date}}
        - {name: to, in: query, schema: {type: string, format: date}}
        - {name: page, in: query, schema: {type: integer, minimum: 1, default: 1}}
        - {name: page_size, in: query, schema: {type: integer, minimum: 1, maximum: 100, default: 20}}
      responses:
        "200": {description: Tenant operation audit page with recursively redacted JSON fields., content: {application/json: {schema: {$ref: "#/components/schemas/AdminAuditOperationListResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "422": {$ref: "#/components/responses/ValidationFailed"}
  /admin-api/v1/audit/logins:
    get:
      summary: List tenant-scoped login events without identifier hashes or raw device payloads
      operationId: listAdminAuditLogins
      tags: [admin-audit-security]
      security: [{adminBearer: []}]
      parameters:
        - {$ref: "#/components/parameters/AcceptLanguage"}
        - {name: q, in: query, schema: {type: string, maxLength: 160}}
        - {name: result, in: query, schema: {type: string, enum: [success, failure, blocked]}}
        - {name: audience, in: query, schema: {type: string, enum: [ak-mobile, ak-admin, ak-api]}}
        - {name: auth_method, in: query, schema: {type: string, enum: [password, email_otp, sms_otp, oauth, refresh_token, api_secret, mfa, tenant_switch]}}
        - {name: from, in: query, schema: {type: string, format: date}}
        - {name: to, in: query, schema: {type: string, format: date}}
        - {name: page, in: query, schema: {type: integer, minimum: 1, default: 1}}
        - {name: page_size, in: query, schema: {type: integer, minimum: 1, maximum: 100, default: 20}}
      responses:
        "200": {description: Tenant login event page., content: {application/json: {schema: {$ref: "#/components/schemas/AdminAuditLoginListResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "422": {$ref: "#/components/responses/ValidationFailed"}
  /admin-api/v1/audit/security-events:
    get:
      summary: List tenant-scoped security events
      operationId: listAdminAuditSecurityEvents
      tags: [admin-audit-security]
      security: [{adminBearer: []}]
      parameters:
        - {$ref: "#/components/parameters/AcceptLanguage"}
        - {name: q, in: query, schema: {type: string, maxLength: 160}}
        - {name: severity, in: query, schema: {type: string, enum: [info, low, medium, high, critical]}}
        - {name: source, in: query, schema: {type: string, maxLength: 64}}
        - {name: status, in: query, schema: {type: string, enum: [open, resolved]}}
        - {name: from, in: query, schema: {type: string, format: date}}
        - {name: to, in: query, schema: {type: string, format: date}}
        - {name: page, in: query, schema: {type: integer, minimum: 1, default: 1}}
        - {name: page_size, in: query, schema: {type: integer, minimum: 1, maximum: 100, default: 20}}
      responses:
        "200": {description: Tenant security event page without details payloads., content: {application/json: {schema: {$ref: "#/components/schemas/AdminAuditSecurityEventListResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "422": {$ref: "#/components/responses/ValidationFailed"}
  /admin-api/v1/audit/security-events/{id}:
    parameters: [{$ref: "#/components/parameters/AuditSecurityEventID"}]
    get:
      summary: Read a tenant-scoped security event with recursively redacted details
      operationId: getAdminAuditSecurityEvent
      tags: [admin-audit-security]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      responses:
        "200": {description: Redacted security event detail., content: {application/json: {schema: {$ref: "#/components/schemas/AdminAuditSecurityEventResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "404": {$ref: "#/components/responses/NotFound"}
  /admin-api/v1/audit/security-events/{id}/resolve:
    parameters: [{$ref: "#/components/parameters/AuditSecurityEventID"}]
    post:
      summary: Resolve one open tenant security event and append an immutable operation audit
      operationId: resolveAdminAuditSecurityEvent
      tags: [admin-audit-security]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      responses:
        "200": {description: Security event resolved and action audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminAuditSecurityEventResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "404": {$ref: "#/components/responses/NotFound"}
        "409": {description: Security event is already resolved., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}
  /admin-api/v1/users:
    get:
      summary: List tenant-scoped managed users
      operationId: listAdminUsers
      tags: [admin-users]
      security: [{adminBearer: []}]
      parameters:
        - {$ref: "#/components/parameters/AcceptLanguage"}
        - {name: q, in: query, schema: {type: string, maxLength: 254}}
        - {name: status, in: query, schema: {$ref: "#/components/schemas/AdminUserStatus"}}
        - {name: unit_id, in: query, schema: {type: string, format: uuid}}
        - {name: position_id, in: query, schema: {type: string, format: uuid}}
        - {name: role_id, in: query, schema: {type: string, format: uuid}}
        - {name: created_from, in: query, schema: {type: string, format: date-time}}
        - {name: created_to, in: query, schema: {type: string, format: date-time}}
        - {name: page, in: query, schema: {type: integer, minimum: 1, default: 1}}
        - {name: page_size, in: query, schema: {type: integer, minimum: 1, maximum: 100, default: 20}}
        - {name: sort, in: query, schema: {type: string, enum: [created_desc, created_asc, name_asc, last_login_desc]}}
      responses:
        "200": {description: Tenant users with server-enforced assignments., content: {application/json: {schema: {$ref: "#/components/schemas/AdminUserListResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "422": {$ref: "#/components/responses/ValidationFailed"}
    post:
      summary: Create a tenant user with a temporary password
      operationId: createAdminUser
      tags: [admin-users]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminUserCreateRequest"}}}}
      responses:
        "201": {description: User and membership created; password is never returned or audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminUserResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "409": {description: Email already exists., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}
        "422": {$ref: "#/components/responses/ValidationFailed"}
  /admin-api/v1/users/import:
    post:
      summary: Import up to 500 tenant users from a UTF-8 CSV file
      operationId: importAdminUsers
      tags: [admin-users]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      requestBody: {required: true, content: {text/csv: {schema: {type: string, maxLength: 2097152}}}}
      responses:
        "200": {description: Per-row import result with stable public error codes., content: {application/json: {schema: {$ref: "#/components/schemas/AdminUserImportResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "422": {$ref: "#/components/responses/ValidationFailed"}
  /admin-api/v1/users/export:
    post:
      summary: Export up to 500 filtered tenant users using a safe field allow-list
      operationId: exportAdminUsers
      tags: [admin-users]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminUserExportRequest"}}}}
      responses:
        "200": {description: UTF-8 CSV without credentials or secret material., content: {text/csv: {schema: {type: string}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "422": {$ref: "#/components/responses/ValidationFailed"}
  /admin-api/v1/users/role-options:
    get:
      summary: List active tenant role options for user assignment
      operationId: listAdminUserRoleOptions
      tags: [admin-users]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      responses:
        "200": {description: Active role options., content: {application/json: {schema: {$ref: "#/components/schemas/AdminUserRoleOptionsResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
  /admin-api/v1/users/{id}:
    parameters: [{$ref: "#/components/parameters/UserResourceID"}]
    get:
      summary: Read a tenant user detail
      operationId: getAdminUser
      tags: [admin-users]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      responses:
        "200": {description: User detail., content: {application/json: {schema: {$ref: "#/components/schemas/AdminUserResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "404": {$ref: "#/components/responses/NotFound"}
    patch:
      summary: Update safe user profile fields
      operationId: updateAdminUser
      tags: [admin-users]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminUserUpdateRequest"}}}}
      responses:
        "200": {description: User updated and audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminUserResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "404": {$ref: "#/components/responses/NotFound"}
        "422": {$ref: "#/components/responses/ValidationFailed"}
  /admin-api/v1/users/{id}/enable:
    $ref: "#/components/pathItems/AdminUserEnable"
  /admin-api/v1/users/{id}/disable:
    $ref: "#/components/pathItems/AdminUserDisable"
  /admin-api/v1/users/{id}/unlock:
    $ref: "#/components/pathItems/AdminUserUnlock"
  /admin-api/v1/users/{id}/reset-password:
    parameters: [{$ref: "#/components/parameters/UserResourceID"}]
    post:
      summary: Reset a user password and revoke every active session
      operationId: resetAdminUserPassword
      tags: [admin-users]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminUserResetPasswordRequest"}}}}
      responses:
        "200": {description: "Password reset, forced change enabled, and sessions revoked.", content: {application/json: {schema: {$ref: "#/components/schemas/AdminUserResetPasswordResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "404": {$ref: "#/components/responses/NotFound"}
        "422": {$ref: "#/components/responses/ValidationFailed"}
  /admin-api/v1/users/{id}/roles:
    parameters: [{$ref: "#/components/parameters/UserResourceID"}]
    put:
      summary: Replace a tenant user's roles after tenant validation
      operationId: replaceAdminUserRoles
      tags: [admin-users]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminUserRolesRequest"}}}}
      responses:
        "200": {description: Roles replaced and audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminUserResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "404": {$ref: "#/components/responses/NotFound"}
        "422": {$ref: "#/components/responses/ValidationFailed"}
  /admin-api/v1/org/users/{user_id}/assignments:
    parameters: [{$ref: "#/components/parameters/OrgUserResourceID"}]
    put:
      summary: Replace tenant-validated unit and position assignments
      operationId: replaceAdminUserAssignments
      tags: [admin-organization]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminUserAssignmentsRequest"}}}}
      responses:
        "200": {description: Assignments replaced and audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminUserResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "404": {$ref: "#/components/responses/NotFound"}
        "422": {$ref: "#/components/responses/ValidationFailed"}
  /admin-api/v1/users/{id}/sessions:
    parameters: [{$ref: "#/components/parameters/UserResourceID"}]
    get:
      summary: List a tenant user's sessions
      operationId: listAdminUserSessions
      tags: [admin-users]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      responses:
        "200": {description: At most 100 tenant-scoped sessions., content: {application/json: {schema: {$ref: "#/components/schemas/AdminUserSessionListResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "404": {$ref: "#/components/responses/NotFound"}
  /admin-api/v1/users/{id}/sessions/{session_id}:
    parameters:
      - {$ref: "#/components/parameters/UserResourceID"}
      - {$ref: "#/components/parameters/UserSessionResourceID"}
    delete:
      summary: Revoke one tenant-scoped user session
      operationId: revokeAdminUserSession
      tags: [admin-users]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      responses:
        "200": {description: Session and refresh tokens revoked., content: {application/json: {schema: {$ref: "#/components/schemas/AdminUserActionResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "404": {$ref: "#/components/responses/NotFound"}
  /admin-api/v1/online-sessions:
    get:
      summary: List tenant-scoped online sessions using only safe identifier hints
      operationId: listAdminOnlineSessions
      tags: [admin-operations]
      security: [{adminBearer: []}]
      parameters:
        - {$ref: "#/components/parameters/AcceptLanguage"}
        - {name: q, in: query, schema: {type: string, maxLength: 160}}
        - {name: audience, in: query, schema: {type: string, enum: [ak-mobile, ak-admin, ak-api]}}
        - {name: platform, in: query, schema: {type: string, enum: [android, ios, harmonyos, web, desktop, unknown]}}
        - {name: status, in: query, schema: {type: string, enum: [active, revoked, expired]}}
        - {name: ip, in: query, description: Server-side match; the response contains only masked IP hints., schema: {type: string, maxLength: 64}}
        - {name: from, in: query, schema: {type: string, format: date-time}}
        - {name: to, in: query, schema: {type: string, format: date-time}}
        - {name: page, in: query, schema: {type: integer, minimum: 1, default: 1}}
        - {name: page_size, in: query, schema: {type: integer, minimum: 1, maximum: 100, default: 20}}
      responses:
        "200": {description: "Tenant session page without token hashes, raw IP addresses, device keys or user-agent strings.", content: {application/json: {schema: {$ref: "#/components/schemas/AdminOnlineSessionListResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "422": {$ref: "#/components/responses/ValidationFailed"}
  /admin-api/v1/online-sessions/{id}:
    parameters:
      - name: id
        in: path
        required: true
        schema: {type: string, format: uuid}
    delete:
      summary: Force one active tenant session offline and revoke its refresh-token family
      operationId: revokeAdminOnlineSession
      tags: [admin-operations]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      responses:
        "200": {description: Session revoked and immutable operation audit written. The current flag tells the client to clear its own authentication., content: {application/json: {schema: {$ref: "#/components/schemas/AdminOnlineSessionRevokeResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "409": {description: "The session is absent, expired, or already revoked.", content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}
  /admin-api/v1/regions:
    get:
      summary: Lazily list or search the global region catalog
      operationId: listAdminRegions
      tags: [admin-system-settings]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}, {name: q, in: query, schema: {type: string, maxLength: 160}}, {name: parent_code, in: query, schema: {type: string, maxLength: 32}}, {name: level, in: query, schema: {type: integer, minimum: 0, maximum: 10}}, {name: status, in: query, schema: {type: string, enum: [active, disabled]}}, {name: limit, in: query, schema: {type: integer, minimum: 1, maximum: 200, default: 100}}]
      responses: {"200": {description: Region nodes with has_children for lazy expansion., content: {application/json: {schema: {$ref: "#/components/schemas/RegionListResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "403": {$ref: "#/components/responses/Forbidden"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
    post:
      summary: Create a direct child below a province-level or city-level region
      operationId: createAdminRegion
      tags: [admin-system-settings]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminRegionCreateRequest"}}}}
      responses:
        "201": {description: Region child created with a server-derived level., content: {application/json: {schema: {$ref: "#/components/schemas/AdminRegionResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "409": {description: Region code already exists., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}
        "422": {$ref: "#/components/responses/ValidationFailed"}
  /admin-api/v1/regions/{code}:
    parameters: [{name: code, in: path, required: true, schema: {type: string, pattern: "^[A-Za-z0-9][A-Za-z0-9._-]{0,31}$"}}]
    patch:
      summary: Update mutable fields of a region without changing its code or hierarchy
      operationId: updateAdminRegion
      tags: [admin-system-settings]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminRegionUpdateRequest"}}}}
      responses:
        "200": {description: Region updated and marked as manually managed., content: {application/json: {schema: {$ref: "#/components/schemas/AdminRegionResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "404": {$ref: "#/components/responses/NotFound"}
        "409": {description: Optimistic-lock version conflict., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}
        "422": {$ref: "#/components/responses/ValidationFailed"}
    delete:
      summary: Soft-delete a leaf region
      operationId: deleteAdminRegion
      tags: [admin-system-settings]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      responses:
        "200": {description: Leaf region soft-deleted., content: {application/json: {schema: {$ref: "#/components/schemas/AdminBooleanResponse"}}}}
        "401": {$ref: "#/components/responses/Unauthorized"}
        "403": {$ref: "#/components/responses/Forbidden"}
        "404": {$ref: "#/components/responses/NotFound"}
        "409": {description: Region still has non-deleted children., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}
  /admin-api/v1/files/upload-policy:
    get:
      summary: Read the effective tenant upload policy without exposing storage credentials or bucket names
      operationId: getAdminFileUploadPolicy
      tags: [admin-storage]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      responses: {"200": {description: Effective provider and server-enforced upload constraints., content: {application/json: {schema: {$ref: "#/components/schemas/AdminFileUploadPolicyResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "403": {$ref: "#/components/responses/Forbidden"}, "503": {description: Storage configuration is incomplete or unavailable., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}}
  /admin-api/v1/files/upload-sessions:
    post:
      summary: Create a tenant-scoped multipart upload session
      operationId: createAdminFileUploadSession
      tags: [admin-storage]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminFileUploadRequest"}}}}
      responses: {"201": {description: Random object key and resumable session created., content: {application/json: {schema: {$ref: "#/components/schemas/AdminFileUploadSessionResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "403": {$ref: "#/components/responses/Forbidden"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /admin-api/v1/files/upload-sessions/{id}:
    parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
    get:
      summary: Get uploaded parts for resumable upload
      operationId: getAdminFileUploadSession
      tags: [admin-storage]
      security: [{adminBearer: []}]
      responses: {"200": {description: Current uploaded parts., content: {application/json: {schema: {$ref: "#/components/schemas/AdminFileUploadSessionResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}}
    delete:
      summary: Cancel a multipart upload and discard its parts
      operationId: cancelAdminFileUploadSession
      tags: [admin-storage]
      security: [{adminBearer: []}]
      responses: {"200": {description: Upload cancelled., content: {application/json: {schema: {$ref: "#/components/schemas/AdminBooleanResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}}
  /admin-api/v1/files/upload-sessions/{id}/parts/{partNumber}:
    put:
      summary: Upload or replace one exact-size part
      operationId: uploadAdminFilePart
      tags: [admin-storage]
      security: [{adminBearer: []}]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}, {name: partNumber, in: path, required: true, schema: {type: integer, minimum: 1}}]
      requestBody: {required: true, content: {application/octet-stream: {schema: {type: string, format: binary}}}}
      responses: {"200": {description: Part checksum persisted for resume., content: {application/json: {schema: {$ref: "#/components/schemas/AdminFilePartResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /admin-api/v1/files/upload-sessions/{id}/complete:
    post:
      summary: Assemble, verify MIME and checksum, then complete a multipart upload
      operationId: completeAdminFileUploadSession
      tags: [admin-storage]
      security: [{adminBearer: []}]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"201": {description: File becomes ready only after validation and the configured scan gate., content: {application/json: {schema: {$ref: "#/components/schemas/AdminFileResponse"}}}}, "409": {description: Missing part or scan gate conflict., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /admin-api/v1/files:
    get:
      summary: List tenant-scoped files
      operationId: listAdminFiles
      tags: [admin-storage]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}, {name: q, in: query, schema: {type: string, maxLength: 160}}, {name: status, in: query, schema: {type: string, enum: [pending, ready, quarantined]}}, {name: scan_status, in: query, schema: {type: string, enum: [pending, clean, infected, failed, skipped]}}, {name: media_type, in: query, schema: {type: string}}, {name: provider, in: query, schema: {type: string, x-appkernia-dictionary: storage.driver}}, {name: page, in: query, schema: {type: integer, minimum: 1, default: 1}}, {name: page_size, in: query, schema: {type: integer, minimum: 1, maximum: 100, default: 20}}]
      responses: {"200": {description: Object keys and checksums are not exposed., content: {application/json: {schema: {$ref: "#/components/schemas/AdminFileListResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "403": {$ref: "#/components/responses/Forbidden"}}
  /admin-api/v1/files/{id}:
    parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
    get:
      summary: Get one tenant-scoped file
      operationId: getAdminFile
      tags: [admin-storage]
      security: [{adminBearer: []}]
      responses: {"200": {description: File metadata., content: {application/json: {schema: {$ref: "#/components/schemas/AdminFileResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}}
    delete:
      summary: Delete an unused tenant-scoped file
      operationId: deleteAdminFile
      tags: [admin-storage]
      security: [{adminBearer: []}]
      responses: {"200": {description: File soft-deleted and object removed., content: {application/json: {schema: {$ref: "#/components/schemas/AdminBooleanResponse"}}}}, "409": {description: File has active usages and cannot be deleted., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}}
  /admin-api/v1/files/{id}/usages:
    get:
      summary: List business references that protect a file from deletion
      operationId: listAdminFileUsages
      tags: [admin-storage]
      security: [{adminBearer: []}]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: File usages., content: {application/json: {schema: {$ref: "#/components/schemas/AdminFileUsageListResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}}
  /admin-api/v1/files/{id}/presign-download:
    post:
      summary: Create a short-lived download target after scan and permission checks
      operationId: presignAdminFileDownload
      tags: [admin-storage]
      security: [{adminBearer: []}]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: Download target., content: {application/json: {schema: {$ref: "#/components/schemas/AdminFileDownloadResponse"}}}}, "409": {description: File is not ready or scan-safe., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}}
  /admin-api/v1/files/{id}/content:
    get:
      summary: Stream a scan-safe private file from the tenant's configured storage adapter
      operationId: downloadAdminFileContent
      tags: [admin-storage]
      security: [{adminBearer: []}]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: Private binary content., content: {application/octet-stream: {schema: {type: string, format: binary}}}}, "409": {description: Scan gate blocked download., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}}
  /api/v1/articles:
    parameters: [{$ref: "#/components/parameters/AppID"}]
    get:
      summary: List published tenant articles localized by Accept-Language
      operationId: listAppArticles
      tags: [public-content]
      security: [{mobileBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}, {name: q, in: query, schema: {type: string, maxLength: 160}}, {name: category, in: query, schema: {type: string, maxLength: 120}}, {name: featured, in: query, schema: {type: boolean}}, {name: cursor, in: query, schema: {type: string, format: uuid}}, {name: limit, in: query, schema: {type: integer, minimum: 1, maximum: 50, default: 20}}]
      responses: {"200": {description: Published articles only., headers: {Content-Language: {schema: {$ref: "#/components/schemas/SupportedLocale"}}}, content: {application/json: {schema: {$ref: "#/components/schemas/AppArticleListResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /api/v1/article-categories:
    parameters: [{$ref: "#/components/parameters/AppID"}]
    get:
      summary: List all active tenant article categories localized by Accept-Language
      operationId: listAppArticleCategories
      tags: [public-content]
      security: [{mobileBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      responses: {"200": {description: Active categories in stable sort order., headers: {Content-Language: {schema: {$ref: "#/components/schemas/SupportedLocale"}}}, content: {application/json: {schema: {$ref: "#/components/schemas/AppArticleCategoryListResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}}
  /api/v1/article-assets/{file_id}:
    parameters: [{$ref: "#/components/parameters/AppID"}]
    get:
      summary: Read a scan-safe image used by a published tenant article
      operationId: getAppArticleAsset
      tags: [public-content]
      security: [{mobileBearer: []}]
      parameters: [{name: file_id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: "Authorized JPEG, PNG, or WebP article cover.", headers: {Cache-Control: {schema: {type: string}}, ETag: {schema: {type: string}}}, content: {image/jpeg: {schema: {type: string, format: binary}}, image/png: {schema: {type: string, format: binary}}, image/webp: {schema: {type: string, format: binary}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "404": {$ref: "#/components/responses/NotFound"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /api/v1/articles/{slug}:
    parameters: [{$ref: "#/components/parameters/AppID"}]
    get:
      summary: Read a published localized article
      operationId: getAppArticle
      tags: [public-content]
      security: [{mobileBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}, {name: slug, in: path, required: true, schema: {type: string, pattern: '^[a-z0-9]+(?:-[a-z0-9]+)*$'}}]
      responses: {"200": {description: Published article., headers: {Content-Language: {schema: {$ref: "#/components/schemas/SupportedLocale"}}}, content: {application/json: {schema: {$ref: "#/components/schemas/AppArticleResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "404": {$ref: "#/components/responses/NotFound"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /api/v1/me/article-bookmarks/{article_id}:
    parameters: [{$ref: "#/components/parameters/AppID"}]
    put:
      summary: Bookmark a published tenant article
      operationId: bookmarkAppArticle
      tags: [mobile-content]
      security: [{mobileBearer: []}]
      parameters: [{name: article_id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: Bookmark present., content: {application/json: {schema: {$ref: "#/components/schemas/AppBookmarkResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "404": {$ref: "#/components/responses/NotFound"}}
    delete:
      summary: Remove an article bookmark
      operationId: removeAppArticleBookmark
      tags: [mobile-content]
      security: [{mobileBearer: []}]
      parameters: [{name: article_id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: Bookmark absent., content: {application/json: {schema: {$ref: "#/components/schemas/AppBookmarkResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}}
  /admin-api/v1/content/categories:
    get:
      summary: List tenant content categories
      operationId: listAdminContentCategories
      tags: [admin-content]
      security: [{adminBearer: []}]
      parameters: [{name: q, in: query, schema: {type: string, maxLength: 160}}, {name: status, in: query, schema: {type: string, enum: [active, disabled]}}, {name: page, in: query, schema: {type: integer, minimum: 1, default: 1}}, {name: page_size, in: query, schema: {type: integer, minimum: 1, maximum: 100, default: 20}}, {name: sort, in: query, schema: {type: string, enum: [sort_order, updated_desc, slug], default: sort_order}}]
      responses: {"200": {description: Category page., content: {application/json: {schema: {$ref: "#/components/schemas/AdminContentCategoryListResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "403": {$ref: "#/components/responses/Forbidden"}}
    post:
      summary: Create a category with both supported translations
      operationId: createAdminContentCategory
      tags: [admin-content]
      security: [{adminBearer: []}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminContentCategoryRequest"}}}}
      responses: {"201": {description: Created., content: {application/json: {schema: {$ref: "#/components/schemas/AdminContentCategoryResponse"}}}}, "422": {$ref: "#/components/responses/ValidationFailed"}, "409": {$ref: "#/components/responses/Conflict"}}
  /admin-api/v1/content/categories/{id}:
    get:
      summary: Read a tenant category
      operationId: getAdminContentCategory
      tags: [admin-content]
      security: [{adminBearer: []}]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: Category., content: {application/json: {schema: {$ref: "#/components/schemas/AdminContentCategoryResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}}
    patch:
      summary: Update a category with optimistic lock version
      operationId: updateAdminContentCategory
      tags: [admin-content]
      security: [{adminBearer: []}]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminContentCategoryUpdateRequest"}}}}
      responses: {"200": {description: Updated., content: {application/json: {schema: {$ref: "#/components/schemas/AdminContentCategoryResponse"}}}}, "409": {$ref: "#/components/responses/Conflict"}}
    delete:
      summary: Delete an unused category
      operationId: deleteAdminContentCategory
      tags: [admin-content]
      security: [{adminBearer: []}]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}, {name: lock_version, in: query, required: true, schema: {type: integer, minimum: 1}}]
      responses: {"200": {description: Deleted., content: {application/json: {schema: {$ref: "#/components/schemas/AdminDeleteResponse"}}}}, "409": {$ref: "#/components/responses/Conflict"}}
  /admin-api/v1/content/articles:
    get:
      summary: List tenant articles in every lifecycle state
      operationId: listAdminContentArticles
      tags: [admin-content]
      security: [{adminBearer: []}]
      parameters: [{name: q, in: query, schema: {type: string, maxLength: 160}}, {name: category_id, in: query, schema: {type: string, format: uuid}}, {name: status, in: query, schema: {type: string, enum: [draft, published, archived]}}, {name: featured, in: query, schema: {type: boolean}}, {name: page, in: query, schema: {type: integer, minimum: 1, default: 1}}, {name: page_size, in: query, schema: {type: integer, minimum: 1, maximum: 100, default: 20}}, {name: sort, in: query, schema: {type: string, enum: [updated_desc, published_desc, sort_order, slug], default: updated_desc}}]
      responses: {"200": {description: Article page., content: {application/json: {schema: {$ref: "#/components/schemas/AdminContentArticleListResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}}
    post:
      summary: Create a draft article
      operationId: createAdminContentArticle
      tags: [admin-content]
      security: [{adminBearer: []}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminContentArticleRequest"}}}}
      responses: {"201": {description: Created., content: {application/json: {schema: {$ref: "#/components/schemas/AdminContentArticleResponse"}}}}, "422": {$ref: "#/components/responses/ValidationFailed"}, "409": {$ref: "#/components/responses/Conflict"}}
  /admin-api/v1/content/articles/{id}:
    get:
      summary: Read a tenant article
      operationId: getAdminContentArticle
      tags: [admin-content]
      security: [{adminBearer: []}]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: Article., content: {application/json: {schema: {$ref: "#/components/schemas/AdminContentArticleResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}}
    patch:
      summary: Update a draft article using lock_version
      operationId: updateAdminContentArticle
      tags: [admin-content]
      security: [{adminBearer: []}]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminContentArticleUpdateRequest"}}}}
      responses: {"200": {description: Updated., content: {application/json: {schema: {$ref: "#/components/schemas/AdminContentArticleResponse"}}}}, "409": {$ref: "#/components/responses/Conflict"}}
    delete:
      summary: Delete a draft article
      operationId: deleteAdminContentArticle
      tags: [admin-content]
      security: [{adminBearer: []}]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}, {name: lock_version, in: query, required: true, schema: {type: integer, minimum: 1}}]
      responses: {"200": {description: Deleted., content: {application/json: {schema: {$ref: "#/components/schemas/AdminDeleteResponse"}}}}, "409": {$ref: "#/components/responses/Conflict"}}
  /admin-api/v1/content/articles/{id}/{transition}:
    post:
      summary: Transition an article using publish, unpublish, or archive
      operationId: transitionAdminContentArticle
      tags: [admin-content]
      security: [{adminBearer: []}]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}, {name: transition, in: path, required: true, schema: {type: string, enum: [publish, unpublish, archive]}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminContentTransitionRequest"}}}}
      responses: {"200": {description: Transitioned., content: {application/json: {schema: {$ref: "#/components/schemas/AdminContentArticleResponse"}}}}, "409": {$ref: "#/components/responses/Conflict"}}
  /admin-api/v1/notices:
    get:
      summary: List tenant-scoped announcements
      operationId: listAdminNotices
      tags: [admin-notifications]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}, {name: q, in: query, schema: {type: string, maxLength: 160}}, {name: status, in: query, schema: {type: string, enum: [draft, scheduled, published, cancelled]}}, {name: page, in: query, schema: {type: integer, minimum: 1, default: 1}}, {name: page_size, in: query, schema: {type: integer, minimum: 1, maximum: 100, default: 20}}]
      responses: {"200": {description: Announcement page., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationMessageListResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "403": {$ref: "#/components/responses/Forbidden"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
    post:
      summary: Create an announcement draft
      operationId: createAdminNotice
      tags: [admin-notifications]
      security: [{adminBearer: []}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationMessageRequest"}}}}
      responses: {"201": {description: Draft created and audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationMessageResponse"}}}}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /admin-api/v1/notices/{id}:
    parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
    get:
      summary: Get one tenant-scoped announcement
      operationId: getAdminNotice
      tags: [admin-notifications]
      security: [{adminBearer: []}]
      responses: {"200": {description: Announcement detail with server-sanitized HTML body., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationMessageResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}}
    patch:
      summary: Update an announcement draft or scheduled announcement
      operationId: updateAdminNotice
      tags: [admin-notifications]
      security: [{adminBearer: []}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationMessageRequest"}}}}
      responses: {"200": {description: Announcement updated and audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationMessageResponse"}}}}, "409": {description: Published or cancelled announcements are immutable., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /admin-api/v1/notices/{id}/recipient-preview:
    post:
      summary: Resolve the exact active recipient set before publishing an announcement
      operationId: previewAdminNoticeRecipients
      tags: [admin-notifications]
      security: [{adminBearer: []}]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: Exact count and at most 20 safe recipient hints., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationRecipientPreviewResponse"}}}}, "409": {description: Empty or immutable recipient set., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}}
  /admin-api/v1/notices/{id}/publish:
    post:
      summary: Publish or schedule an announcement and idempotently materialize recipients
      operationId: publishAdminNotice
      tags: [admin-notifications]
      security: [{adminBearer: []}]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: Announcement published or scheduled with the resolved audience., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationPublishResponse"}}}}, "409": {description: Invalid lifecycle or empty audience., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}}
  /admin-api/v1/notices/{id}/cancel:
    post:
      summary: Cancel an announcement
      operationId: cancelAdminNotice
      tags: [admin-notifications]
      security: [{adminBearer: []}]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: Announcement cancelled and audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationMessageResponse"}}}}, "409": {description: Invalid lifecycle., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}}
  /admin-api/v1/notices/{id}/recipients:
    get:
      summary: Get announcement recipient delivery and read statistics
      operationId: getAdminNoticeRecipients
      tags: [admin-notifications]
      security: [{adminBearer: []}]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: Aggregate recipient statistics., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationRecipientStatsResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}}
  /admin-api/v1/messages:
    get:
      summary: List tenant-scoped non-announcement in-app messages
      operationId: listAdminMessages
      tags: [admin-notifications]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}, {name: q, in: query, schema: {type: string, maxLength: 160}}, {name: status, in: query, schema: {type: string, enum: [draft, scheduled, published, cancelled]}}, {name: message_type, in: query, schema: {type: string, enum: [system, private, marketing, security]}}, {name: page, in: query, schema: {type: integer, minimum: 1, default: 1}}, {name: page_size, in: query, schema: {type: integer, minimum: 1, maximum: 100, default: 20}}]
      responses: {"200": {description: In-app message page., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationMessageListResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "403": {$ref: "#/components/responses/Forbidden"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
    post:
      summary: Create an in-app message draft
      operationId: createAdminMessage
      tags: [admin-notifications]
      security: [{adminBearer: []}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationMessageRequest"}}}}
      responses: {"201": {description: Draft created and audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationMessageResponse"}}}}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /admin-api/v1/messages/{id}:
    parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
    get:
      summary: Get one tenant-scoped in-app message
      operationId: getAdminMessage
      tags: [admin-notifications]
      security: [{adminBearer: []}]
      responses: {"200": {description: Message detail., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationMessageResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}}
    patch:
      summary: Update an in-app message draft or scheduled message
      operationId: updateAdminMessage
      tags: [admin-notifications]
      security: [{adminBearer: []}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationMessageRequest"}}}}
      responses: {"200": {description: Message updated and audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationMessageResponse"}}}}, "409": {description: Published or cancelled messages are immutable., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /admin-api/v1/messages/{id}/recipient-preview:
    post:
      summary: Resolve the exact active recipient set before publishing a message
      operationId: previewAdminMessageRecipients
      tags: [admin-notifications]
      security: [{adminBearer: []}]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: Exact count and at most 20 safe recipient hints., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationRecipientPreviewResponse"}}}}, "409": {description: Empty or immutable recipient set., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}}
  /admin-api/v1/messages/{id}/publish:
    post:
      summary: Publish or schedule a message and idempotently materialize recipients
      operationId: publishAdminMessage
      tags: [admin-notifications]
      security: [{adminBearer: []}]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: Message published or scheduled with the resolved audience., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationPublishResponse"}}}}, "409": {description: Invalid lifecycle or empty audience., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}}
  /admin-api/v1/messages/{id}/cancel:
    post:
      summary: Cancel an in-app message
      operationId: cancelAdminMessage
      tags: [admin-notifications]
      security: [{adminBearer: []}]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: Message cancelled and audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationMessageResponse"}}}}, "409": {description: Invalid lifecycle., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}}
  /admin-api/v1/messages/{id}/recipients:
    get:
      summary: Get message recipient delivery and read statistics
      operationId: getAdminMessageRecipients
      tags: [admin-notifications]
      security: [{adminBearer: []}]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: Aggregate recipient statistics., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationRecipientStatsResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}}
  /admin-api/v1/notification-templates:
    get:
      summary: List tenant and global notification templates
      operationId: listAdminNotificationTemplates
      tags: [admin-notifications]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}, {name: q, in: query, schema: {type: string, maxLength: 160}}, {name: channel, in: query, schema: {$ref: "#/components/schemas/AdminNotificationTemplateChannel"}}, {name: locale, in: query, schema: {type: string, enum: [zh-CN, en-US, global]}}, {name: status, in: query, schema: {type: string, enum: [active, disabled]}}, {name: page, in: query, schema: {type: integer, minimum: 1, default: 1}}, {name: page_size, in: query, schema: {type: integer, minimum: 1, maximum: 100, default: 20}}]
      responses: {"200": {description: Locale-specific templates. Global templates have a null locale., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationTemplateListResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
    post:
      summary: Create a tenant notification template
      operationId: createAdminNotificationTemplate
      tags: [admin-notifications]
      security: [{adminBearer: []}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationTemplateRequest"}}}}
      responses: {"201": {description: Template created and audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationTemplateResponse"}}}}, "409": {description: "Duplicate code, channel and locale.", content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /admin-api/v1/notification-templates/{id}:
    patch:
      summary: Update a tenant notification template
      operationId: updateAdminNotificationTemplate
      tags: [admin-notifications]
      security: [{adminBearer: []}]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationTemplateRequest"}}}}
      responses: {"200": {description: Template updated and audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationTemplateResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}, "409": {description: "Duplicate code, channel and locale.", content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /admin-api/v1/notification-templates/{id}/sms-bindings:
    get:
      summary: List tenant SMS provider bindings for a template
      operationId: listAdminSMSTemplateBindings
      tags: [admin-notifications]
      security: [{adminBearer: []}]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: Provider bindings without credentials., content: {application/json: {schema: {$ref: "#/components/schemas/AdminSMSTemplateBindingListResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}}
  /admin-api/v1/notification-templates/{id}/sms-bindings/{provider}:
    put:
      summary: Create or replace an audited SMS provider template binding
      operationId: upsertAdminSMSTemplateBinding
      tags: [admin-notifications]
      security: [{adminBearer: []}]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}, {name: provider, in: path, required: true, schema: {type: string, enum: [tencent, aliyun]}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminSMSTemplateBindingRequest"}}}}
      responses: {"200": {description: Binding saved and audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminSMSTemplateBindingResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
    delete:
      summary: Delete an audited SMS provider template binding
      operationId: deleteAdminSMSTemplateBinding
      tags: [admin-notifications]
      security: [{adminBearer: []}]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}, {name: provider, in: path, required: true, schema: {type: string, enum: [tencent, aliyun]}}]
      responses: {"200": {description: Binding deleted., content: {application/json: {schema: {$ref: "#/components/schemas/AdminBooleanResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}}
  /admin-api/v1/notification-templates/{id}/test:
    post:
      summary: Enqueue a billable real delivery from a saved email or SMS template
      operationId: testAdminNotificationTemplate
      tags: [admin-notifications]
      security: [{adminBearer: []}]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationTemplateTestRequest"}}}}
      responses: {"202": {description: Encrypted delivery and River job created atomically., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationDeliveryResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}, "422": {$ref: "#/components/responses/ValidationFailed"}, "503": {$ref: "#/components/responses/ServiceUnavailable"}}
  /admin-api/v1/notification-deliveries:
    get:
      summary: List tenant notification deliveries without encrypted targets or provider payloads
      operationId: listAdminNotificationDeliveries
      tags: [admin-notifications]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}, {name: q, in: query, schema: {type: string, maxLength: 160}}, {name: channel, in: query, schema: {type: string, enum: [email, sms, push, webhook]}}, {name: status, in: query, schema: {type: string, enum: [pending, processing, sent, failed, cancelled]}}, {name: page, in: query, schema: {type: integer, minimum: 1, default: 1}}, {name: page_size, in: query, schema: {type: integer, minimum: 1, maximum: 100, default: 20}}]
      responses: {"200": {description: Safe delivery page with target hints only., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationDeliveryListResponse"}}}}, "403": {$ref: "#/components/responses/Forbidden"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /admin-api/v1/notification-deliveries/{id}:
    get:
      summary: Get safe notification delivery detail
      operationId: getAdminNotificationDelivery
      tags: [admin-notifications]
      security: [{adminBearer: []}]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: Safe error code and bounded summary; no target secret or raw provider payload., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationDeliveryResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}}
  /admin-api/v1/notification-deliveries/{id}/retry:
    post:
      summary: Requeue a failed delivery below its attempt limit
      operationId: retryAdminNotificationDelivery
      tags: [admin-notifications]
      security: [{adminBearer: []}]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationRetryRequest"}}}}
      responses: {"200": {description: Delivery reset to pending and audited. A configured worker adapter performs the next attempt., content: {application/json: {schema: {$ref: "#/components/schemas/AdminNotificationDeliveryResponse"}}}}, "409": {description: Delivery is not failed or exhausted its attempt budget., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}}
  /admin-api/v1/job-handlers:
    get:
      summary: List compile-time registered scheduled-job handlers
      operationId: listAdminJobHandlers
      tags: [admin-jobs]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      responses: {"200": {description: Static safe handler catalog with translation keys and payload schemas., content: {application/json: {schema: {$ref: "#/components/schemas/AdminJobHandlerListResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "403": {$ref: "#/components/responses/Forbidden"}}
  /admin-api/v1/job-schedules/preview:
    post:
      summary: Validate a registered handler, Cron expression and IANA time zone and preview five runs
      operationId: previewAdminJobSchedule
      tags: [admin-jobs]
      security: [{adminBearer: []}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminJobScheduleRequest"}}}}
      responses: {"200": {description: Five strictly ordered UTC instants interpreted in the requested IANA time zone., content: {application/json: {schema: {$ref: "#/components/schemas/AdminJobCronPreviewResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "403": {$ref: "#/components/responses/Forbidden"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /admin-api/v1/job-schedules:
    get:
      summary: List tenant-scoped scheduled jobs
      operationId: listAdminJobSchedules
      tags: [admin-jobs]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}, {name: q, in: query, schema: {type: string, maxLength: 160}}, {name: status, in: query, schema: {type: string, enum: [active, paused, disabled]}}, {name: time_zone, in: query, schema: {type: string, maxLength: 64}}, {name: page, in: query, schema: {type: integer, minimum: 1, default: 1}}, {name: page_size, in: query, schema: {type: integer, minimum: 1, maximum: 100, default: 20}}]
      responses: {"200": {description: Tenant-scoped schedule page., content: {application/json: {schema: {$ref: "#/components/schemas/AdminJobScheduleListResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "403": {$ref: "#/components/responses/Forbidden"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
    post:
      summary: Create a tenant scheduled job using a compile-time handler
      operationId: createAdminJobSchedule
      tags: [admin-jobs]
      security: [{adminBearer: []}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminJobScheduleRequest"}}}}
      responses: {"201": {description: Active schedule created with a DST-aware next run and audit record., content: {application/json: {schema: {$ref: "#/components/schemas/AdminJobScheduleResponse"}}}}, "409": {description: Tenant schedule code conflict., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /admin-api/v1/job-schedules/{id}:
    patch:
      summary: Update a tenant scheduled job
      operationId: updateAdminJobSchedule
      tags: [admin-jobs]
      security: [{adminBearer: []}]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminJobScheduleRequest"}}}}
      responses: {"200": {description: Schedule updated and audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminJobScheduleResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}, "409": {description: Disabled schedule or duplicate code conflict., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /admin-api/v1/job-schedules/{id}/pause:
    post:
      summary: Pause an active scheduled job
      operationId: pauseAdminJobSchedule
      tags: [admin-jobs]
      security: [{adminBearer: []}]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: Schedule paused and next run cleared., content: {application/json: {schema: {$ref: "#/components/schemas/AdminJobScheduleResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}, "409": {description: Invalid lifecycle transition., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}}
  /admin-api/v1/job-schedules/{id}/resume:
    post:
      summary: Resume a paused scheduled job
      operationId: resumeAdminJobSchedule
      tags: [admin-jobs]
      security: [{adminBearer: []}]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: Schedule resumed with a newly calculated next run., content: {application/json: {schema: {$ref: "#/components/schemas/AdminJobScheduleResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}, "409": {description: Invalid lifecycle transition., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}}
  /admin-api/v1/job-schedules/{id}/execute:
    post:
      summary: Manually enqueue a scheduled job through River
      operationId: executeAdminJobSchedule
      tags: [admin-jobs]
      security: [{adminBearer: []}]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}, {name: Idempotency-Key, in: header, required: true, schema: {type: string, minLength: 16, maxLength: 128}, description: Opaque key reused only when intentionally replaying the same manual execution request.}]
      responses: {"202": {description: Run record and River job inserted atomically; duplicate idempotency keys return the original run., content: {application/json: {schema: {$ref: "#/components/schemas/AdminJobRunResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}, "409": {description: Disabled schedule or overlap policy conflict., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /admin-api/v1/job-schedules/{id}/runs:
    get:
      summary: List safe run history for a tenant scheduled job
      operationId: listAdminJobScheduleRuns
      tags: [admin-jobs]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}, {name: id, in: path, required: true, schema: {type: string, format: uuid}}, {name: status, in: query, schema: {type: string, enum: [queued, running, succeeded, failed, cancelled, skipped]}}, {name: page, in: query, schema: {type: integer, minimum: 1, default: 1}}, {name: page_size, in: query, schema: {type: integer, minimum: 1, maximum: 100, default: 20}}]
      responses: {"200": {description: Safe run records; raw River errors and arbitrary worker logs are never returned., content: {application/json: {schema: {$ref: "#/components/schemas/AdminJobRunListResponse"}}}}, "404": {$ref: "#/components/responses/NotFound"}, "403": {$ref: "#/components/responses/Forbidden"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /admin-api/v1/configs:
    get:
      summary: List visible system configuration items
      operationId: listAdminConfigs
      tags: [admin-system-settings]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}, {name: q, in: query, schema: {type: string}}, {name: module_code, in: query, schema: {type: string}}, {name: config_group, in: query, schema: {type: string}}, {name: value_type, in: query, schema: {type: string}}, {name: status, in: query, schema: {type: string}}, {name: is_public, in: query, schema: {type: boolean}}, {name: is_secret, in: query, schema: {type: boolean}}, {name: sort, in: query, schema: {type: string}}, {name: page, in: query, schema: {type: integer}}, {name: page_size, in: query, schema: {type: integer, maximum: 100}}]
      responses: {"200": {description: "Secret plaintext and ciphertext are never returned.", content: {application/json: {schema: {$ref: "#/components/schemas/AdminConfigListResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "403": {$ref: "#/components/responses/Forbidden"}}
    post:
      summary: Create a tenant configuration item
      operationId: createAdminConfig
      tags: [admin-system-settings]
      security: [{adminBearer: []}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminConfigWriteRequest"}}}}
      responses: {"201": {description: Created, content: {application/json: {schema: {$ref: "#/components/schemas/AdminConfigResponse"}}}}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /admin-api/v1/configs/{id}:
    patch:
      summary: Update a tenant configuration item
      operationId: updateAdminConfig
      tags: [admin-system-settings]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}, {name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminConfigWriteRequest"}}}}
      responses: {"200": {description: Updated, content: {application/json: {schema: {$ref: "#/components/schemas/AdminConfigResponse"}}}}, "409": {description: Conflict, content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}}
  /admin-api/v1/configs/{id}/rotate-secret:
    post:
      summary: Replace a secret configuration value
      operationId: rotateAdminConfigSecret
      tags: [admin-system-settings]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}, {name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminConfigSecretRequest"}}}}
      responses: {"200": {description: "Secret replaced; plaintext and ciphertext are absent from response and audit.", content: {application/json: {schema: {$ref: "#/components/schemas/AdminConfigResponse"}}}}, "409": {description: Conflict, content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}}
  /admin-api/v1/dict-types:
    get:
      summary: List visible dictionary types
      operationId: listAdminDictionaryTypes
      tags: [admin-system-settings]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}, {name: q, in: query, schema: {type: string}}, {name: status, in: query, schema: {type: string}}, {name: sort, in: query, schema: {type: string}}, {name: page, in: query, schema: {type: integer}}, {name: page_size, in: query, schema: {type: integer, maximum: 100}}]
      responses: {"200": {description: Visible dictionary types, content: {application/json: {schema: {$ref: "#/components/schemas/AdminDictionaryTypeListResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "403": {$ref: "#/components/responses/Forbidden"}}
    post:
      summary: Create a tenant dictionary type
      operationId: createAdminDictionaryType
      tags: [admin-system-settings]
      security: [{adminBearer: []}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminDictionaryTypeWriteRequest"}}}}
      responses: {"201": {description: Created, content: {application/json: {schema: {$ref: "#/components/schemas/AdminDictionaryTypeResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "403": {$ref: "#/components/responses/Forbidden"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /admin-api/v1/dictionaries/{code}:
    get:
      summary: Resolve tenant-overlaid active dictionary options for internal Admin consumption
      operationId: getAdminDictionary
      tags: [admin-system-settings]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}, {name: code, in: path, required: true, schema: {type: string, pattern: "^[a-z][a-z0-9_.-]{1,159}$"}}]
      responses: {"200": {description: Merged consumption fields without internal overlay structure., content: {application/json: {schema: {$ref: "#/components/schemas/ResolvedDictionaryResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "403": {$ref: "#/components/responses/Forbidden"}, "404": {$ref: "#/components/responses/NotFound"}}
  /admin-api/v1/dict-types/{id}:
    patch:
      summary: Update a tenant dictionary type
      operationId: updateAdminDictionaryType
      tags: [admin-system-settings]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}, {name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminDictionaryTypeWriteRequest"}}}}
      responses: {"200": {description: Updated, content: {application/json: {schema: {$ref: "#/components/schemas/AdminDictionaryTypeResponse"}}}}, "409": {description: Conflict, content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}}
  /admin-api/v1/dict-types/{id}/items:
    get:
      summary: List items in a visible dictionary type
      operationId: listAdminDictionaryItems
      tags: [admin-system-settings]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}, {name: id, in: path, required: true, schema: {type: string, format: uuid}}, {name: q, in: query, schema: {type: string}}, {name: locale, in: query, schema: {type: string, enum: [zh-CN, en-US, neutral]}}, {name: status, in: query, schema: {type: string}}, {name: sort, in: query, schema: {type: string}}, {name: page, in: query, schema: {type: integer}}, {name: page_size, in: query, schema: {type: integer, maximum: 100}}]
      responses: {"200": {description: Items with explicit locale and lock state, content: {application/json: {schema: {$ref: "#/components/schemas/AdminDictionaryItemListResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "403": {$ref: "#/components/responses/Forbidden"}, "404": {$ref: "#/components/responses/NotFound"}}
    post:
      summary: Create a dictionary item
      operationId: createAdminDictionaryItem
      tags: [admin-system-settings]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}, {name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminDictionaryItemWriteRequest"}}}}
      responses: {"201": {description: Created, content: {application/json: {schema: {$ref: "#/components/schemas/AdminDictionaryItemResponse"}}}}, "409": {description: Conflict, content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}}
  /admin-api/v1/dict-items/{id}:
    patch:
      summary: Update a dictionary item
      operationId: updateAdminDictionaryItem
      tags: [admin-system-settings]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}, {name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminDictionaryItemWriteRequest"}}}}
      responses: {"200": {description: Updated, content: {application/json: {schema: {$ref: "#/components/schemas/AdminDictionaryItemResponse"}}}}, "409": {description: Conflict, content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}}
    delete:
      summary: Delete a dictionary item
      operationId: deleteAdminDictionaryItem
      tags: [admin-system-settings]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}, {name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: Deleted, content: {application/json: {schema: {$ref: "#/components/schemas/AdminDeleteResponse"}}}}, "409": {description: Conflict, content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}}
  /api/v1/auth/client-token:
    parameters: [{$ref: "#/components/parameters/AppID"}]
    post:
      summary: Exchange an API Client secret for a short-lived ak-api audience token
      operationId: createApiClientToken
      tags: [api-client-auth]
      security: []
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/APIClientTokenRequest"}}}}
      responses: {"200": {description: Machine access token., content: {application/json: {schema: {$ref: "#/components/schemas/APIClientTokenResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}}
  /admin-api/v1/api-clients:
    get:
      summary: List tenant API Clients without secret material
      operationId: listAdminAPIClients
      tags: [admin-api-clients]
      security: [{adminBearer: []}]
      parameters: [{name: q, in: query, schema: {type: string}}, {name: status, in: query, schema: {type: string, enum: [active, disabled]}}, {name: page, in: query, schema: {type: integer, default: 1}}, {name: page_size, in: query, schema: {type: integer, default: 20, maximum: 100}}]
      responses: {"200": {description: API Client page., content: {application/json: {schema: {$ref: "#/components/schemas/AdminAPIClientListResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "403": {$ref: "#/components/responses/Forbidden"}}
    post:
      summary: Create a tenant API Client
      operationId: createAdminAPIClient
      tags: [admin-api-clients]
      security: [{adminBearer: []}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminAPIClientRequest"}}}}
      responses: {"201": {description: API Client created without a secret., content: {application/json: {schema: {$ref: "#/components/schemas/AdminAPIClientResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "403": {$ref: "#/components/responses/Forbidden"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /admin-api/v1/api-clients/{id}:
    get:
      summary: Get one tenant API Client without secret material
      operationId: getAdminAPIClient
      tags: [admin-api-clients]
      security: [{adminBearer: []}]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: Tenant-scoped API Client metadata., content: {application/json: {schema: {$ref: "#/components/schemas/AdminAPIClientResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "403": {$ref: "#/components/responses/Forbidden"}, "404": {$ref: "#/components/responses/NotFound"}}
    patch:
      summary: Update an API Client status expiry and CIDR allowlist
      operationId: updateAdminAPIClient
      tags: [admin-api-clients]
      security: [{adminBearer: []}]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminAPIClientRequest"}}}}
      responses: {"200": {description: API Client updated., content: {application/json: {schema: {$ref: "#/components/schemas/AdminAPIClientResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "403": {$ref: "#/components/responses/Forbidden"}, "404": {$ref: "#/components/responses/NotFound"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /admin-api/v1/api-clients/{id}/secrets:
    post:
      summary: Create and disclose an API Client secret exactly once
      operationId: createAdminAPIClientSecret
      tags: [admin-api-clients]
      security: [{adminBearer: []}]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {content: {application/json: {schema: {$ref: "#/components/schemas/AdminAPIClientSecretRequest"}}}}
      responses: {"201": {description: One-time plaintext secret. Never returned by list or update., content: {application/json: {schema: {$ref: "#/components/schemas/AdminAPIClientSecretCreatedResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "403": {$ref: "#/components/responses/Forbidden"}, "404": {$ref: "#/components/responses/NotFound"}, "409": {description: At most two active secrets are allowed., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}}
  /admin-api/v1/api-clients/{id}/secrets/{secret_id}:
    delete:
      summary: Revoke an API Client secret
      operationId: revokeAdminAPIClientSecret
      tags: [admin-api-clients]
      security: [{adminBearer: []}]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}, {name: secret_id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: Secret revoked., content: {application/json: {schema: {$ref: "#/components/schemas/AdminBooleanResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "403": {$ref: "#/components/responses/Forbidden"}, "404": {$ref: "#/components/responses/NotFound"}}
  /admin-api/v1/api-clients/{id}/permissions:
    put:
      summary: Replace stable permission codes assigned to an API Client
      operationId: replaceAdminAPIClientPermissions
      tags: [admin-api-clients]
      security: [{adminBearer: []}]
      parameters: [{name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminAPIClientPermissionsRequest"}}}}
      responses: {"200": {description: Permissions replaced., content: {application/json: {schema: {$ref: "#/components/schemas/AdminAPIClientResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "403": {$ref: "#/components/responses/Forbidden"}, "404": {$ref: "#/components/responses/NotFound"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /admin-api/v1/webhooks:
    get:
      summary: List tenant webhook endpoints without signing secret material
      operationId: listAdminWebhooks
      tags: [admin-webhooks]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}, {name: q, in: query, schema: {type: string}}, {name: event_type, in: query, schema: {type: string}}, {name: status, in: query, schema: {type: string, enum: [active, disabled]}}, {name: page, in: query, schema: {type: integer, default: 1}}, {name: page_size, in: query, schema: {type: integer, default: 20, maximum: 100}}]
      responses: {"200": {description: Webhook endpoint page., content: {application/json: {schema: {$ref: "#/components/schemas/AdminWebhookListResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "403": {$ref: "#/components/responses/Forbidden"}}
    post:
      summary: Create a webhook endpoint and disclose its signing secret exactly once
      operationId: createAdminWebhook
      tags: [admin-webhooks]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminWebhookRequest"}}}}
      responses: {"201": {description: Endpoint plus one-time signing secret., content: {application/json: {schema: {$ref: "#/components/schemas/AdminWebhookCreatedResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "403": {$ref: "#/components/responses/Forbidden"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /admin-api/v1/webhooks/{id}:
    patch:
      summary: Update a webhook endpoint without rotating or exposing its signing secret
      operationId: updateAdminWebhook
      tags: [admin-webhooks]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}, {name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminWebhookRequest"}}}}
      responses: {"200": {description: Webhook endpoint updated., content: {application/json: {schema: {$ref: "#/components/schemas/AdminWebhookResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "403": {$ref: "#/components/responses/Forbidden"}, "404": {$ref: "#/components/responses/NotFound"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /admin-api/v1/webhooks/{id}/test:
    post:
      summary: Send an idempotent signed test delivery through the configured adapter
      operationId: testAdminWebhook
      tags: [admin-webhooks]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}, {name: id, in: path, required: true, schema: {type: string, format: uuid}}, {name: Idempotency-Key, in: header, required: true, schema: {type: string, minLength: 16, maxLength: 128}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminWebhookTestRequest"}}}}
      responses: {"200": {description: The created or existing idempotent delivery., content: {application/json: {schema: {$ref: "#/components/schemas/AdminWebhookDeliveryResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "403": {$ref: "#/components/responses/Forbidden"}, "404": {$ref: "#/components/responses/NotFound"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /admin-api/v1/webhooks/{id}/deliveries:
    get:
      summary: List bounded webhook delivery summaries for one tenant endpoint
      operationId: listAdminWebhookDeliveries
      tags: [admin-webhooks]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}, {name: id, in: path, required: true, schema: {type: string, format: uuid}}, {name: page, in: query, schema: {type: integer, default: 1}}, {name: page_size, in: query, schema: {type: integer, default: 20, maximum: 100}}]
      responses: {"200": {description: Delivery page with bounded response and error summaries., content: {application/json: {schema: {$ref: "#/components/schemas/AdminWebhookDeliveryListResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "403": {$ref: "#/components/responses/Forbidden"}, "404": {$ref: "#/components/responses/NotFound"}}
  /admin-api/v1/block-rules:
    get:
      summary: List tenant access rules with server-redacted subject hints
      operationId: listAdminBlockRules
      tags: [admin-audit-security]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}, {name: subject_type, in: query, schema: {$ref: "#/components/schemas/AdminBlockRuleSubjectType"}}, {name: subject_hint, in: query, description: Matches only the server-generated redacted hint., schema: {type: string}}, {name: scope, in: query, schema: {type: string, enum: [tenant]}}, {name: status, in: query, schema: {type: string, enum: [active, disabled]}}, {name: expiry, in: query, schema: {type: string, enum: [active, expired, never]}}, {name: page, in: query, schema: {type: integer, default: 1}}, {name: page_size, in: query, schema: {type: integer, default: 20, maximum: 100}}]
      responses: {"200": {description: Redacted access-rule page., content: {application/json: {schema: {$ref: "#/components/schemas/AdminBlockRuleListResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "403": {$ref: "#/components/responses/Forbidden"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
    post:
      summary: Create a tenant access rule after client-side impact confirmation
      operationId: createAdminBlockRule
      tags: [admin-audit-security]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminBlockRuleCreateRequest"}}}}
      responses: {"201": {description: Created rule with only a redacted subject hint., content: {application/json: {schema: {$ref: "#/components/schemas/AdminBlockRuleResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "403": {$ref: "#/components/responses/Forbidden"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
  /admin-api/v1/block-rules/{id}:
    patch:
      summary: Update access-rule action reason timing or status without returning its raw subject
      operationId: updateAdminBlockRule
      tags: [admin-audit-security]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}, {name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      requestBody: {required: true, content: {application/json: {schema: {$ref: "#/components/schemas/AdminBlockRuleUpdateRequest"}}}}
      responses: {"200": {description: Updated redacted rule., content: {application/json: {schema: {$ref: "#/components/schemas/AdminBlockRuleResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "403": {$ref: "#/components/responses/Forbidden"}, "404": {$ref: "#/components/responses/NotFound"}, "422": {$ref: "#/components/responses/ValidationFailed"}}
    delete:
      summary: Revoke and permanently remove a tenant access rule with an immutable audit record
      operationId: revokeAdminBlockRule
      tags: [admin-audit-security]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}, {name: id, in: path, required: true, schema: {type: string, format: uuid}}]
      responses: {"200": {description: Rule revoked., content: {application/json: {schema: {$ref: "#/components/schemas/AdminBlockRuleRevokeResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "403": {$ref: "#/components/responses/Forbidden"}, "404": {$ref: "#/components/responses/NotFound"}}
  /admin-api/v1/ops/health:
    get:
      summary: Read a secret-free dependency health summary
      operationId: getAdminOpsHealth
      tags: [admin-operations]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      responses: {"200": {description: Dependency status without connection strings or paths., content: {application/json: {schema: {$ref: "#/components/schemas/AdminOpsHealthResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "403": {$ref: "#/components/responses/Forbidden"}}
  /admin-api/v1/ops/runtime-summary:
    get:
      summary: Read versions modules Worker queue and tenant schedule-run counts without secrets
      operationId: getAdminOpsRuntimeSummary
      tags: [admin-operations]
      security: [{adminBearer: []}]
      parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
      responses: {"200": {description: Safe runtime diagnostic summary., content: {application/json: {schema: {$ref: "#/components/schemas/AdminOpsRuntimeResponse"}}}}, "401": {$ref: "#/components/responses/Unauthorized"}, "403": {$ref: "#/components/responses/Forbidden"}}
components:
  securitySchemes:
    adminBearer:
      type: http
      scheme: bearer
      bearerFormat: JWT
    mobileBearer:
      type: http
      scheme: bearer
      bearerFormat: JWT
    adminRefreshCookie:
      type: apiKey
      in: cookie
      name: ak_admin_refresh
  responses:
    Conflict:
      description: The resource changed or cannot transition in its current state.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
    BadRequest:
      description: The request could not be parsed or validated.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
    Unauthorized:
      description: Authentication is missing, expired or invalid.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
    Forbidden:
      description: The request is authenticated but not permitted, or CSRF validation failed.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
    ValidationFailed:
      description: Request validation failed.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
    NotFound:
      description: The requested resource is outside the authenticated self scope, missing or already revoked.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
    ServiceUnavailable:
      description: The requested feature is enabled but its required local or external service is unavailable.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
  parameters:
    AcceptLanguage:
      name: Accept-Language
      in: header
      required: false
      schema:
        type: string
    AppID:
      name: X-AppID
      in: header
      required: true
      description: Public immutable App UUID. It selects an active App only; authenticated tenant and user scope are derived from the verified session.
      schema: {type: string, format: uuid}
    CSRFToken:
      name: X-CSRF-Token
      in: header
      required: true
      schema:
        type: string
        minLength: 32
    AdminDeviceKey:
      name: X-AK-Device-Key
      in: header
      required: false
      description: A random installation identifier used only to associate Web sessions with a removable device record. It is not an authentication factor.
      schema:
        type: string
        format: uuid
    DashboardRange:
      name: range
      in: query
      required: false
      schema:
        type: string
        enum: [7d, 30d, 90d]
        default: 30d
    OrgResourceID:
      name: id
      in: path
      required: true
      schema: {type: string, format: uuid}
    TenantResourceID:
      name: id
      in: path
      required: true
      schema: {type: string, format: uuid}
    TenantMemberUserID:
      name: user_id
      in: path
      required: true
      schema: {type: string, format: uuid}
    RoleResourceID:
      name: id
      in: path
      required: true
      schema: {type: string, format: uuid}
    MenuResourceID:
      name: id
      in: path
      required: true
      schema: {type: string, format: uuid}
    AuditSecurityEventID:
      name: id
      in: path
      required: true
      schema: {type: string, format: uuid}
    UserResourceID:
      name: id
      in: path
      required: true
      schema: {type: string, format: uuid}
    OrgUserResourceID:
      name: user_id
      in: path
      required: true
      schema: {type: string, format: uuid}
    UserSessionResourceID:
      name: session_id
      in: path
      required: true
      schema: {type: string, format: uuid}
  pathItems:
    AdminUserEnable:
      parameters: [{$ref: "#/components/parameters/UserResourceID"}]
      post:
        summary: Enable a suspended tenant membership
        operationId: enableAdminUser
        tags: [admin-users]
        security: [{adminBearer: []}]
        parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
        responses:
          "200": {description: Membership enabled and audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminUserResponse"}}}}
          "401": {$ref: "#/components/responses/Unauthorized"}
          "403": {$ref: "#/components/responses/Forbidden"}
          "404": {$ref: "#/components/responses/NotFound"}
    AdminUserDisable:
      parameters: [{$ref: "#/components/parameters/UserResourceID"}]
      post:
        summary: Suspend a tenant membership and revoke its tenant sessions
        operationId: disableAdminUser
        tags: [admin-users]
        security: [{adminBearer: []}]
        parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
        responses:
          "200": {description: Membership suspended and tenant sessions revoked., content: {application/json: {schema: {$ref: "#/components/schemas/AdminUserResponse"}}}}
          "401": {$ref: "#/components/responses/Unauthorized"}
          "403": {$ref: "#/components/responses/Forbidden"}
          "404": {$ref: "#/components/responses/NotFound"}
          "409": {description: The last active tenant administrator cannot be disabled., content: {application/json: {schema: {$ref: "#/components/schemas/ErrorResponse"}}}}
    AdminUserUnlock:
      parameters: [{$ref: "#/components/parameters/UserResourceID"}]
      post:
        summary: Clear credential lock state for a tenant user
        operationId: unlockAdminUser
        tags: [admin-users]
        security: [{adminBearer: []}]
        parameters: [{$ref: "#/components/parameters/AcceptLanguage"}]
        responses:
          "200": {description: Credential unlocked and audited., content: {application/json: {schema: {$ref: "#/components/schemas/AdminUserActionResponse"}}}}
          "401": {$ref: "#/components/responses/Unauthorized"}
          "403": {$ref: "#/components/responses/Forbidden"}
          "404": {$ref: "#/components/responses/NotFound"}
  schemas:
    SupportedLocale:
      type: string
      enum: [zh-CN, en-US]
    AdminSwitchTenantRequest:
      type: object
      additionalProperties: false
      required: [tenant_id]
      properties:
        tenant_id: {type: string, format: uuid}
    HealthResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data:
          type: object
          required: [status]
          properties:
            status: {type: string}
        request_id: {type: string}
    AppPublicConfigResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data:
          type: object
          required: [app_id, appid, app_type, name, default_locale, registration_enabled, registration_verification_mode, startup]
          properties:
            app_id: {type: string, format: uuid}
            appid: {type: string}
            app_type: {type: string, enum: [uni_app, uni_app_x]}
            name: {type: string}
            default_locale: {$ref: "#/components/schemas/SupportedLocale"}
            registration_enabled: {type: boolean}
            registration_verification_mode: {type: string, enum: [none, email_otp]}
            startup: {$ref: "#/components/schemas/AppPublicStartup"}
        request_id: {type: string}
    PublicConfigResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data:
          type: object
          required: [locale, default_locale, supported_locales, feature_flags, settings]
          properties:
            locale: {$ref: "#/components/schemas/SupportedLocale"}
            default_locale: {$ref: "#/components/schemas/SupportedLocale"}
            supported_locales: {type: array, items: {$ref: "#/components/schemas/SupportedLocale"}}
            feature_flags: {type: object, additionalProperties: {type: boolean}}
            settings: {type: object, additionalProperties: true}
        request_id: {type: string}
    AppPublicPage:
      type: object
      required: [slug, document_type, title, body, body_format, version, content_hash, locale, revision_id]
      properties:
        slug: {type: string}
        document_type: {type: string, enum: [privacy-policy, terms-of-service, about-us, custom]}
        title: {type: string}
        body: {oneOf: [{type: string}, {type: array}]}
        body_format: {type: string, enum: [markdown, blocks]}
        version: {type: integer, minimum: 1}
        content_hash: {type: string, pattern: '^[a-f0-9]{64}$'}
        locale: {$ref: "#/components/schemas/SupportedLocale"}
        revision_id: {type: string, format: uuid}
    AppPublicPageResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/AppPublicPage"}, request_id: {type: string}}
    AppLegalConsentRequest:
      type: object
      additionalProperties: false
      required: [document_type, revision_id, content_hash, locale]
      properties:
        document_type: {type: string, enum: [privacy-policy, terms-of-service]}
        revision_id: {type: string, format: uuid}
        content_hash: {type: string, pattern: '^[a-f0-9]{64}$'}
        locale: {$ref: "#/components/schemas/SupportedLocale"}
    AppRegistrationRequest:
      type: object
      additionalProperties: false
      required: [email, display_name, password, locale, accept_terms]
      properties:
        email: {type: string, format: email, maxLength: 254}
        display_name: {type: string, minLength: 2, maxLength: 120}
        password: {type: string, format: password, minLength: 12, maxLength: 256}
        locale: {$ref: "#/components/schemas/SupportedLocale"}
        accept_terms: {type: boolean, const: true}
    AppEmailRequest:
      type: object
      additionalProperties: false
      required: [email]
      properties: {email: {type: string, format: email, maxLength: 254}}
    AppEmailOTPRequest:
      allOf:
        - $ref: "#/components/schemas/AppEmailRequest"
        - type: object
          required: [code]
          properties: {code: {type: string, pattern: '^[0-9]{6}$'}}
    AppPasswordResetRequest:
      allOf:
        - $ref: "#/components/schemas/AppEmailOTPRequest"
        - type: object
          required: [new_password]
          properties: {new_password: {type: string, format: password, minLength: 12, maxLength: 256}}
    AppAcceptedResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {type: object, required: [accepted], properties: {accepted: {type: boolean}, verification_required: {type: boolean}, retry_after_seconds: {type: integer, minimum: 1}}}, request_id: {type: string}}
    AdminApp:
      type: object
      required: [id, tenant_id, appid, appid_pending, app_type, code, name, description, introduction, remark, status, default_locale, registration_enabled, registration_verification_mode, owner_type, managers, members, screenshots, channels, store_listings, is_default, lock_version, created_at, updated_at, startup]
      properties:
        id: {type: string, format: uuid}
        tenant_id: {type: string, format: uuid}
        appid: {type: string}
        appid_pending: {type: boolean}
        app_type: {type: string, enum: [uni_app, uni_app_x]}
        code: {type: string, pattern: '^[a-z][a-z0-9-]{1,62}$'}
        name: {type: string, minLength: 1, maxLength: 120}
        description: {type: string, maxLength: 4000}
        introduction: {type: string, maxLength: 1000}
        remark: {type: string, maxLength: 4000}
        status: {type: string, enum: [active, disabled]}
        default_locale: {$ref: "#/components/schemas/SupportedLocale"}
        registration_enabled: {type: boolean}
        registration_verification_mode: {type: string, enum: [none, email_otp]}
        creator_user_id: {type: [string, 'null'], format: uuid}
        owner_type: {type: string, enum: [user, tenant]}
        owner_id: {type: [string, 'null'], format: uuid}
        icon_file_id: {type: [string, 'null'], format: uuid}
        managers: {type: array, maxItems: 100, items: {type: string, format: uuid}}
        members: {type: array, maxItems: 100, items: {type: string, format: uuid}}
        screenshots: {type: array, maxItems: 20, items: {$ref: "#/components/schemas/AdminAppAsset"}}
        channels: {type: array, maxItems: 20, items: {$ref: "#/components/schemas/AdminAppChannel"}}
        store_listings: {type: array, maxItems: 100, items: {$ref: "#/components/schemas/AdminAppStoreListing"}}
        is_default: {type: boolean}
        lock_version: {type: integer, minimum: 1}
        created_at: {type: string, format: date-time}
        updated_at: {type: string, format: date-time}
        startup: {$ref: "#/components/schemas/AdminAppStartup"}
    AdminAppRequest:
      type: object
      additionalProperties: false
      required: [appid, app_type, name, default_locale, registration_enabled, registration_verification_mode, startup]
      properties:
        appid: {type: string, pattern: '^__UNI__[A-Za-z0-9_]{2,120}$'}
        app_type: {type: string, enum: [uni_app, uni_app_x]}
        code: {type: string, pattern: '^[a-z][a-z0-9-]{1,62}$'}
        name: {type: string, minLength: 1, maxLength: 120}
        description: {type: string, maxLength: 4000}
        introduction: {type: string, maxLength: 1000}
        remark: {type: string, maxLength: 4000}
        default_locale: {$ref: "#/components/schemas/SupportedLocale"}
        registration_enabled: {type: boolean}
        registration_verification_mode: {type: string, enum: [none, email_otp]}
        owner_type: {type: string, enum: [user, tenant]}
        owner_id: {type: [string, 'null'], format: uuid}
        icon_file_id: {type: [string, 'null'], format: uuid}
        managers: {type: array, maxItems: 100, items: {type: string, format: uuid}}
        members: {type: array, maxItems: 100, items: {type: string, format: uuid}}
        screenshot_file_ids: {type: array, maxItems: 20, items: {type: string, format: uuid}}
        channels: {type: array, maxItems: 20, items: {$ref: "#/components/schemas/AdminAppChannel"}}
        store_listings: {type: array, maxItems: 100, items: {$ref: "#/components/schemas/AdminAppStoreListing"}}
        lock_version: {type: integer, minimum: 1}
        startup: {$ref: "#/components/schemas/AdminAppStartupInput"}
    StartupTranslation:
      type: object
      additionalProperties: false
      required: [display_name, subtitle]
      properties:
        display_name: {type: string, minLength: 1, maxLength: 120}
        subtitle: {type: string, maxLength: 240}
    StartupSlideAsset:
      type: object
      additionalProperties: false
      required: [file_id, accessibility_label]
      properties:
        file_id: {type: string, format: uuid}
        accessibility_label: {type: string, minLength: 1, maxLength: 500}
    StartupSlide:
      type: object
      additionalProperties: false
      required: [position, assets]
      properties:
        id: {type: string, format: uuid}
        position: {type: integer, minimum: 0, maximum: 9}
        assets:
          type: object
          additionalProperties: false
          required: [zh-CN, en-US]
          properties:
            zh-CN: {$ref: "#/components/schemas/StartupSlideAsset"}
            en-US: {$ref: "#/components/schemas/StartupSlideAsset"}
    AdminAppStartupInput:
      type: object
      additionalProperties: false
      required: [translations, onboarding_enabled, draft_slides]
      properties:
        translations:
          type: object
          additionalProperties: false
          required: [zh-CN, en-US]
          properties:
            zh-CN: {$ref: "#/components/schemas/StartupTranslation"}
            en-US: {$ref: "#/components/schemas/StartupTranslation"}
        onboarding_enabled: {type: boolean}
        draft_slides: {type: array, maxItems: 10, items: {$ref: "#/components/schemas/StartupSlide"}}
    AdminAppStartup:
      allOf:
        - $ref: "#/components/schemas/AdminAppStartupInput"
        - type: object
          required: [published_version, draft_changed]
          properties:
            published_version: {type: integer, minimum: 0}
            published_at: {type: [string, 'null'], format: date-time}
            draft_changed: {type: boolean}
    AdminAppOnboardingPublishRequest:
      type: object
      additionalProperties: false
      required: [expected_published_version]
      properties:
        expected_published_version: {type: integer, minimum: 0}
    AppPublicStartupSlide:
      type: object
      required: [position, image_url, accessibility_label]
      properties:
        position: {type: integer, minimum: 0, maximum: 9}
        image_url: {type: string}
        accessibility_label: {type: string, minLength: 1, maxLength: 500}
    AppPublicStartup:
      type: object
      required: [display_name, subtitle, onboarding_enabled, published_version, slides]
      properties:
        display_name: {type: string, minLength: 1, maxLength: 120}
        subtitle: {type: string, maxLength: 240}
        icon_url: {type: [string, 'null']}
        onboarding_enabled: {type: boolean}
        published_version: {type: integer, minimum: 0}
        slides: {type: array, maxItems: 10, items: {$ref: "#/components/schemas/AppPublicStartupSlide"}}
    AdminAppAsset:
      type: object
      required: [id, file_id, position]
      properties: {id: {type: string, format: uuid}, file_id: {type: string, format: uuid}, position: {type: integer, minimum: 0}}
    AdminAppChannel:
      type: object
      required: [channel_code, name, enabled]
      properties:
        id: {type: string, format: uuid}
        channel_code: {type: string, enum: [android, ios, harmony, h5, quickapp, mp_weixin, mp_alipay, mp_baidu, mp_toutiao, mp_qq, mp_kuaishou, mp_lark, mp_jd, mp_dingtalk]}
        name: {type: string, maxLength: 160}
        url: {type: [string, 'null'], pattern: '^https://'}
        abm_url: {type: [string, 'null'], pattern: '^https://'}
        qrcode_file_id: {type: [string, 'null'], format: uuid}
        enabled: {type: boolean}
    AdminAppStoreListing:
      type: object
      required: [name, scheme, enabled, priority]
      properties: {id: {type: string, format: uuid}, name: {type: string, minLength: 1, maxLength: 160}, scheme: {type: string, maxLength: 255}, enabled: {type: boolean}, priority: {type: integer, minimum: -100000, maximum: 100000}}
    AdminAppStatusRequest:
      type: object
      additionalProperties: false
      required: [lock_version]
      properties: {lock_version: {type: integer, minimum: 1}}
    AdminAppResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/AdminApp"}, request_id: {type: string}}
    AdminAppListResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/AdminAppListPage"}, request_id: {type: string}}
    AdminAppListPage:
      type: object
      required: [items, total]
      properties: {items: {type: array, items: {$ref: "#/components/schemas/AdminApp"}}, total: {type: integer, minimum: 0}}
    AdminAppPage:
      type: object
      required: [id, slug, page_type, status, lock_version, updated_at, translations, revisions]
      properties:
        id: {type: string, format: uuid}
        slug: {type: string}
        page_type: {type: string, enum: [privacy-policy, terms-of-service, about-us, custom]}
        status: {type: string, enum: [draft, published, archived]}
        lock_version: {type: integer, minimum: 1}
        current_revision_id: {type: [string, 'null'], format: uuid}
        updated_at: {type: string, format: date-time}
        translations: {type: object, required: [zh-CN, en-US], properties: {zh-CN: {type: object, required: [title, body_format, body], properties: {title: {type: string}, body_format: {type: string, enum: [markdown, blocks]}, body: {oneOf: [{type: string}, {type: array}]}}}, en-US: {type: object, required: [title, body_format, body], properties: {title: {type: string}, body_format: {type: string, enum: [markdown, blocks]}, body: {oneOf: [{type: string}, {type: array}]}}}}}
        revisions: {type: array, items: {type: object, required: [id, version, status, content_hash, created_at], properties: {id: {type: string, format: uuid}, version: {type: integer, minimum: 1}, status: {type: string, enum: [draft, published, archived]}, content_hash: {type: string}, created_at: {type: string, format: date-time}, created_by: {type: [string, 'null'], format: uuid}}}}
    AdminAppPageRequest:
      type: object
      additionalProperties: false
      required: [slug, page_type, translations, publish]
      properties:
        slug: {type: string, pattern: '^[a-z0-9]+(?:-[a-z0-9]+)*$'}
        page_type: {type: string, enum: [privacy-policy, terms-of-service, about-us, custom]}
        lock_version: {type: integer, minimum: 1}
        publish: {type: boolean}
        translations:
          type: object
          required: [zh-CN, en-US]
          properties:
            zh-CN: {$ref: "#/components/schemas/AdminAppPageTranslation"}
            en-US: {$ref: "#/components/schemas/AdminAppPageTranslation"}
    AdminAppPageTranslation:
      type: object
      required: [title, body_format, body]
      properties: {title: {type: string, minLength: 1, maxLength: 300}, body_format: {type: string, enum: [markdown, blocks]}, body: {oneOf: [{type: string}, {type: array}]}}
    AdminAppPageResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/AdminAppPage"}, request_id: {type: string}}
    AdminAppPageListResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/AdminAppPageListPage"}, request_id: {type: string}}
    AdminAppPageListPage:
      type: object
      required: [items, total]
      properties: {items: {type: array, items: {$ref: "#/components/schemas/AdminAppPage"}}, total: {type: integer, minimum: 0}}
    AdminAppUser:
      type: object
      required: [id, user_id, email, display_name, status, source, created_at, lock_version]
      properties:
        id: {type: string, format: uuid}
        user_id: {type: string, format: uuid}
        email: {type: string, format: email}
        display_name: {type: string}
        status: {type: string, enum: [pending_verification, active, disabled]}
        source: {type: string, enum: [self_registration, admin_created, legacy]}
        verified_at: {type: [string, 'null'], format: date-time}
        created_at: {type: string, format: date-time}
        last_sign_in_at: {type: [string, 'null'], format: date-time}
        lock_version: {type: integer, minimum: 1}
    AdminAppUserResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/AdminAppUser"}, request_id: {type: string}}
    AdminAppUserListResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/AdminAppUserListPage"}, request_id: {type: string}}
    AdminAppUserListPage:
      type: object
      required: [items, total]
      properties: {items: {type: array, items: {$ref: "#/components/schemas/AdminAppUser"}}, total: {type: integer, minimum: 0}}
    AdminAppUserCreateRequest:
      type: object
      additionalProperties: false
      required: [email, display_name, locale, password]
      properties: {email: {type: string, format: email}, display_name: {type: string, minLength: 2, maxLength: 120}, locale: {$ref: "#/components/schemas/SupportedLocale"}, password: {type: string, format: password, minLength: 12, maxLength: 256}}
    AdminAppUserUpdateRequest:
      type: object
      additionalProperties: false
      required: [display_name, lock_version]
      properties: {display_name: {type: string, minLength: 2, maxLength: 120}, lock_version: {type: integer, minimum: 1}}
    AdminAppUserActionRequest:
      type: object
      additionalProperties: false
      required: [lock_version]
      properties: {lock_version: {type: integer, minimum: 1}}
    AdminAppPasswordResetRequest:
      type: object
      additionalProperties: false
      required: [new_password, lock_version]
      properties: {new_password: {type: string, format: password, minLength: 12, maxLength: 256}, lock_version: {type: integer, minimum: 1}}
    ErrorResponse:
      type: object
      required: [error, request_id]
      properties:
        error:
          type: object
          required: [code, message_key, message]
          properties:
            code: {type: string}
            message_key: {type: string}
            message: {type: string}
            details: {type: object}
        request_id: {type: string}
    OrgStatus:
      type: string
      enum: [active, disabled]
    AdminOrgUnit:
      type: object
      additionalProperties: false
      required: [id, parent_id, code, name, unit_type, phone, email, sort_order, status, direct_member_count, child_count, updated_at, children]
      properties:
        id: {type: string, format: uuid}
        parent_id: {type: [string, "null"], format: uuid}
        code: {type: string, minLength: 2, maxLength: 64}
        name: {type: string, minLength: 1, maxLength: 160}
        unit_type: {type: string, enum: [company, division, department, team, group]}
        phone: {type: string, maxLength: 32}
        email: {type: string, maxLength: 320}
        sort_order: {type: integer, format: int32}
        status: {$ref: "#/components/schemas/OrgStatus"}
        direct_member_count: {type: integer, format: int64, minimum: 0}
        child_count: {type: integer, format: int64, minimum: 0}
        updated_at: {type: string, format: date-time}
        children:
          type: array
          items: {$ref: "#/components/schemas/AdminOrgUnit"}
    AdminOrgUnitRequest:
      type: object
      additionalProperties: false
      required: [code, name, unit_type, phone, email, sort_order, status]
      properties:
        parent_id: {type: [string, "null"], format: uuid}
        code: {type: string, minLength: 2, maxLength: 64}
        name: {type: string, minLength: 1, maxLength: 160}
        unit_type: {type: string, enum: [company, division, department, team, group]}
        phone: {type: string, maxLength: 32}
        email: {type: string, maxLength: 320}
        sort_order: {type: integer, format: int32, default: 0}
        status: {$ref: "#/components/schemas/OrgStatus"}
    AdminOrgUnitMoveRequest:
      type: object
      additionalProperties: false
      required: [parent_id, sort_order]
      properties:
        parent_id: {type: [string, "null"], format: uuid}
        sort_order: {type: integer, format: int32}
    AdminOrgUnitResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data: {$ref: "#/components/schemas/AdminOrgUnit"}
        request_id: {type: string}
    AdminOrgUnitTreeResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data: {type: array, items: {$ref: "#/components/schemas/AdminOrgUnit"}}
        request_id: {type: string}
    AdminOrgPosition:
      type: object
      additionalProperties: false
      required: [id, code, name, description, sort_order, status, member_count, updated_at]
      properties:
        id: {type: string, format: uuid}
        code: {type: string, minLength: 2, maxLength: 64}
        name: {type: string, minLength: 1, maxLength: 120}
        description: {type: string, maxLength: 500}
        sort_order: {type: integer, format: int32}
        status: {$ref: "#/components/schemas/OrgStatus"}
        member_count: {type: integer, format: int64, minimum: 0}
        updated_at: {type: string, format: date-time}
    AdminOrgPositionRequest:
      type: object
      additionalProperties: false
      required: [code, name, description, sort_order, status]
      properties:
        code: {type: string, minLength: 2, maxLength: 64}
        name: {type: string, minLength: 1, maxLength: 120}
        description: {type: string, maxLength: 500}
        sort_order: {type: integer, format: int32, default: 0}
        status: {$ref: "#/components/schemas/OrgStatus"}
    AdminOrgPositionResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data: {$ref: "#/components/schemas/AdminOrgPosition"}
        request_id: {type: string}
    AdminOrgPositionListResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data:
          type: object
          required: [items, total]
          properties:
            items: {type: array, items: {$ref: "#/components/schemas/AdminOrgPosition"}}
            total: {type: integer, minimum: 0}
        request_id: {type: string}
    AdminDeleteResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data:
          type: object
          required: [deleted]
          properties: {deleted: {type: boolean, const: true}}
        request_id: {type: string}
    AdminAccessStatus:
      type: string
      enum: [active, disabled]
    AdminRoleType:
      type: string
      enum: [system, custom]
    AdminDataScope:
      type: string
      enum: [all, tenant, department, department_tree, self, custom]
    AdminRole:
      type: object
      additionalProperties: false
      required: [id, parent_id, code, name, description, role_type, data_scope, sort_order, is_default, is_system, status, member_count, permission_ids, menu_ids, scope_unit_ids, created_at, updated_at]
      properties:
        id: {type: string, format: uuid}
        parent_id: {type: [string, "null"], format: uuid}
        code: {type: string, minLength: 2, maxLength: 128}
        name: {type: string, minLength: 1, maxLength: 120}
        description: {type: string, maxLength: 500}
        role_type: {$ref: "#/components/schemas/AdminRoleType"}
        data_scope: {$ref: "#/components/schemas/AdminDataScope"}
        sort_order: {type: integer, format: int32}
        is_default: {type: boolean}
        is_system: {type: boolean}
        status: {$ref: "#/components/schemas/AdminAccessStatus"}
        member_count: {type: integer, format: int64, minimum: 0}
        permission_ids: {type: array, items: {type: string, format: uuid}, uniqueItems: true}
        menu_ids: {type: array, items: {type: string, format: uuid}, uniqueItems: true}
        scope_unit_ids: {type: array, items: {type: string, format: uuid}, uniqueItems: true}
        created_at: {type: string, format: date-time}
        updated_at: {type: string, format: date-time}
    AdminRoleRequest:
      type: object
      additionalProperties: false
      required: [parent_id, code, name, description, sort_order, status]
      properties:
        parent_id: {type: [string, "null"], format: uuid}
        code: {type: string, pattern: "^[a-z][a-z0-9._-]{1,127}$"}
        name: {type: string, minLength: 1, maxLength: 120}
        description: {type: string, maxLength: 500}
        sort_order: {type: integer, format: int32}
        status: {$ref: "#/components/schemas/AdminAccessStatus"}
    AdminRolePermissionsRequest:
      type: object
      additionalProperties: false
      required: [permission_ids]
      properties:
        permission_ids: {type: array, maxItems: 500, uniqueItems: true, items: {type: string, format: uuid}}
    AdminRoleMenusRequest:
      type: object
      additionalProperties: false
      required: [menu_ids]
      properties:
        menu_ids: {type: array, maxItems: 500, uniqueItems: true, items: {type: string, format: uuid}}
    AdminRoleDataScopeRequest:
      type: object
      additionalProperties: false
      required: [data_scope, unit_ids]
      properties:
        data_scope: {$ref: "#/components/schemas/AdminDataScope"}
        unit_ids: {type: array, maxItems: 500, uniqueItems: true, items: {type: string, format: uuid}}
    AdminRoleResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data: {$ref: "#/components/schemas/AdminRole"}
        request_id: {type: string}
    AdminRoleListResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data:
          type: object
          additionalProperties: false
          required: [items, total, page, page_size]
          properties:
            items: {type: array, items: {$ref: "#/components/schemas/AdminRole"}}
            total: {type: integer, format: int64, minimum: 0}
            page: {type: integer, minimum: 1}
            page_size: {type: integer, minimum: 1, maximum: 100}
        request_id: {type: string}
    AdminPermissionKind:
      type: string
      enum: [api, ui_action, feature]
    AdminPermission:
      type: object
      additionalProperties: false
      required: [id, code, name, module_code, resource_name, action_name, permission_kind, http_methods, route_pattern, description, status]
      properties:
        id: {type: string, format: uuid}
        code: {type: string}
        name: {type: string}
        module_code: {type: string}
        resource_name: {type: string}
        action_name: {type: string}
        permission_kind: {$ref: "#/components/schemas/AdminPermissionKind"}
        http_methods: {type: array, items: {type: string}}
        route_pattern: {type: string}
        description: {type: string}
        status: {$ref: "#/components/schemas/AdminAccessStatus"}
    AdminPermissionListResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data:
          type: object
          additionalProperties: false
          required: [items, total]
          properties:
            items: {type: array, items: {$ref: "#/components/schemas/AdminPermission"}}
            total: {type: integer, minimum: 0}
        request_id: {type: string}
    AdminMenuType:
      type: string
      enum: [directory, page, external]
    AdminMenuNode:
      type: object
      additionalProperties: false
      required: [id, tenant_id, parent_id, permission_id, permission_code, code, title, i18n_key, type, path, component_key, icon, external_url, open_mode, hidden, affix, sort_order, status, is_core, role_count, children, updated_at]
      properties:
        id: {type: string, format: uuid}
        tenant_id: {type: [string, "null"], format: uuid}
        parent_id: {type: [string, "null"], format: uuid}
        permission_id: {type: [string, "null"], format: uuid}
        permission_code: {type: string}
        code: {type: string}
        title: {type: string}
        i18n_key: {type: string}
        type: {$ref: "#/components/schemas/AdminMenuType"}
        path: {type: string}
        component_key: {type: string}
        icon: {type: string}
        external_url: {type: string}
        open_mode: {type: string, enum: [same_tab, new_tab, iframe]}
        hidden: {type: boolean}
        affix: {type: boolean}
        sort_order: {type: integer, format: int32}
        status: {$ref: "#/components/schemas/AdminAccessStatus"}
        is_core: {type: boolean}
        role_count: {type: integer, format: int64, minimum: 0}
        children: {type: array, items: {$ref: "#/components/schemas/AdminMenuNode"}}
        updated_at: {type: string, format: date-time}
    AdminMenuRequest:
      type: object
      additionalProperties: false
      required: [parent_id, permission_id, code, title, i18n_key, type, path, component_key, icon, external_url, open_mode, hidden, affix, sort_order, status]
      properties:
        parent_id: {type: [string, "null"], format: uuid}
        permission_id: {type: [string, "null"], format: uuid}
        code: {type: string, pattern: "^[a-z][a-z0-9._-]{1,127}$"}
        title: {type: string, minLength: 1, maxLength: 160}
        i18n_key: {type: string, minLength: 1, maxLength: 200}
        type: {$ref: "#/components/schemas/AdminMenuType"}
        path: {type: string, maxLength: 500}
        component_key: {type: string, maxLength: 255}
        icon: {type: string, maxLength: 160}
        external_url: {type: string, maxLength: 2000}
        open_mode: {type: string, enum: [same_tab, new_tab, iframe]}
        hidden: {type: boolean}
        affix: {type: boolean}
        sort_order: {type: integer, format: int32}
        status: {$ref: "#/components/schemas/AdminAccessStatus"}
    AdminMenuMoveRequest:
      type: object
      additionalProperties: false
      required: [parent_id, sort_order]
      properties:
        parent_id: {type: [string, "null"], format: uuid}
        sort_order: {type: integer, format: int32}
    AdminMenuResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data: {$ref: "#/components/schemas/AdminMenuNode"}
        request_id: {type: string}
    AdminMenuTreeResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data:
          type: object
          additionalProperties: false
          required: [items]
          properties:
            items: {type: array, items: {$ref: "#/components/schemas/AdminMenuNode"}}
        request_id: {type: string}
    AdminAuditJSONObject:
      type: object
      description: A recursively field-redacted JSON object. Sensitive values are replaced with the stable string [REDACTED].
      additionalProperties: true
    AdminAuditOperation:
      type: object
      additionalProperties: false
      required: [id, user_id, session_id, request_id, trace_id, module_code, action_name, permission_code, resource_type, resource_id, http_method, request_path, response_status, client_ip, request_summary, before_data, after_data, duration_ms, succeeded, error_code, occurred_at]
      properties:
        id: {type: string, format: uuid}
        user_id: {type: [string, "null"], format: uuid}
        session_id: {type: [string, "null"], format: uuid}
        request_id: {type: string}
        trace_id: {type: string}
        module_code: {type: string}
        action_name: {type: string}
        permission_code: {type: string}
        resource_type: {type: string}
        resource_id: {type: string}
        http_method: {type: string}
        request_path: {type: string}
        response_status: {type: [integer, "null"], format: int32}
        client_ip: {type: string}
        request_summary: {$ref: "#/components/schemas/AdminAuditJSONObject"}
        before_data: {$ref: "#/components/schemas/AdminAuditJSONObject"}
        after_data: {$ref: "#/components/schemas/AdminAuditJSONObject"}
        duration_ms: {type: [integer, "null"], format: int32, minimum: 0}
        succeeded: {type: boolean}
        error_code: {type: string}
        occurred_at: {type: string, format: date-time}
    AdminAuditLogin:
      type: object
      additionalProperties: false
      required: [id, user_id, session_id, request_id, login_identifier_hint, auth_method, audience, result, failure_reason, client_ip, occurred_at]
      properties:
        id: {type: string, format: uuid}
        user_id: {type: [string, "null"], format: uuid}
        session_id: {type: [string, "null"], format: uuid}
        request_id: {type: string}
        login_identifier_hint: {type: string, description: Redacted display hint only; never the identifier hash or complete account identifier.}
        auth_method: {type: string}
        audience: {type: string, enum: [ak-mobile, ak-admin, ak-api]}
        result: {type: string, enum: [success, failure, blocked]}
        failure_reason: {type: string}
        client_ip: {type: string}
        occurred_at: {type: string, format: date-time}
    AdminAuditSecurityEvent:
      type: object
      additionalProperties: false
      required: [id, user_id, session_id, event_type, severity, source, client_ip, details, resolved_at, resolved_by, occurred_at]
      properties:
        id: {type: string, format: uuid}
        user_id: {type: [string, "null"], format: uuid}
        session_id: {type: [string, "null"], format: uuid}
        event_type: {type: string}
        severity: {type: string, enum: [info, low, medium, high, critical]}
        source: {type: string}
        client_ip: {type: string}
        details: {$ref: "#/components/schemas/AdminAuditJSONObject"}
        resolved_at: {type: [string, "null"], format: date-time}
        resolved_by: {type: [string, "null"], format: uuid}
        occurred_at: {type: string, format: date-time}
    AdminAuditOperationListResponse:
      $ref: "#/components/schemas/AdminAuditOperationPageEnvelope"
    AdminAuditLoginListResponse:
      $ref: "#/components/schemas/AdminAuditLoginPageEnvelope"
    AdminAuditSecurityEventListResponse:
      $ref: "#/components/schemas/AdminAuditSecurityEventPageEnvelope"
    AdminAuditOperationPageEnvelope:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data: {$ref: "#/components/schemas/AdminAuditOperationPage"}
        request_id: {type: string}
    AdminAuditLoginPageEnvelope:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data: {$ref: "#/components/schemas/AdminAuditLoginPage"}
        request_id: {type: string}
    AdminAuditSecurityEventPageEnvelope:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data: {$ref: "#/components/schemas/AdminAuditSecurityEventPage"}
        request_id: {type: string}
    AdminAuditOperationPage:
      type: object
      required: [items, total, page, page_size]
      properties:
        items: {type: array, items: {$ref: "#/components/schemas/AdminAuditOperation"}}
        total: {type: integer, format: int64, minimum: 0}
        page: {type: integer, minimum: 1}
        page_size: {type: integer, minimum: 1, maximum: 100}
    AdminAuditLoginPage:
      type: object
      required: [items, total, page, page_size]
      properties:
        items: {type: array, items: {$ref: "#/components/schemas/AdminAuditLogin"}}
        total: {type: integer, format: int64, minimum: 0}
        page: {type: integer, minimum: 1}
        page_size: {type: integer, minimum: 1, maximum: 100}
    AdminAuditSecurityEventPage:
      type: object
      required: [items, total, page, page_size]
      properties:
        items: {type: array, items: {$ref: "#/components/schemas/AdminAuditSecurityEvent"}}
        total: {type: integer, format: int64, minimum: 0}
        page: {type: integer, minimum: 1}
        page_size: {type: integer, minimum: 1, maximum: 100}
    AdminAuditSecurityEventResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data: {$ref: "#/components/schemas/AdminAuditSecurityEvent"}
        request_id: {type: string}
    AdminOnlineSession:
      type: object
      additionalProperties: false
      required: [id, user_id, user_hint, display_name, audience, platform, device_hint, ip_hint, status, current, last_seen_at, expires_at, revoked_at]
      properties:
        id: {type: string, format: uuid}
        user_id: {type: string, format: uuid}
        user_hint: {type: string, description: Server-masked login identifier.}
        display_name: {type: string}
        audience: {type: string, enum: [ak-mobile, ak-admin, ak-api]}
        platform: {type: string, enum: [android, ios, harmonyos, web, desktop, unknown]}
        device_hint: {type: string, description: Safe device label; never a device key or fingerprint.}
        ip_hint: {type: string, description: Server-masked IP hint.}
        status: {type: string, enum: [active, revoked, expired]}
        current: {type: boolean}
        last_seen_at: {type: string, format: date-time}
        expires_at: {type: string, format: date-time}
        revoked_at: {type: [string, "null"], format: date-time}
    AdminOnlineSessionPage:
      type: object
      additionalProperties: false
      required: [items, total, page, page_size]
      properties:
        items: {type: array, items: {$ref: "#/components/schemas/AdminOnlineSession"}}
        total: {type: integer, format: int64, minimum: 0}
        page: {type: integer, minimum: 1}
        page_size: {type: integer, minimum: 1, maximum: 100}
    AdminOnlineSessionListResponse:
      type: object
      additionalProperties: false
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data: {$ref: "#/components/schemas/AdminOnlineSessionPage"}
        request_id: {type: string}
    AdminOnlineSessionRevokeResult:
      type: object
      additionalProperties: false
      required: [id, revoked, current]
      properties:
        id: {type: string, format: uuid}
        revoked: {type: boolean, const: true}
        current: {type: boolean}
    AdminOnlineSessionRevokeResponse:
      type: object
      additionalProperties: false
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data: {$ref: "#/components/schemas/AdminOnlineSessionRevokeResult"}
        request_id: {type: string}
    AdminTenantStatus:
      type: string
      enum: [active, disabled]
    AdminTenant:
      type: object
      additionalProperties: false
      required: [id, code, name, status, plan_code, member_count, created_at, updated_at]
      properties:
        id: {type: string, format: uuid}
        code: {type: string, minLength: 2, maxLength: 64}
        name: {type: string, minLength: 1, maxLength: 120}
        status: {$ref: "#/components/schemas/AdminTenantStatus"}
        plan_code: {type: string}
        member_count: {type: integer, format: int64, minimum: 0}
        created_at: {type: string, format: date-time}
        updated_at: {type: string, format: date-time}
    AdminTenantCreateRequest:
      type: object
      additionalProperties: false
      required: [code, name]
      properties:
        code: {type: string, pattern: "^[a-z0-9][a-z0-9-]{1,63}$"}
        name: {type: string, minLength: 1, maxLength: 120}
    AdminTenantUpdateRequest:
      type: object
      additionalProperties: false
      required: [name, status]
      properties:
        name: {type: string, minLength: 1, maxLength: 120}
        status: {$ref: "#/components/schemas/AdminTenantStatus"}
    AdminTenantResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data: {$ref: "#/components/schemas/AdminTenant"}
        request_id: {type: string}
    AdminTenantListResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data:
          type: object
          additionalProperties: false
          required: [items, total, page, page_size]
          properties:
            items: {type: array, items: {$ref: "#/components/schemas/AdminTenant"}}
            total: {type: integer, format: int64, minimum: 0}
            page: {type: integer, minimum: 1}
            page_size: {type: integer, minimum: 1, maximum: 100}
        request_id: {type: string}
    AdminTenantMemberStatus:
      type: string
      enum: [active, suspended, left]
    AdminTenantMember:
      type: object
      additionalProperties: false
      required: [user_id, email, display_name, status, joined_at, role_codes]
      properties:
        user_id: {type: string, format: uuid}
        email: {type: string, format: email}
        display_name: {type: string}
        status: {$ref: "#/components/schemas/AdminTenantMemberStatus"}
        joined_at: {type: string, format: date-time}
        role_codes: {type: array, items: {type: string}}
    AdminTenantMemberAddRequest:
      type: object
      additionalProperties: false
      required: [email]
      properties:
        email: {type: string, format: email, maxLength: 320}
        display_name: {type: string, maxLength: 120, default: ""}
    AdminTenantMemberUpdateRequest:
      type: object
      additionalProperties: false
      required: [status]
      properties:
        status: {type: string, enum: [active, suspended]}
    AdminTenantMemberResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data: {$ref: "#/components/schemas/AdminTenantMember"}
        request_id: {type: string}
    AdminTenantMemberListResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data: {type: array, items: {$ref: "#/components/schemas/AdminTenantMember"}}
        request_id: {type: string}
    AdminUserStatus:
      type: string
      enum: [pending, active, disabled, locked]
    AdminUserReference:
      type: object
      additionalProperties: false
      required: [id, code, name]
      properties:
        id: {type: string, format: uuid}
        code: {type: string}
        name: {type: string}
    AdminUser:
      type: object
      additionalProperties: false
      required: [id, email, username, display_name, locale, time_zone, status, global_status, member_status, is_system, roles, units, positions, active_session_count, last_login_at, last_active_at, created_at, updated_at]
      properties:
        id: {type: string, format: uuid}
        email: {type: string, format: email}
        username: {type: string}
        display_name: {type: string, minLength: 1, maxLength: 120}
        locale: {$ref: "#/components/schemas/SupportedLocale"}
        time_zone: {type: string, minLength: 1, maxLength: 64}
        status: {$ref: "#/components/schemas/AdminUserStatus"}
        global_status: {type: string, enum: [pending, active, disabled, locked, deleted]}
        member_status: {type: string, enum: [invited, active, suspended, left]}
        is_system: {type: boolean}
        roles: {type: array, items: {$ref: "#/components/schemas/AdminUserReference"}}
        units: {type: array, items: {$ref: "#/components/schemas/AdminUserReference"}}
        positions: {type: array, items: {$ref: "#/components/schemas/AdminUserReference"}}
        active_session_count: {type: integer, format: int64, minimum: 0}
        last_login_at: {type: [string, "null"], format: date-time}
        last_active_at: {type: [string, "null"], format: date-time}
        created_at: {type: string, format: date-time}
        updated_at: {type: string, format: date-time}
    AdminUserCreateRequest:
      type: object
      additionalProperties: false
      required: [email, display_name, locale, time_zone, temporary_password]
      properties:
        email: {type: string, format: email, maxLength: 254}
        display_name: {type: string, minLength: 1, maxLength: 120}
        locale: {$ref: "#/components/schemas/SupportedLocale"}
        time_zone: {type: string, minLength: 1, maxLength: 64}
        temporary_password: {type: string, format: password, minLength: 12, maxLength: 256, writeOnly: true}
    AdminUserUpdateRequest:
      type: object
      additionalProperties: false
      required: [display_name, locale, time_zone]
      properties:
        display_name: {type: string, minLength: 1, maxLength: 120}
        locale: {$ref: "#/components/schemas/SupportedLocale"}
        time_zone: {type: string, minLength: 1, maxLength: 64}
    AdminUserResetPasswordRequest:
      type: object
      additionalProperties: false
      required: [temporary_password]
      properties:
        temporary_password: {type: string, format: password, minLength: 12, maxLength: 256, writeOnly: true}
    AdminUserRolesRequest:
      type: object
      additionalProperties: false
      required: [role_ids]
      properties:
        role_ids: {type: array, uniqueItems: true, maxItems: 100, items: {type: string, format: uuid}}
    AdminUserAssignmentsRequest:
      type: object
      additionalProperties: false
      required: [unit_ids, primary_unit_id, position_ids, primary_position_id]
      properties:
        unit_ids: {type: array, uniqueItems: true, maxItems: 100, items: {type: string, format: uuid}}
        primary_unit_id: {type: [string, "null"], format: uuid}
        position_ids: {type: array, uniqueItems: true, maxItems: 100, items: {type: string, format: uuid}}
        primary_position_id: {type: [string, "null"], format: uuid}
    AdminUserExportRequest:
      type: object
      additionalProperties: false
      properties:
        q: {type: string, maxLength: 254}
        status: {$ref: "#/components/schemas/AdminUserStatus"}
        unit_id: {type: [string, "null"], format: uuid}
        position_id: {type: [string, "null"], format: uuid}
        role_id: {type: [string, "null"], format: uuid}
        created_from: {type: [string, "null"], format: date-time}
        created_to: {type: [string, "null"], format: date-time}
        sort: {type: string, enum: [created_desc, created_asc, name_asc, last_login_desc]}
    AdminUserResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data: {$ref: "#/components/schemas/AdminUser"}
        request_id: {type: string}
    AdminUserRoleOptionsResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data:
          type: object
          required: [items]
          properties:
            items: {type: array, items: {$ref: "#/components/schemas/AdminUserReference"}}
        request_id: {type: string}
    AdminUserListResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data:
          type: object
          required: [items, total, page, page_size]
          properties:
            items: {type: array, items: {$ref: "#/components/schemas/AdminUser"}}
            total: {type: integer, format: int64, minimum: 0}
            page: {type: integer, minimum: 1}
            page_size: {type: integer, minimum: 1, maximum: 100}
        request_id: {type: string}
    AdminUserActionResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data: {type: object, additionalProperties: {type: boolean}}
        request_id: {type: string}
    AdminUserResetPasswordResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data:
          type: object
          additionalProperties: false
          required: [reset, sessions_revoked, force_password_change]
          properties:
            reset: {type: boolean, const: true}
            sessions_revoked: {type: integer, format: int64, minimum: 0}
            force_password_change: {type: boolean, const: true}
        request_id: {type: string}
    AdminUserSession:
      type: object
      additionalProperties: false
      required: [id, audience, status, ip_address, user_agent, last_seen_at, expires_at, revoked_at, current]
      properties:
        id: {type: string, format: uuid}
        audience: {type: string, enum: [ak-admin, ak-mobile, ak-api]}
        status: {type: string, enum: [active, revoked, expired]}
        ip_address: {type: string}
        user_agent: {type: string}
        last_seen_at: {type: string, format: date-time}
        expires_at: {type: string, format: date-time}
        revoked_at: {type: [string, "null"], format: date-time}
        current: {type: boolean}
    AdminUserSessionListResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data:
          type: object
          required: [items, total]
          properties:
            items: {type: array, items: {$ref: "#/components/schemas/AdminUserSession"}}
            total: {type: integer, minimum: 0}
        request_id: {type: string}
    AdminUserImportError:
      type: object
      additionalProperties: false
      required: [row, code]
      properties:
        row: {type: integer, minimum: 2}
        code: {type: string}
    AdminUserImportResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data:
          type: object
          required: [created, failed, errors]
          properties:
            created: {type: integer, minimum: 0}
            failed: {type: integer, minimum: 0}
            errors: {type: array, items: {$ref: "#/components/schemas/AdminUserImportError"}}
        request_id: {type: string}
    AdminLoginRequest:
      type: object
      additionalProperties: false
      required: [email, password]
      properties:
        email: {type: string, format: email, maxLength: 320}
        password: {type: string, minLength: 12, maxLength: 256, format: password}
        captcha_id: {type: string, format: uuid, description: Required only after the server returns IAM.AUTH.CAPTCHA_REQUIRED.}
        captcha_answer: {type: string, pattern: '^[2-9]{6}$', description: Required only after the server returns IAM.AUTH.CAPTCHA_REQUIRED.}
    AdminLoginCaptchaRequest:
      type: object
      additionalProperties: false
      required: [email]
      properties:
        email: {type: string, format: email, maxLength: 320}
    AdminLoginCaptchaResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data:
          type: object
          additionalProperties: false
          required: [captcha_id, image_base64, mime_type, expires_in_seconds]
          properties:
            captcha_id: {type: string, format: uuid}
            image_base64: {type: string, contentEncoding: base64, description: Base64-encoded PNG bytes. The answer is never returned as text or vector content.}
            mime_type: {type: string, const: image/png}
            expires_in_seconds: {type: integer, format: int64, minimum: 1, maximum: 300}
        request_id: {type: string}
    AdminRegistrationRequest:
      type: object
      additionalProperties: false
      required: [email, display_name, password, locale, accept_terms]
      properties:
        email: {type: string, format: email, maxLength: 254}
        display_name: {type: string, minLength: 2, maxLength: 120}
        password: {type: string, minLength: 12, maxLength: 256, format: password, writeOnly: true}
        locale: {$ref: "#/components/schemas/SupportedLocale"}
        accept_terms: {type: boolean, const: true}
    AdminRegistrationResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data:
          type: object
          required: [accepted]
          properties:
            accepted: {type: boolean, const: true}
        request_id: {type: string}
    AdminForgotPasswordRequest:
      type: object
      additionalProperties: false
      required: [email]
      properties:
        email: {type: string, format: email, maxLength: 254}
    AdminForgotPasswordResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data:
          type: object
          required: [accepted, retry_after_seconds]
          properties:
            accepted: {type: boolean, const: true}
            retry_after_seconds: {type: integer, minimum: 1}
        request_id: {type: string}
    AdminResetPasswordRequest:
      type: object
      additionalProperties: false
      required: [token, new_password]
      properties:
        token: {type: string, minLength: 32, maxLength: 512, writeOnly: true}
        new_password: {type: string, minLength: 12, maxLength: 256, format: password, writeOnly: true}
    AdminResetPasswordResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data:
          type: object
          required: [reset]
          properties:
            reset: {type: boolean, const: true}
        request_id: {type: string}
    AdminTokenData:
      type: object
      additionalProperties: false
      required: [access_token, token_type, expires_in, csrf_token]
      properties:
        access_token: {type: string}
        token_type: {type: string, const: Bearer}
        expires_in: {type: integer, format: int64, minimum: 0}
        csrf_token: {type: string, minLength: 32}
    AdminTokenResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data: {$ref: "#/components/schemas/AdminTokenData"}
        request_id: {type: string}
    AdminLogoutResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data:
          type: object
          required: [signed_out]
          properties:
            signed_out: {type: boolean, const: true}
        request_id: {type: string}
    AdminMe:
      type: object
      additionalProperties: false
      required: [id, email, display_name, locale, time_zone, avatar_url]
      properties:
        id: {type: string, format: uuid}
        email: {type: string, format: email}
        display_name: {type: string, minLength: 1, maxLength: 160}
        locale: {$ref: "#/components/schemas/SupportedLocale"}
        time_zone: {type: string, minLength: 1, maxLength: 64}
        avatar_url: {type: [string, "null"], description: Authenticated same-origin avatar content URL.}
    AdminMeResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data: {$ref: "#/components/schemas/AdminMe"}
        request_id: {type: string}
    AdminUpdateMeRequest:
      type: object
      additionalProperties: false
      minProperties: 1
      properties:
        display_name: {type: string, minLength: 1, maxLength: 160}
        locale: {$ref: "#/components/schemas/SupportedLocale"}
        time_zone: {type: string, minLength: 1, maxLength: 64, description: IANA time zone name.}
    AdminAvatarUploadRequest:
      type: object
      additionalProperties: false
      required: [file_name, media_type, size_bytes]
      properties:
        file_name: {type: string, minLength: 1, maxLength: 240}
        media_type: {type: string, enum: [image/jpeg, image/png, image/webp]}
        size_bytes: {type: integer, format: int64, minimum: 1, maximum: 5242880}
    AdminAvatarUploadSession:
      type: object
      additionalProperties: false
      required: [id, upload_url, method, expires_at]
      properties:
        id: {type: string, format: uuid}
        upload_url: {type: string}
        method: {type: string, const: PUT}
        expires_at: {type: string, format: date-time}
    AdminAvatarUploadSessionResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data: {$ref: "#/components/schemas/AdminAvatarUploadSession"}
        request_id: {type: string}
    AdminAvatarUploadCompleteResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data:
          type: object
          required: [file_id, avatar_url]
          properties:
            file_id: {type: string, format: uuid}
            avatar_url: {type: string}
        request_id: {type: string}
    AdminSelfSession:
      type: object
      additionalProperties: false
      required: [id, audience, status, ip_address, user_agent, last_seen_at, absolute_expires_at, created_at, current]
      properties:
        id: {type: string, format: uuid}
        audience: {type: string, const: ak-admin}
        status: {type: string, const: active}
        ip_address: {type: [string, "null"], format: ip}
        user_agent: {type: string}
        last_seen_at: {type: string, format: date-time}
        absolute_expires_at: {type: string, format: date-time}
        created_at: {type: string, format: date-time}
        current: {type: boolean}
    AdminSelfSessionListResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data:
          type: array
          items: {$ref: "#/components/schemas/AdminSelfSession"}
        request_id: {type: string}
    AdminSelfSessionRevokeResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data:
          type: object
          additionalProperties: false
          required: [revoked, current_session]
          properties:
            revoked: {type: boolean, const: true}
            current_session: {type: boolean}
        request_id: {type: string}
    AdminSelfDevice:
      type: object
      additionalProperties: false
      required: [id, platform, device_name, model, os_version, app_version, last_ip, last_seen_at, created_at, latest_user_agent, active_session_count, current]
      properties:
        id: {type: string, format: uuid}
        platform: {type: string, enum: [web]}
        device_name: {type: string}
        model: {type: string}
        os_version: {type: string}
        app_version: {type: string}
        last_ip: {type: [string, "null"], format: ip}
        last_seen_at: {type: [string, "null"], format: date-time}
        created_at: {type: string, format: date-time}
        latest_user_agent: {type: string}
        active_session_count: {type: integer, format: int64, minimum: 0}
        current: {type: boolean}
    AdminSelfDeviceListResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data:
          type: array
          items: {$ref: "#/components/schemas/AdminSelfDevice"}
        request_id: {type: string}
    AdminSelfDeviceRemoveResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data:
          type: object
          additionalProperties: false
          required: [removed, current_device]
          properties:
            removed: {type: boolean, const: true}
            current_device: {type: boolean}
        request_id: {type: string}
    AdminSelfPasswordChangeRequest:
      type: object
      additionalProperties: false
      required: [current_password, new_password]
      properties:
        current_password: {type: string, minLength: 12, maxLength: 256, format: password}
        new_password: {type: string, minLength: 12, maxLength: 256, format: password}
    AdminSelfPasswordChangeResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data:
          type: object
          additionalProperties: false
          required: [changed, other_sessions_revoked]
          properties:
            changed: {type: boolean, const: true}
            other_sessions_revoked: {type: boolean, const: true}
        request_id: {type: string}
    AdminMfaStatus:
      type: object
      additionalProperties: false
      required: [totp_enabled, recovery_codes_remaining]
      properties:
        totp_enabled: {type: boolean}
        totp_verified_at: {type: [string, "null"], format: date-time}
        recovery_codes_remaining: {type: integer, format: int64, minimum: 0}
    AdminMfaStatusResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data: {$ref: "#/components/schemas/AdminMfaStatus"}
        request_id: {type: string}
    AdminTotpEnrollment:
      type: object
      additionalProperties: false
      required: [secret, otpauth_uri, expires_at]
      properties:
        secret: {type: string, minLength: 32, maxLength: 64, readOnly: true, description: One-time Base32 TOTP secret.}
        otpauth_uri: {type: string, pattern: "^otpauth://totp/", readOnly: true, description: One-time authenticator enrollment URI.}
        expires_at: {type: string, format: date-time}
    AdminTotpEnrollmentResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data: {$ref: "#/components/schemas/AdminTotpEnrollment"}
        request_id: {type: string}
    AdminTotpVerifyRequest:
      type: object
      additionalProperties: false
      required: [code]
      properties:
        code: {type: string, pattern: "^[0-9]{6}$", writeOnly: true}
    AdminStepUpRequest:
      type: object
      additionalProperties: false
      required: [method, proof]
      properties:
        method: {type: string, enum: [password, totp]}
        proof: {type: string, minLength: 6, maxLength: 256, writeOnly: true}
    AdminRecoveryCodes:
      type: object
      additionalProperties: false
      required: [codes]
      properties:
        codes:
          type: array
          minItems: 10
          maxItems: 10
          readOnly: true
          items: {type: string, pattern: "^[A-Z2-7]{6}-[A-Z2-7]{6}$"}
    AdminRecoveryCodesResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data: {$ref: "#/components/schemas/AdminRecoveryCodes"}
        request_id: {type: string}
    AdminMfaDisableResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data:
          type: object
          additionalProperties: false
          required: [disabled]
          properties: {disabled: {type: boolean, const: true}}
        request_id: {type: string}
    AdminOAuthAccount:
      type: object
      additionalProperties: false
      required: [id, provider, account_hint, status, bound_at]
      properties:
        id: {type: string, format: uuid}
        provider: {type: string}
        account_hint: {type: string, description: "Server-generated safe hint; never the provider subject or token."}
        status: {type: string, enum: [active, disabled]}
        bound_at: {type: string, format: date-time}
    AdminOAuthAccountListResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data:
          type: object
          required: [items]
          properties: {items: {type: array, items: {$ref: "#/components/schemas/AdminOAuthAccount"}}}
        request_id: {type: string}
    AdminOAuthStart:
      type: object
      additionalProperties: false
      required: [authorization_url, expires_at]
      properties:
        authorization_url: {type: string, format: uri}
        expires_at: {type: string, format: date-time}
    AdminOAuthStartResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data: {$ref: "#/components/schemas/AdminOAuthStart"}
        request_id: {type: string}
    AdminOAuthCallbackRequest:
      type: object
      additionalProperties: false
      required: [code, state]
      properties:
        code: {type: string, minLength: 32, maxLength: 256, writeOnly: true}
        state: {type: string, minLength: 32, maxLength: 256, writeOnly: true}
    AdminOAuthAccountResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data: {$ref: "#/components/schemas/AdminOAuthAccount"}
        request_id: {type: string}
    AdminOAuthUnbindResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data:
          type: object
          additionalProperties: false
          required: [unbound]
          properties: {unbound: {type: boolean, const: true}}
        request_id: {type: string}
    AdminDashboardWindow:
      type: object
      required: [range, start_at, end_at]
      properties:
        range: {type: string, enum: [7d, 30d, 90d]}
        start_at: {type: string, format: date-time}
        end_at: {type: string, format: date-time}
    AdminDashboardMetric:
      type: object
      additionalProperties: false
      required: [key, value]
      properties:
        key:
          type: string
          enum: [users.total, users.new, sessions.active, jobs.failed, security.open, messages.published]
        value: {type: integer, format: int64, minimum: 0}
    AdminDashboardSummaryResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data:
          allOf:
            - $ref: "#/components/schemas/AdminDashboardWindow"
            - type: object
              required: [metrics]
              properties:
                metrics:
                  type: array
                  items: {$ref: "#/components/schemas/AdminDashboardMetric"}
        request_id: {type: string}
    AdminDashboardTrendPoint:
      type: object
      additionalProperties: false
      required: [day, value]
      properties:
        day: {type: string, format: date}
        value: {type: integer, format: int64, minimum: 0}
    AdminDashboardTrendSeries:
      type: object
      additionalProperties: false
      required: [key, points]
      properties:
        key:
          type: string
          enum: [logins.success, logins.failure, users.new, jobs.failed, security.events]
        points:
          type: array
          items: {$ref: "#/components/schemas/AdminDashboardTrendPoint"}
    AdminDashboardTrendsResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data:
          allOf:
            - $ref: "#/components/schemas/AdminDashboardWindow"
            - type: object
              required: [series]
              properties:
                series:
                  type: array
                  items: {$ref: "#/components/schemas/AdminDashboardTrendSeries"}
        request_id: {type: string}
    AdminDashboardOperationActivity:
      type: object
      additionalProperties: false
      required: [id, module_code, action_name, resource_type, succeeded, error_code, occurred_at]
      properties:
        id: {type: string, format: uuid}
        module_code: {type: string}
        action_name: {type: string}
        resource_type: {type: string}
        succeeded: {type: boolean}
        error_code: {type: string}
        occurred_at: {type: string, format: date-time}
    AdminDashboardFailedJobActivity:
      type: object
      additionalProperties: false
      required: [id, schedule_code, schedule_name, error_code, occurred_at]
      properties:
        id: {type: string, format: uuid}
        schedule_code: {type: string}
        schedule_name: {type: string}
        error_code: {type: string}
        occurred_at: {type: string, format: date-time}
    AdminDashboardSecurityActivity:
      type: object
      additionalProperties: false
      required: [id, event_type, severity, source, occurred_at]
      properties:
        id: {type: string, format: uuid}
        event_type: {type: string}
        severity: {type: string, enum: [info, low, medium, high, critical]}
        source: {type: string}
        occurred_at: {type: string, format: date-time}
    AdminDashboardActivityResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data:
          allOf:
            - $ref: "#/components/schemas/AdminDashboardWindow"
            - type: object
              required: [operations, failed_jobs, security_events]
              properties:
                operations:
                  type: array
                  items: {$ref: "#/components/schemas/AdminDashboardOperationActivity"}
                failed_jobs:
                  type: array
                  items: {$ref: "#/components/schemas/AdminDashboardFailedJobActivity"}
                security_events:
                  type: array
                  items: {$ref: "#/components/schemas/AdminDashboardSecurityActivity"}
        request_id: {type: string}
    AdminAuthContextResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data:
          type: object
          required: [user, active_tenant, available_tenants, roles, permissions, menus, feature_flags, menu_revision, permission_revision, server_time]
          properties:
            user:
              type: object
              required: [id, email, display_name, locale, time_zone, avatar_url]
              properties:
                id: {type: string, format: uuid}
                email: {type: string, format: email}
                display_name: {type: string}
                locale: {$ref: "#/components/schemas/SupportedLocale"}
                time_zone: {type: string}
                avatar_url: {type: [string, "null"]}
            active_tenant:
              type: object
              required: [id, code, name]
              properties:
                id: {type: string, format: uuid}
                code: {type: string}
                name: {type: string}
            available_tenants:
              type: array
              items:
                type: object
                additionalProperties: false
                required: [id, code, name, status]
                properties:
                  id: {type: string, format: uuid}
                  code: {type: string}
                  name: {type: string}
                  status: {type: string, const: active}
            roles:
              type: array
              items: {type: string}
            permissions:
              type: array
              items: {type: string}
            menus:
              type: array
              items: {$ref: "#/components/schemas/AdminMenuItem"}
            feature_flags:
              type: object
              additionalProperties: {type: boolean}
            menu_revision: {type: integer, minimum: 0}
            permission_revision: {type: integer, minimum: 0}
            server_time: {type: string, format: date-time}
        request_id: {type: string}
    AdminMenuItem:
      type: object
      required: [id, parent_id, code, i18n_key, title, type, path, component_key, icon, affix, sort, feature_flag]
      properties:
        id: {type: string, format: uuid}
        parent_id: {type: [string, "null"], format: uuid}
        code: {type: string}
        i18n_key: {type: string}
        title: {type: string, description: Diagnostic fallback only; clients render i18n_key.}
        type: {type: string, enum: [directory, page, external]}
        path: {type: [string, "null"]}
        component_key: {type: [string, "null"]}
        icon: {type: [string, "null"]}
        affix: {type: boolean}
        sort: {type: integer, format: int32}
        feature_flag: {type: string}
    Region:
      type: object
      additionalProperties: false
      required: [code, parent_code, level, name, full_name, postal_code, longitude, latitude, status, has_children, version, updated_at]
      properties:
        code: {type: string, maxLength: 32}
        parent_code: {type: [string, "null"], maxLength: 32}
        level: {type: integer, minimum: 0, maximum: 10}
        name: {type: string, maxLength: 160}
        full_name: {type: string, maxLength: 500}
        postal_code: {type: string, maxLength: 24}
        longitude: {type: [number, "null"]}
        latitude: {type: [number, "null"]}
        status: {type: string, enum: [active, disabled]}
        has_children: {type: boolean}
        version: {type: integer, format: int32, minimum: 1}
        updated_at: {type: string, format: date-time}
    AdminRegionCreateRequest:
      type: object
      additionalProperties: false
      required: [code, parent_code, name, full_name, postal_code, longitude, latitude, status]
      properties:
        code: {type: string, pattern: "^[A-Za-z0-9][A-Za-z0-9._-]{0,31}$"}
        parent_code: {type: string, pattern: "^[A-Za-z0-9][A-Za-z0-9._-]{0,31}$"}
        name: {type: string, minLength: 1, maxLength: 160}
        full_name: {type: string, minLength: 1, maxLength: 500}
        postal_code: {type: string, maxLength: 24}
        longitude: {type: [number, "null"], minimum: -180, maximum: 180}
        latitude: {type: [number, "null"], minimum: -90, maximum: 90}
        status: {type: string, enum: [active, disabled]}
    AdminRegionUpdateRequest:
      type: object
      additionalProperties: false
      required: [name, full_name, postal_code, longitude, latitude, status, version]
      properties:
        name: {type: string, minLength: 1, maxLength: 160}
        full_name: {type: string, minLength: 1, maxLength: 500}
        postal_code: {type: string, maxLength: 24}
        longitude: {type: [number, "null"], minimum: -180, maximum: 180}
        latitude: {type: [number, "null"], minimum: -90, maximum: 90}
        status: {type: string, enum: [active, disabled]}
        version: {type: integer, format: int32, minimum: 1}
    AdminRegionResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string, const: OK}, message: {type: string}, data: {$ref: "#/components/schemas/Region"}, request_id: {type: string}}
    RegionListResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data:
          type: object
          required: [items]
          properties: {items: {type: array, items: {$ref: "#/components/schemas/Region"}}}
        request_id: {type: string}
    AdminFileUploadRequest:
      type: object
      additionalProperties: false
      required: [file_name, media_type, size_bytes]
      properties: {file_name: {type: string, minLength: 1, maxLength: 1000}, media_type: {type: string, minLength: 1, maxLength: 255}, size_bytes: {type: integer, format: int64, minimum: 1, maximum: 104857600}}
    AdminFilePart:
      type: object
      additionalProperties: false
      required: [part_number, size_bytes, etag]
      properties: {part_number: {type: integer, format: int32, minimum: 1}, size_bytes: {type: integer, format: int64, minimum: 1}, etag: {type: string}}
    AdminFileUploadSession:
      type: object
      additionalProperties: false
      required: [id, original_name, media_type, expected_size, part_size, status, provider, expires_at, uploaded_parts]
      properties: {id: {type: string, format: uuid}, original_name: {type: string}, media_type: {type: string}, expected_size: {type: integer, format: int64}, part_size: {type: integer, format: int64}, status: {type: string, enum: [initiated, uploading]}, provider: {type: string, x-appkernia-dictionary: storage.driver}, expires_at: {type: string, format: date-time}, uploaded_parts: {type: array, items: {$ref: "#/components/schemas/AdminFilePart"}}}
    AdminFileUploadPolicy:
      type: object
      additionalProperties: false
      required: [provider, max_image_bytes, max_file_bytes, image_media_types, file_media_types, configuration_safe]
      properties: {provider: {type: string, x-appkernia-dictionary: storage.driver}, max_image_bytes: {type: integer, format: int64, minimum: 1, maximum: 5242880}, max_file_bytes: {type: integer, format: int64, minimum: 1, maximum: 104857600}, image_media_types: {type: array, items: {type: string}}, file_media_types: {type: array, items: {type: string}}, configuration_safe: {type: boolean}}
    AdminFile:
      type: object
      additionalProperties: false
      required: [id, original_name, media_type, extension, size_bytes, provider, status, scan_status, usage_count, created_at, updated_at]
      properties: {id: {type: string, format: uuid}, original_name: {type: string}, media_type: {type: string}, extension: {type: string}, size_bytes: {type: integer, format: int64}, provider: {type: string, x-appkernia-dictionary: storage.driver}, status: {type: string, enum: [pending, ready, quarantined]}, scan_status: {type: string, enum: [pending, clean, infected, failed, skipped]}, usage_count: {type: integer, format: int64, minimum: 0}, owner_user_id: {type: [string, "null"], format: uuid}, created_at: {type: string, format: date-time}, updated_at: {type: string, format: date-time}}
    AdminFileUsage:
      type: object
      additionalProperties: false
      required: [id, module_code, entity_type, entity_id, field_name, created_at]
      properties: {id: {type: string, format: uuid}, module_code: {type: string}, entity_type: {type: string}, entity_id: {type: string, format: uuid}, field_name: {type: string}, created_at: {type: string, format: date-time}}
    AdminFilePage:
      type: object
      required: [items, page, page_size, total]
      properties: {items: {type: array, items: {$ref: "#/components/schemas/AdminFile"}}, page: {type: integer}, page_size: {type: integer}, total: {type: integer, format: int64}}
    AdminFileResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/AdminFile"}, request_id: {type: string}}
    AdminFileListResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/AdminFilePage"}, request_id: {type: string}}
    AdminFileUploadSessionResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/AdminFileUploadSession"}, request_id: {type: string}}
    AdminFileUploadPolicyResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/AdminFileUploadPolicy"}, request_id: {type: string}}
    AdminFilePartResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/AdminFilePart"}, request_id: {type: string}}
    AdminFileUsageListResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {type: object, required: [items], properties: {items: {type: array, items: {$ref: "#/components/schemas/AdminFileUsage"}}}}, request_id: {type: string}}
    AdminFileDownloadResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {type: object, required: [file_id, method, download_url, expires_at], properties: {file_id: {type: string, format: uuid}, method: {type: string, const: GET}, download_url: {type: string}, expires_at: {type: string, format: date-time}}}, request_id: {type: string}}
    AdminNotificationMessage:
      type: object
      additionalProperties: false
      required: [id, app_id, message_type, title, body, body_format, status, audience_scope, audience_user_ids, created_at, updated_at]
      properties:
        id: {type: string, format: uuid}
        app_id: {type: string, format: uuid}
        message_type: {type: string, enum: [system, notice, private, marketing, security]}
        title: {type: string, minLength: 1, maxLength: 300}
        body: {type: string, description: HTML bodies have already passed the server allowlist sanitizer. Plain and Markdown bodies are untrusted text and must not be inserted as raw HTML.}
        body_format: {type: string, enum: [plain, markdown, html]}
        status: {type: string, enum: [draft, scheduled, published, cancelled]}
        audience_scope: {type: string, enum: [all, selected]}
        audience_user_ids: {type: array, maxItems: 500, uniqueItems: true, items: {type: string, format: uuid}}
        scheduled_at: {type: [string, "null"], format: date-time}
        published_at: {type: [string, "null"], format: date-time}
        expires_at: {type: [string, "null"], format: date-time}
        created_at: {type: string, format: date-time}
        updated_at: {type: string, format: date-time}
    AdminNotificationMessageRequest:
      type: object
      additionalProperties: false
      required: [message_type, title, body, body_format, audience_scope, audience_user_ids]
      properties:
        message_type: {type: string, enum: [system, notice, private, marketing, security]}
        title: {type: string, minLength: 1, maxLength: 300}
        body: {type: string, minLength: 1, maxLength: 100000}
        body_format: {type: string, enum: [plain, markdown, html]}
        audience_scope: {type: string, enum: [all, selected]}
        audience_user_ids: {type: array, maxItems: 500, uniqueItems: true, items: {type: string, format: uuid}}
        scheduled_at: {type: [string, "null"], format: date-time}
        expires_at: {type: [string, "null"], format: date-time}
    AdminNotificationRecipient:
      type: object
      additionalProperties: false
      required: [user_id, display_name, email_hint]
      properties: {user_id: {type: string, format: uuid}, display_name: {type: string}, email_hint: {type: string, description: Server-masked email hint only.}}
    AdminNotificationRecipientPreview:
      type: object
      additionalProperties: false
      required: [count, items]
      properties: {count: {type: integer, format: int64, minimum: 1}, items: {type: array, maxItems: 20, items: {$ref: "#/components/schemas/AdminNotificationRecipient"}}}
    AdminNotificationRecipientStats:
      type: object
      additionalProperties: false
      required: [total, pending, delivered, failed, read]
      properties: {total: {type: integer, format: int64, minimum: 0}, pending: {type: integer, format: int64, minimum: 0}, delivered: {type: integer, format: int64, minimum: 0}, failed: {type: integer, format: int64, minimum: 0}, read: {type: integer, format: int64, minimum: 0}}
    AdminNotificationMessagePage:
      type: object
      additionalProperties: false
      required: [items, page, page_size, total]
      properties: {items: {type: array, items: {$ref: "#/components/schemas/AdminNotificationMessage"}}, page: {type: integer, minimum: 1}, page_size: {type: integer, minimum: 1, maximum: 100}, total: {type: integer, format: int64, minimum: 0}}
    AdminNotificationMessageResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string, const: OK}, message: {type: string}, data: {$ref: "#/components/schemas/AdminNotificationMessage"}, request_id: {type: string}}
    AdminNotificationMessageListResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string, const: OK}, message: {type: string}, data: {$ref: "#/components/schemas/AdminNotificationMessagePage"}, request_id: {type: string}}
    AdminNotificationRecipientPreviewResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string, const: OK}, message: {type: string}, data: {$ref: "#/components/schemas/AdminNotificationRecipientPreview"}, request_id: {type: string}}
    AdminNotificationRecipientStatsResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string, const: OK}, message: {type: string}, data: {$ref: "#/components/schemas/AdminNotificationRecipientStats"}, request_id: {type: string}}
    AdminNotificationPublishResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string, const: OK}
        message: {type: string}
        data:
          type: object
          additionalProperties: false
          required: [message, recipients]
          properties: {message: {$ref: "#/components/schemas/AdminNotificationMessage"}, recipients: {$ref: "#/components/schemas/AdminNotificationRecipientPreview"}}
        request_id: {type: string}
    AdminNotificationTemplateChannel:
      type: string
      enum: [in_app, email, sms, push, webhook]
    AdminNotificationTemplate:
      type: object
      additionalProperties: false
      required: [id, tenant_id, code, name, channel, locale, subject_template, body_template, body_format, variables_schema, status, is_locked, created_at, updated_at]
      properties:
        id: {type: string, format: uuid}
        tenant_id: {type: [string, "null"], format: uuid}
        code: {type: string}
        name: {type: string}
        channel: {$ref: "#/components/schemas/AdminNotificationTemplateChannel"}
        locale: {type: [string, "null"], enum: [zh-CN, en-US, null]}
        subject_template: {type: [string, "null"]}
        body_template: {type: string}
        body_format: {type: string, enum: [plain, html]}
        variables_schema: {type: object, additionalProperties: true, description: JSON Schema object declaring every double-brace template variable.}
        status: {type: string, enum: [active, disabled]}
        is_locked: {type: boolean}
        created_at: {type: string, format: date-time}
        updated_at: {type: string, format: date-time}
    AdminNotificationTemplateRequest:
      type: object
      additionalProperties: false
      required: [code, name, channel, locale, subject_template, body_template, body_format, variables_schema, status]
      properties:
        code: {type: string, pattern: "^[a-z][a-z0-9_.-]{1,95}$"}
        name: {type: string, minLength: 1, maxLength: 160}
        channel: {$ref: "#/components/schemas/AdminNotificationTemplateChannel"}
        locale: {type: [string, "null"], enum: [zh-CN, en-US, null]}
        subject_template: {type: [string, "null"], maxLength: 500}
        body_template: {type: string, minLength: 1, maxLength: 100000}
        body_format: {type: string, enum: [plain, html]}
        variables_schema: {type: object, additionalProperties: true}
        status: {type: string, enum: [active, disabled]}
    AdminNotificationTemplatePage:
      type: object
      additionalProperties: false
      required: [items, page, page_size, total]
      properties: {items: {type: array, items: {$ref: "#/components/schemas/AdminNotificationTemplate"}}, page: {type: integer, minimum: 1}, page_size: {type: integer, minimum: 1, maximum: 100}, total: {type: integer, format: int64, minimum: 0}}
    AdminNotificationTemplateResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string, const: OK}, message: {type: string}, data: {$ref: "#/components/schemas/AdminNotificationTemplate"}, request_id: {type: string}}
    AdminNotificationTemplateListResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string, const: OK}, message: {type: string}, data: {$ref: "#/components/schemas/AdminNotificationTemplatePage"}, request_id: {type: string}}
    AdminSMSTemplateBinding:
      type: object
      additionalProperties: false
      required: [id, template_id, provider, external_template_id, sign_name, parameter_order, status, version, created_at, updated_at]
      properties: {id: {type: string, format: uuid}, template_id: {type: string, format: uuid}, provider: {type: string, enum: [tencent, aliyun]}, external_template_id: {type: string}, sign_name: {type: string}, parameter_order: {type: array, items: {type: string}}, status: {type: string, enum: [active, disabled]}, version: {type: integer, format: int32, minimum: 1}, created_at: {type: string, format: date-time}, updated_at: {type: string, format: date-time}}
    AdminSMSTemplateBindingRequest:
      type: object
      additionalProperties: false
      required: [external_template_id, sign_name, parameter_order, status, version]
      properties: {external_template_id: {type: string, minLength: 1, maxLength: 255}, sign_name: {type: string, maxLength: 120}, parameter_order: {type: array, maxItems: 50, uniqueItems: true, items: {type: string, pattern: "^[a-zA-Z][a-zA-Z0-9_.-]{0,63}$"}}, status: {type: string, enum: [active, disabled]}, version: {type: integer, format: int32, minimum: 1}}
    AdminSMSTemplateBindingResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string, const: OK}, message: {type: string}, data: {$ref: "#/components/schemas/AdminSMSTemplateBinding"}, request_id: {type: string}}
    AdminSMSTemplateBindingListResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string, const: OK}, message: {type: string}, data: {type: array, items: {$ref: "#/components/schemas/AdminSMSTemplateBinding"}}, request_id: {type: string}}
    AdminNotificationTemplateTestRequest:
      type: object
      additionalProperties: false
      required: [target, provider, variables, confirm_billable]
      properties: {target: {type: string, minLength: 3, maxLength: 320}, provider: {type: string, enum: [smtp, tencent, aliyun]}, variables: {type: object, maxProperties: 100, additionalProperties: {type: string}}, confirm_billable: {type: boolean, description: Must be true for SMS because a real provider request can incur charges.}}
    AdminNotificationRetryRequest:
      type: object
      additionalProperties: false
      properties: {acknowledge_duplicate_risk: {type: boolean, default: false, description: Required when retry_risk is duplicate_possible or manual_review.}}
    AdminNotificationDelivery:
      type: object
      additionalProperties: false
      required: [id, channel, target_hint, provider, status, attempt_count, max_attempts, scheduled_at, error_code, error_summary, retryable, retry_risk, created_at, updated_at]
      properties:
        id: {type: string, format: uuid}
        message_id: {type: [string, "null"], format: uuid}
        user_id: {type: [string, "null"], format: uuid}
        template_id: {type: [string, "null"], format: uuid}
        channel: {type: string, enum: [email, sms, push, webhook]}
        target_hint: {type: string, description: Safe server-generated hint; ciphertext and hash are never returned.}
        provider: {type: string}
        provider_message_id: {type: string, description: Safe provider receipt identifier when available.}
        status: {type: string, enum: [pending, processing, sent, failed, cancelled]}
        attempt_count: {type: integer, format: int32, minimum: 0}
        max_attempts: {type: integer, format: int32, minimum: 1}
        scheduled_at: {type: string, format: date-time}
        next_attempt_at: {type: [string, "null"], format: date-time}
        sent_at: {type: [string, "null"], format: date-time}
        error_code: {type: string, description: Stable safe error category; never a provider payload.}
        error_summary: {type: string, maxLength: 500, description: Bounded control-character-free recovery summary.}
        retryable: {type: boolean, description: True only for explicit transient provider rejection below the attempt limit.}
        retry_risk: {type: string, enum: [none, duplicate_possible, manual_review]}
        created_at: {type: string, format: date-time}
        updated_at: {type: string, format: date-time}
    AdminNotificationDeliveryPage:
      type: object
      additionalProperties: false
      required: [items, page, page_size, total]
      properties: {items: {type: array, items: {$ref: "#/components/schemas/AdminNotificationDelivery"}}, page: {type: integer, minimum: 1}, page_size: {type: integer, minimum: 1, maximum: 100}, total: {type: integer, format: int64, minimum: 0}}
    AdminNotificationDeliveryResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string, const: OK}, message: {type: string}, data: {$ref: "#/components/schemas/AdminNotificationDelivery"}, request_id: {type: string}}
    AdminNotificationDeliveryListResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string, const: OK}, message: {type: string}, data: {$ref: "#/components/schemas/AdminNotificationDeliveryPage"}, request_id: {type: string}}
    AdminJobHandler:
      type: object
      additionalProperties: false
      required: [key, name_key, description_key, payload_schema, default_queue]
      properties:
        key: {type: string, pattern: "^[a-z][a-z0-9_.-]{0,159}$"}
        name_key: {type: string}
        description_key: {type: string}
        payload_schema: {type: object, additionalProperties: true}
        default_queue: {type: string}
    AdminJobScheduleRequest:
      type: object
      additionalProperties: false
      required: [code, name, handler_key, cron_expression, time_zone, payload, queue_name, overlap_policy, misfire_policy, timeout_seconds, max_attempts]
      properties:
        code: {type: string, pattern: "^[a-z][a-z0-9_.-]{0,95}$"}
        name: {type: string, minLength: 1, maxLength: 160}
        handler_key: {type: string, description: Must match the compile-time catalog returned by GET /job-handlers.}
        cron_expression: {type: string, maxLength: 128, description: Five-field minute hour day-of-month month day-of-week Cron expression.}
        time_zone: {type: string, maxLength: 64, description: IANA time zone name such as UTC or Asia/Shanghai.}
        payload: {type: object, additionalProperties: true, description: Data validated against the selected handler payload_schema; never executable code.}
        queue_name: {type: string, enum: [default]}
        overlap_policy: {type: string, enum: [allow, skip, replace]}
        misfire_policy: {type: string, enum: [ignore, fire_once, catch_up]}
        timeout_seconds: {type: integer, format: int32, minimum: 1, maximum: 86400}
        max_attempts: {type: integer, format: int32, minimum: 1, maximum: 100}
    AdminJobSchedule:
      allOf:
        - {$ref: "#/components/schemas/AdminJobScheduleRequest"}
        - type: object
          required: [id, status, created_at, updated_at]
          properties:
            id: {type: string, format: uuid}
            status: {type: string, enum: [active, paused, disabled]}
            last_enqueued_at: {type: [string, "null"], format: date-time}
            next_run_at: {type: [string, "null"], format: date-time}
            created_at: {type: string, format: date-time}
            updated_at: {type: string, format: date-time}
    AdminJobSchedulePage:
      type: object
      additionalProperties: false
      required: [items, page, page_size, total]
      properties: {items: {type: array, items: {$ref: "#/components/schemas/AdminJobSchedule"}}, page: {type: integer, minimum: 1}, page_size: {type: integer, minimum: 1, maximum: 100}, total: {type: integer, format: int64, minimum: 0}}
    AdminJobCronPreview:
      type: object
      additionalProperties: false
      required: [cron_expression, time_zone, next_runs]
      properties: {cron_expression: {type: string}, time_zone: {type: string}, next_runs: {type: array, minItems: 5, maxItems: 5, items: {type: string, format: date-time}}}
    AdminJobRun:
      type: object
      additionalProperties: false
      required: [id, schedule_id, trigger_type, status, attempt, scheduled_at, created_at]
      properties:
        id: {type: string, format: uuid}
        schedule_id: {type: string, format: uuid}
        river_job_id: {type: [integer, "null"], format: int64}
        trigger_type: {type: string, enum: [schedule, manual, retry]}
        status: {type: string, enum: [queued, running, succeeded, failed, cancelled, skipped]}
        attempt: {type: integer, format: int32, minimum: 0}
        scheduled_at: {type: string, format: date-time}
        started_at: {type: [string, "null"], format: date-time}
        finished_at: {type: [string, "null"], format: date-time}
        worker_id: {type: string, description: Safe logical worker identifier only.}
        output: {type: [object, "null"], additionalProperties: true, description: Bounded output emitted by a compile-time handler; never raw logs.}
        error_code: {type: string, description: Stable safe error code.}
        error_summary: {type: string, maxLength: 500, description: Bounded and server-redacted summary; raw River errors are not exposed.}
        created_at: {type: string, format: date-time}
    AdminJobRunPage:
      type: object
      additionalProperties: false
      required: [items, page, page_size, total]
      properties: {items: {type: array, items: {$ref: "#/components/schemas/AdminJobRun"}}, page: {type: integer, minimum: 1}, page_size: {type: integer, minimum: 1, maximum: 100}, total: {type: integer, format: int64, minimum: 0}}
    AdminJobHandlerListResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string, const: OK}, message: {type: string}, data: {type: array, items: {$ref: "#/components/schemas/AdminJobHandler"}}, request_id: {type: string}}
    AdminJobCronPreviewResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string, const: OK}, message: {type: string}, data: {$ref: "#/components/schemas/AdminJobCronPreview"}, request_id: {type: string}}
    AdminJobScheduleResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string, const: OK}, message: {type: string}, data: {$ref: "#/components/schemas/AdminJobSchedule"}, request_id: {type: string}}
    AdminJobScheduleListResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string, const: OK}, message: {type: string}, data: {$ref: "#/components/schemas/AdminJobSchedulePage"}, request_id: {type: string}}
    AdminJobRunResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string, const: OK}, message: {type: string}, data: {$ref: "#/components/schemas/AdminJobRun"}, request_id: {type: string}}
    AdminJobRunListResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string, const: OK}, message: {type: string}, data: {$ref: "#/components/schemas/AdminJobRunPage"}, request_id: {type: string}}
    AdminBooleanResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {type: object, additionalProperties: {type: boolean}}, request_id: {type: string}}
    AdminConfigItem:
      type: object
      required: [id, tenant_id, module_code, config_group, config_key, display_name, value_type, value, default_value, is_secret, secret_configured, secret_key_version, is_public, validation_schema, description, sort_order, status, version, is_locked, created_at, updated_at]
      properties:
        id: {type: string, format: uuid}
        tenant_id: {type: [string, "null"], format: uuid}
        module_code: {type: string}
        config_group: {type: string}
        config_key: {type: string}
        display_name: {type: string}
        value_type: {type: string, enum: [string, integer, decimal, boolean, json, datetime]}
        value: {}
        default_value: {}
        is_secret: {type: boolean}
        secret_configured: {type: boolean}
        secret_key_version: {type: [integer, "null"], format: int32}
        is_public: {type: boolean}
        validation_schema: {type: object, additionalProperties: true}
        description: {type: string}
        sort_order: {type: integer, format: int32}
        status: {type: string, enum: [active, disabled]}
        version: {type: integer, format: int32, minimum: 1}
        is_locked: {type: boolean}
        created_at: {type: string, format: date-time}
        updated_at: {type: string, format: date-time}
    AdminConfigWriteRequest:
      type: object
      additionalProperties: false
      required: [module_code, config_group, config_key, display_name, value_type, is_secret, is_public, validation_schema, description, sort_order, status, version]
      properties:
        module_code: {type: string, maxLength: 64}
        config_group: {type: string, maxLength: 96}
        config_key: {type: string, maxLength: 160}
        display_name: {type: string, maxLength: 160}
        value_type: {type: string, enum: [string, integer, decimal, boolean, json, datetime]}
        value: {}
        default_value: {}
        secret_value: {type: string, writeOnly: true, maxLength: 16384}
        is_secret: {type: boolean}
        is_public: {type: boolean}
        validation_schema: {type: object, additionalProperties: true}
        description: {type: string, maxLength: 1000}
        sort_order: {type: integer, format: int32}
        status: {type: string, enum: [active, disabled]}
        version: {type: integer, format: int32}
    AdminConfigSecretRequest:
      type: object
      additionalProperties: false
      required: [secret_value, version]
      properties: {secret_value: {type: string, writeOnly: true, minLength: 1, maxLength: 16384}, version: {type: integer, format: int32, minimum: 1}}
    AdminConfigPage:
      type: object
      required: [items, total, page, page_size]
      properties: {items: {type: array, items: {$ref: "#/components/schemas/AdminConfigItem"}}, total: {type: integer, format: int64}, page: {type: integer}, page_size: {type: integer}}
    AdminConfigResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/AdminConfigItem"}, request_id: {type: string}}
    AdminConfigListResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/AdminConfigPage"}, request_id: {type: string}}
    AdminDictionaryType:
      type: object
      required: [id, tenant_id, code, name, name_key, description, description_key, visibility, extension_policy, status, is_system, is_locked, created_at, updated_at]
      properties: {id: {type: string, format: uuid}, tenant_id: {type: [string, "null"], format: uuid}, code: {type: string}, name: {type: string}, name_key: {type: string}, description: {type: string}, description_key: {type: string}, visibility: {type: string, enum: [internal, public]}, extension_policy: {type: string, enum: [fixed, open, registered, s3_compatible]}, status: {type: string, enum: [active, disabled]}, is_system: {type: boolean}, is_locked: {type: boolean}, created_at: {type: string, format: date-time}, updated_at: {type: string, format: date-time}}
    AdminDictionaryTypeWriteRequest:
      type: object
      additionalProperties: false
      required: [code, name, description, status]
      properties: {code: {type: string}, name: {type: string}, description: {type: string}, status: {type: string, enum: [active, disabled]}}
    AdminDictionaryTypePage:
      type: object
      required: [items, total, page, page_size]
      properties: {items: {type: array, items: {$ref: "#/components/schemas/AdminDictionaryType"}}, total: {type: integer, format: int64}, page: {type: integer}, page_size: {type: integer}}
    AdminDictionaryTypeResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/AdminDictionaryType"}, request_id: {type: string}}
    AdminDictionaryTypeListResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/AdminDictionaryTypePage"}, request_id: {type: string}}
    AdminDictionaryItem:
      type: object
      required: [id, dict_type_id, tenant_id, item_value, label, locale, color, css_class, sort_order, is_default, extra, status, is_locked, created_at, updated_at]
      properties: {id: {type: string, format: uuid}, dict_type_id: {type: string, format: uuid}, tenant_id: {type: [string, "null"], format: uuid}, item_value: {type: string}, label: {type: string}, locale: {type: [string, "null"], enum: [zh-CN, en-US, null]}, color: {type: string}, css_class: {type: string}, sort_order: {type: integer, format: int32}, is_default: {type: boolean}, extra: {type: object, additionalProperties: true}, status: {type: string, enum: [active, disabled]}, is_locked: {type: boolean}, created_at: {type: string, format: date-time}, updated_at: {type: string, format: date-time}}
    AdminDictionaryItemWriteRequest:
      type: object
      additionalProperties: false
      required: [item_value, label, locale, color, css_class, sort_order, is_default, extra, status]
      properties: {item_value: {type: string}, label: {type: string}, locale: {type: [string, "null"], enum: [zh-CN, en-US, null]}, color: {type: string}, css_class: {type: string}, sort_order: {type: integer, format: int32}, is_default: {type: boolean}, extra: {type: object, additionalProperties: true}, status: {type: string, enum: [active, disabled]}}
    AdminDictionaryItemPage:
      type: object
      required: [items, total, page, page_size, type]
      properties: {items: {type: array, items: {$ref: "#/components/schemas/AdminDictionaryItem"}}, total: {type: integer, format: int64}, page: {type: integer}, page_size: {type: integer}, type: {$ref: "#/components/schemas/AdminDictionaryType"}}
    AdminDictionaryItemResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/AdminDictionaryItem"}, request_id: {type: string}}
    AdminDictionaryItemListResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/AdminDictionaryItemPage"}, request_id: {type: string}}
    DictionaryOption:
      type: object
      additionalProperties: false
      required: [value, label, is_default, extra]
      properties: {value: {type: string}, label: {type: string}, color: {type: string}, css_class: {type: string}, is_default: {type: boolean}, extra: {type: object, additionalProperties: true}}
    ResolvedDictionary:
      type: object
      additionalProperties: false
      required: [code, locale, extension_policy, items]
      properties: {code: {type: string}, locale: {$ref: "#/components/schemas/SupportedLocale"}, extension_policy: {type: string, enum: [fixed, open, registered, s3_compatible]}, items: {type: array, items: {$ref: "#/components/schemas/DictionaryOption"}}}
    ResolvedDictionaryResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string, const: OK}, message: {type: string}, data: {$ref: "#/components/schemas/ResolvedDictionary"}, request_id: {type: string}}
    AdminAPIClientSecret:
      type: object
      required: [id, prefix, created_at]
      properties: {id: {type: string, format: uuid}, prefix: {type: string}, created_at: {type: string, format: date-time}, expires_at: {type: string, format: date-time}, revoked_at: {type: string, format: date-time}, last_used_at: {type: string, format: date-time}}
    AdminAPIClient:
      type: object
      required: [id, client_id, name, description, allowed_cidrs, status, created_at, updated_at, secrets, permissions]
      properties:
        id: {type: string, format: uuid}
        client_id: {type: string}
        name: {type: string}
        description: {type: string}
        allowed_cidrs: {type: array, items: {type: string}}
        status: {type: string, enum: [active, disabled]}
        expires_at: {type: string, format: date-time}
        created_at: {type: string, format: date-time}
        updated_at: {type: string, format: date-time}
        secrets: {type: array, items: {$ref: "#/components/schemas/AdminAPIClientSecret"}}
        permissions: {type: array, items: {type: string}}
    AdminAPIClientRequest:
      type: object
      additionalProperties: false
      required: [name, description, allowed_cidrs, status]
      properties: {name: {type: string, minLength: 1, maxLength: 160}, description: {type: string, maxLength: 500}, allowed_cidrs: {type: array, maxItems: 64, items: {type: string}}, status: {type: string, enum: [active, disabled]}, expires_at: {type: string, format: date-time}}
    AdminAPIClientSecretRequest:
      type: object
      additionalProperties: false
      properties: {expires_at: {type: string, format: date-time}}
    AdminAPIClientPermissionsRequest:
      type: object
      additionalProperties: false
      required: [permission_codes]
      properties: {permission_codes: {type: array, maxItems: 256, uniqueItems: true, items: {type: string}}}
    AdminAPIClientPage:
      type: object
      required: [items, page, page_size, total]
      properties: {items: {type: array, items: {$ref: "#/components/schemas/AdminAPIClient"}}, page: {type: integer}, page_size: {type: integer}, total: {type: integer, format: int64}}
    AdminAPIClientResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/AdminAPIClient"}, request_id: {type: string}}
    AdminAPIClientListResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/AdminAPIClientPage"}, request_id: {type: string}}
    AdminAPIClientSecretCreated:
      type: object
      required: [metadata, secret]
      properties: {metadata: {$ref: "#/components/schemas/AdminAPIClientSecret"}, secret: {type: string, writeOnly: true, description: Returned exactly once and never persisted as plaintext.}}
    AdminAPIClientSecretCreatedResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/AdminAPIClientSecretCreated"}, request_id: {type: string}}
    APIClientTokenRequest:
      type: object
      additionalProperties: false
      required: [client_id, client_secret]
      properties: {client_id: {type: string}, client_secret: {type: string, writeOnly: true}}
    APIClientToken:
      type: object
      required: [access_token, token_type, audience, expires_at]
      properties: {access_token: {type: string, writeOnly: true}, token_type: {type: string, const: Bearer}, audience: {type: string, const: ak-api}, expires_at: {type: string, format: date-time}}
    APIClientTokenResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/APIClientToken"}, request_id: {type: string}}
    AdminWebhookRequest:
      type: object
      additionalProperties: false
      required: [name, endpoint_url, event_types, max_attempts, timeout_seconds, status]
      properties: {name: {type: string, minLength: 1, maxLength: 160}, endpoint_url: {type: string, format: uri, pattern: "^https://"}, event_types: {type: array, minItems: 1, maxItems: 64, uniqueItems: true, items: {type: string, pattern: "^[a-z0-9][a-z0-9_.-]{2,159}$"}}, max_attempts: {type: integer, format: int32, minimum: 1, maximum: 100}, timeout_seconds: {type: integer, format: int32, minimum: 1, maximum: 60}, status: {type: string, enum: [active, disabled]}}
    AdminWebhook:
      allOf:
        - {$ref: "#/components/schemas/AdminWebhookRequest"}
        - type: object
          required: [id, created_at, updated_at]
          properties: {id: {type: string, format: uuid}, created_at: {type: string, format: date-time}, updated_at: {type: string, format: date-time}}
    AdminWebhookPage:
      type: object
      required: [items, page, page_size, total]
      properties: {items: {type: array, items: {$ref: "#/components/schemas/AdminWebhook"}}, page: {type: integer, minimum: 1}, page_size: {type: integer, minimum: 1, maximum: 100}, total: {type: integer, format: int64, minimum: 0}}
    AdminWebhookDelivery:
      type: object
      required: [id, endpoint_id, event_id, event_type, payload, status, attempt_count, created_at, updated_at]
      properties: {id: {type: string, format: uuid}, endpoint_id: {type: string, format: uuid}, event_id: {type: string, format: uuid}, event_type: {type: string}, payload: {type: object, additionalProperties: true}, status: {type: string, enum: [pending, processing, succeeded, failed, cancelled]}, attempt_count: {type: integer, format: int32, minimum: 0}, next_attempt_at: {type: string, format: date-time}, response_status: {type: integer, minimum: 100, maximum: 599}, response_body: {type: string, maxLength: 4000}, last_error: {type: string, maxLength: 2000}, delivered_at: {type: string, format: date-time}, created_at: {type: string, format: date-time}, updated_at: {type: string, format: date-time}}
    AdminWebhookDeliveryPage:
      type: object
      required: [items, page, page_size, total]
      properties: {items: {type: array, items: {$ref: "#/components/schemas/AdminWebhookDelivery"}}, page: {type: integer, minimum: 1}, page_size: {type: integer, minimum: 1, maximum: 100}, total: {type: integer, format: int64, minimum: 0}}
    AdminWebhookTestRequest:
      type: object
      additionalProperties: false
      required: [event_type, payload]
      properties: {event_type: {type: string, pattern: "^[a-z0-9][a-z0-9_.-]{2,159}$"}, payload: {type: object, additionalProperties: true}}
    AdminWebhookCreated:
      type: object
      required: [endpoint, signing_secret]
      properties: {endpoint: {$ref: "#/components/schemas/AdminWebhook"}, signing_secret: {type: string, writeOnly: true, description: Returned exactly once; only AES-GCM ciphertext is persisted.}}
    AdminWebhookResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/AdminWebhook"}, request_id: {type: string}}
    AdminWebhookListResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/AdminWebhookPage"}, request_id: {type: string}}
    AdminWebhookCreatedResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/AdminWebhookCreated"}, request_id: {type: string}}
    AdminWebhookDeliveryResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/AdminWebhookDelivery"}, request_id: {type: string}}
    AdminWebhookDeliveryListResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/AdminWebhookDeliveryPage"}, request_id: {type: string}}
    AdminBlockRuleSubjectType:
      type: string
      enum: [ip, cidr, user, device, identifier]
    AdminBlockRuleAction:
      type: string
      enum: [deny, challenge, rate_limit]
    AdminBlockRuleCreateRequest:
      type: object
      additionalProperties: false
      required: [subject_type, subject_value, action, reason, status]
      properties: {subject_type: {$ref: "#/components/schemas/AdminBlockRuleSubjectType"}, subject_value: {type: string, writeOnly: true, minLength: 4, maxLength: 512, description: Accepted only on create and never returned by an API response.}, action: {$ref: "#/components/schemas/AdminBlockRuleAction"}, reason: {type: string, maxLength: 500}, starts_at: {type: [string, "null"], format: date-time}, expires_at: {type: [string, "null"], format: date-time}, status: {type: string, enum: [active, disabled]}}
    AdminBlockRuleUpdateRequest:
      type: object
      additionalProperties: false
      required: [action, reason, starts_at, status]
      properties: {action: {$ref: "#/components/schemas/AdminBlockRuleAction"}, reason: {type: string, maxLength: 500}, starts_at: {type: string, format: date-time}, expires_at: {type: [string, "null"], format: date-time}, status: {type: string, enum: [active, disabled]}}
    AdminBlockRule:
      type: object
      additionalProperties: false
      required: [id, subject_type, subject_hint, scope, action, reason, starts_at, status, created_at, updated_at]
      properties: {id: {type: string, format: uuid}, subject_type: {$ref: "#/components/schemas/AdminBlockRuleSubjectType"}, subject_hint: {type: string, description: Server-generated redacted display value; never sufficient to recover the subject.}, scope: {type: string, const: tenant}, action: {$ref: "#/components/schemas/AdminBlockRuleAction"}, reason: {type: string}, starts_at: {type: string, format: date-time}, expires_at: {type: [string, "null"], format: date-time}, status: {type: string, enum: [active, disabled]}, created_at: {type: string, format: date-time}, updated_at: {type: string, format: date-time}}
    AdminBlockRulePage:
      type: object
      required: [items, page, page_size, total]
      properties: {items: {type: array, items: {$ref: "#/components/schemas/AdminBlockRule"}}, page: {type: integer, minimum: 1}, page_size: {type: integer, minimum: 1, maximum: 100}, total: {type: integer, format: int64, minimum: 0}}
    AdminBlockRuleResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/AdminBlockRule"}, request_id: {type: string}}
    AdminBlockRuleListResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/AdminBlockRulePage"}, request_id: {type: string}}
    AdminBlockRuleRevokeResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {type: object, required: [id, revoked], properties: {id: {type: string, format: uuid}, revoked: {type: boolean, const: true}}}, request_id: {type: string}}
    ContentTranslation:
      type: object
      required: [title, summary, body_format, body]
      properties: {title: {type: string, maxLength: 300}, summary: {type: string, maxLength: 1000}, body_format: {type: string, enum: [markdown, blocks]}, body: {description: Restricted Markdown string or validated block array. Client rendering must sanitize Markdown and never render unsafe HTML.}}
    ContentCategoryTranslation:
      type: object
      required: [name, description]
      properties: {name: {type: string, maxLength: 160}, description: {type: string, maxLength: 500}}
    AdminContentTranslations:
      type: object
      required: [zh-CN, en-US]
      properties: {zh-CN: {$ref: "#/components/schemas/ContentTranslation"}, en-US: {$ref: "#/components/schemas/ContentTranslation"}}
    AdminContentCategoryTranslations:
      type: object
      required: [zh-CN, en-US]
      properties: {zh-CN: {$ref: "#/components/schemas/ContentCategoryTranslation"}, en-US: {$ref: "#/components/schemas/ContentCategoryTranslation"}}
    AdminContentCategory:
      type: object
      required: [id, slug, status, sort_order, lock_version, translations, created_at, updated_at]
      properties: {id: {type: string, format: uuid}, slug: {type: string}, status: {type: string, enum: [active, disabled]}, sort_order: {type: integer}, lock_version: {type: integer, minimum: 1}, translations: {$ref: "#/components/schemas/AdminContentCategoryTranslations"}, created_at: {type: string, format: date-time}, updated_at: {type: string, format: date-time}}
    AdminContentCategoryRequest:
      type: object
      required: [slug, status, sort_order, translations]
      properties: {slug: {type: string, pattern: '^[a-z0-9]+(?:-[a-z0-9]+)*$'}, status: {type: string, enum: [active, disabled]}, sort_order: {type: integer}, lock_version: {type: integer, minimum: 1}, translations: {$ref: "#/components/schemas/AdminContentCategoryTranslations"}}
    AdminContentCategoryUpdateRequest:
      allOf:
        - $ref: "#/components/schemas/AdminContentCategoryRequest"
        - type: object
          required: [lock_version]
          properties: {lock_version: {type: integer, minimum: 1}}
    AdminContentArticle:
      type: object
      required: [id, slug, status, featured, sort_order, reading_minutes, lock_version, translations, created_at, updated_at]
      properties: {id: {type: string, format: uuid}, category_id: {type: [string, 'null'], format: uuid}, slug: {type: string}, status: {type: string, enum: [draft, published, archived]}, featured: {type: boolean}, sort_order: {type: integer}, cover_file_id: {type: [string, 'null'], format: uuid}, cover_url: {type: [string, 'null'], description: Server-derived safe URL only}, reading_minutes: {type: integer, minimum: 1, maximum: 120}, lock_version: {type: integer, minimum: 1}, published_at: {type: [string, 'null'], format: date-time}, translations: {$ref: "#/components/schemas/AdminContentTranslations"}, created_at: {type: string, format: date-time}, updated_at: {type: string, format: date-time}}
    AdminContentArticleRequest:
      type: object
      required: [slug, featured, sort_order, reading_minutes, translations]
      properties: {category_id: {type: [string, 'null'], format: uuid}, slug: {type: string, pattern: '^[a-z0-9]+(?:-[a-z0-9]+)*$'}, featured: {type: boolean}, sort_order: {type: integer}, cover_file_id: {type: [string, 'null'], format: uuid}, reading_minutes: {type: integer, minimum: 1, maximum: 120}, lock_version: {type: integer, minimum: 1}, translations: {$ref: "#/components/schemas/AdminContentTranslations"}}
    AdminContentArticleUpdateRequest:
      allOf:
        - $ref: "#/components/schemas/AdminContentArticleRequest"
        - type: object
          required: [lock_version]
          properties: {lock_version: {type: integer, minimum: 1}}
    AdminContentTransitionRequest:
      type: object
      required: [lock_version]
      properties: {lock_version: {type: integer, minimum: 1}}
    AdminContentCategoryResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/AdminContentCategory"}, request_id: {type: string}}
    AdminContentCategoryListResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {type: object, required: [items, page, page_size, total], properties: {items: {type: array, items: {$ref: "#/components/schemas/AdminContentCategory"}}, page: {type: integer}, page_size: {type: integer}, total: {type: integer}}}, request_id: {type: string}}
    AdminContentArticleResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/AdminContentArticle"}, request_id: {type: string}}
    AdminContentArticleListResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {type: object, required: [items, page, page_size, total], properties: {items: {type: array, items: {$ref: "#/components/schemas/AdminContentArticle"}}, page: {type: integer}, page_size: {type: integer}, total: {type: integer}}}, request_id: {type: string}}
    AppArticle:
      type: object
      required: [id, slug, featured, published_at, title, summary, body_format, body, category, reading_minutes, bookmarked]
      properties: {id: {type: string, format: uuid}, slug: {type: string}, featured: {type: boolean}, published_at: {type: string, format: date-time}, title: {type: string}, summary: {type: string}, body_format: {type: string, enum: [markdown, blocks]}, body: {}, category: {oneOf: [{$ref: "#/components/schemas/AppArticleCategory"}, {type: 'null'}]}, reading_minutes: {type: integer, minimum: 1, maximum: 120}, cover_url: {type: [string, 'null'], description: "Authenticated same-origin article asset path for a published scan-safe image."}, bookmarked: {type: boolean}}
    AppArticleCategory:
      type: object
      required: [id, slug, sort_order, name, description]
      properties: {id: {type: string, format: uuid}, slug: {type: string}, sort_order: {type: integer}, name: {type: string}, description: {type: string}}
    AppArticleCategoryListResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {type: object, required: [items], properties: {items: {type: array, items: {$ref: "#/components/schemas/AppArticleCategory"}}}}, request_id: {type: string}}
    AppArticleResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/AppArticle"}, request_id: {type: string}}
    AppArticleListResponse:
      type: object
      required: [code, message, data, meta, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {type: object, required: [items], properties: {items: {type: array, items: {$ref: "#/components/schemas/AppArticle"}}}}, meta: {type: object, properties: {next_cursor: {type: [string, 'null']}}}, request_id: {type: string}}
    AppBookmarkResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {type: object, required: [bookmarked], properties: {bookmarked: {type: boolean}}}, request_id: {type: string}}
    AdminOpsStatus:
      type: string
      enum: [ready, degraded, unavailable, not_configured, unknown]
    AdminOpsDependency:
      type: object
      additionalProperties: false
      required: [code, status, latency_ms, detail_code, checked_at]
      properties: {code: {type: string, enum: [api, postgresql, redis, object_storage]}, status: {$ref: "#/components/schemas/AdminOpsStatus"}, latency_ms: {type: integer, format: int64, minimum: 0}, detail_code: {type: string, description: Stable translation/diagnostic code without raw exception text.}, checked_at: {type: string, format: date-time}}
    AdminOpsHealth:
      type: object
      additionalProperties: false
      required: [status, dependencies, checked_at]
      properties: {status: {$ref: "#/components/schemas/AdminOpsStatus"}, dependencies: {type: array, items: {$ref: "#/components/schemas/AdminOpsDependency"}}, checked_at: {type: string, format: date-time}}
    AdminOpsHealthResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/AdminOpsHealth"}, request_id: {type: string}}
    AdminOpsModule:
      type: object
      additionalProperties: false
      required: [code, name_key, description_key, version, capabilities, status]
      properties:
        code: {type: string}
        name_key: {type: string}
        description_key: {type: string}
        version: {type: string}
        capabilities: {type: object, additionalProperties: {type: boolean}}
        status: {type: string, enum: [enabled, disabled]}
    AdminOpsQueue:
      type: object
      additionalProperties: false
      required: [status, available, running, retryable, scheduled, completed, failed]
      properties: {status: {$ref: "#/components/schemas/AdminOpsStatus"}, last_heartbeat_at: {type: [string, "null"], format: date-time}, available: {type: integer, format: int64, minimum: 0}, running: {type: integer, format: int64, minimum: 0}, retryable: {type: integer, format: int64, minimum: 0}, scheduled: {type: integer, format: int64, minimum: 0}, completed: {type: integer, format: int64, minimum: 0}, failed: {type: integer, format: int64, minimum: 0}}
    AdminOpsRunSummary:
      type: object
      additionalProperties: false
      required: [queued, running, succeeded, failed, skipped]
      properties: {queued: {type: integer, format: int64, minimum: 0}, running: {type: integer, format: int64, minimum: 0}, succeeded: {type: integer, format: int64, minimum: 0}, failed: {type: integer, format: int64, minimum: 0}, skipped: {type: integer, format: int64, minimum: 0}}
    AdminOpsRuntime:
      type: object
      additionalProperties: false
      required: [app_version, go_version, uptime_seconds, modules, queue, schedule_runs_24h, generated_at]
      properties: {app_version: {type: string}, go_version: {type: string}, uptime_seconds: {type: integer, format: int64, minimum: 0}, modules: {type: array, items: {$ref: "#/components/schemas/AdminOpsModule"}}, queue: {$ref: "#/components/schemas/AdminOpsQueue"}, schedule_runs_24h: {$ref: "#/components/schemas/AdminOpsRunSummary"}, generated_at: {type: string, format: date-time}}
    AdminOpsRuntimeResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/AdminOpsRuntime"}, request_id: {type: string}}
    MobilePasswordLoginRequest:
      type: object
      additionalProperties: false
      required: [email, password]
      properties: {email: {type: string, format: email}, password: {type: string, format: password, minLength: 12, maxLength: 256}}
    MobileRefreshRequest:
      type: object
      additionalProperties: false
      required: [refresh_token]
      properties: {refresh_token: {type: string, minLength: 32, description: Opaque token held only in mobile secure storage.}}
    MobileToken:
      type: object
      required: [access_token, token_type, expires_in, refresh_token, refresh_token_expires_in, session_id, app_id]
      properties: {access_token: {type: string}, token_type: {type: string, const: Bearer}, expires_in: {type: integer, minimum: 0}, refresh_token: {type: string}, refresh_token_expires_in: {type: integer, minimum: 0}, session_id: {type: string, format: uuid}, app_id: {type: string, format: uuid}}
    MobileTokenResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/MobileToken"}, request_id: {type: string}}
    SelfPasswordChangeRequest:
      type: object
      additionalProperties: false
      required: [current_password, new_password]
      properties: {current_password: {type: string, format: password}, new_password: {type: string, format: password, minLength: 12, maxLength: 256}}
    SelfProfile:
      type: object
      required: [id, email, display_name, locale, time_zone]
      properties: {id: {type: string, format: uuid}, email: {type: string, format: email}, display_name: {type: string}, locale: {$ref: "#/components/schemas/SupportedLocale"}, time_zone: {type: string}, avatar_url: {type: [string, 'null']}}
    SelfProfileResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/SelfProfile"}, request_id: {type: string}}
    SelfProfileUpdateRequest:
      type: object
      additionalProperties: false
      minProperties: 1
      properties: {display_name: {type: string, minLength: 1, maxLength: 160}, locale: {$ref: "#/components/schemas/SupportedLocale"}, time_zone: {type: string, maxLength: 64}}
    MobileContextResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {type: object, required: [user, active_tenant, roles, permissions, feature_flags, server_time], properties: {user: {$ref: "#/components/schemas/SelfProfile"}, active_tenant: {type: object}, roles: {type: array, items: {type: string}}, permissions: {type: array, items: {type: string}}, feature_flags: {type: object, additionalProperties: {type: boolean}}, server_time: {type: string, format: date-time}}}, request_id: {type: string}}
    MobileSession:
      type: object
      required: [id, audience, status, last_seen_at, absolute_expires_at, created_at, current]
      properties: {id: {type: string, format: uuid}, audience: {type: string, const: ak-mobile}, status: {type: string}, ip_address: {type: [string, 'null']}, user_agent: {type: string}, last_seen_at: {type: string, format: date-time}, absolute_expires_at: {type: string, format: date-time}, created_at: {type: string, format: date-time}, current: {type: boolean}}
    MobileSessionListResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {type: array, items: {$ref: "#/components/schemas/MobileSession"}}, request_id: {type: string}}
    MobileDevice:
      type: object
      required: [id, platform, device_name, model, os_version, app_version, created_at, latest_user_agent, active_session_count, current]
      properties: {id: {type: string, format: uuid}, platform: {type: string}, device_name: {type: string}, model: {type: string}, os_version: {type: string}, app_version: {type: string}, last_ip: {type: [string, 'null']}, last_seen_at: {type: [string, 'null'], format: date-time}, created_at: {type: string, format: date-time}, latest_user_agent: {type: string}, active_session_count: {type: integer}, current: {type: boolean}}
    MobileDeviceListResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {type: array, items: {$ref: "#/components/schemas/MobileDevice"}}, request_id: {type: string}}
    MobilePreferences:
      type: object
      required: [locale, appearance, notification_preferences]
      properties: {locale: {$ref: "#/components/schemas/SupportedLocale"}, appearance: {type: string, enum: [system, light, dark]}, notification_preferences: {type: object, additionalProperties: false, properties: {in_app: {type: boolean}, push: {type: boolean}, email: {type: boolean}}}}
    MobilePreferencesUpdateRequest:
      type: object
      additionalProperties: false
      minProperties: 1
      properties: {locale: {$ref: "#/components/schemas/SupportedLocale"}, appearance: {type: string, enum: [system, light, dark]}, notification_preferences: {$ref: "#/components/schemas/MobilePreferences/properties/notification_preferences"}}
    MobilePreferencesResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/MobilePreferences"}, request_id: {type: string}}
    MobileNotificationPreferences:
      type: object
      additionalProperties: false
      required: [notification_preferences]
      properties: {notification_preferences: {type: object, additionalProperties: false, properties: {in_app: {type: boolean}, push: {type: boolean}, email: {type: boolean}}}}
    MobileNotificationPreferencesUpdateRequest:
      allOf: [{$ref: "#/components/schemas/MobileNotificationPreferences"}]
    MobileNotificationPreferencesResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/MobileNotificationPreferences"}, request_id: {type: string}}
    MobileUnreadCountResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {type: object, required: [count], properties: {count: {type: integer, minimum: 0}}}, request_id: {type: string}}
    MobileLoginEvent:
      type: object
      required: [id, auth_method, result, occurred_at]
      properties: {id: {type: string, format: uuid}, auth_method: {type: string}, result: {type: string}, occurred_at: {type: string, format: date-time}, ip_address: {type: [string, 'null']}}
    MobileLoginEventListResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {type: array, items: {$ref: "#/components/schemas/MobileLoginEvent"}}, request_id: {type: string}}
    MobileSecurityEvent:
      type: object
      required: [id, event_type, severity, occurred_at]
      properties: {id: {type: string, format: uuid}, event_type: {type: string}, severity: {type: string, enum: [info, low, medium, high, critical]}, occurred_at: {type: string, format: date-time}}
    MobileSecurityEventListResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {type: array, items: {$ref: "#/components/schemas/MobileSecurityEvent"}}, request_id: {type: string}}
    MobileAppVersionResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/MobileAppVersion"}, request_id: {type: string}}
    MobileAppVersion:
      type: object
      additionalProperties: false
      required: [platform, package_type, delivery_mode, current_version, minimum_version, store_list, title, release_notes, is_silently, is_mandatory]
      properties: {platform: {type: string, enum: [android, ios, harmony]}, package_type: {type: string, enum: [native_app, wgt]}, delivery_mode: {type: string, enum: [internal_package, external_link]}, current_version: {type: string, pattern: '^\d+\.\d+\.\d+$'}, minimum_version: {type: string, pattern: '^\d+\.\d+\.\d+$'}, upgrade_url: {type: [string, 'null'], format: uri-reference}, store_list: {type: array, items: {$ref: "#/components/schemas/MobileAppVersionStore"}}, title: {type: string}, release_notes: {type: string}, is_silently: {type: boolean}, is_mandatory: {type: boolean}, published_at: {type: [string, 'null'], format: date-time}}
    MobileAppVersionStore:
      type: object
      additionalProperties: false
      required: [id, name, scheme, priority]
      properties: {id: {type: string, format: uuid}, name: {type: string}, scheme: {type: string}, priority: {type: integer, format: int32}}
    BooleanSuccessResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {type: object}, request_id: {type: string}}
    MobileNotification:
      type: object
      required: [id, title, body, body_format, message_type, created_at]
      properties: {id: {type: string, format: uuid}, title: {type: string}, body: {type: string}, body_format: {type: string, enum: [plain, markdown, html]}, message_type: {type: string}, created_at: {type: string, format: date-time}, read_at: {type: [string, 'null'], format: date-time}}
    MobileNotificationPageResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {type: object, required: [items], properties: {items: {type: array, items: {$ref: "#/components/schemas/MobileNotification"}}, next_cursor: {type: [string, 'null']}}}, request_id: {type: string}}
    AdminMobileRelease:
      type: object
      required: [id, app_id, package_type, platforms, version, titles, contents, store_listing_ids, create_env, is_silently, is_mandatory, publish_status, published_platforms, platform, current_version, minimum_version, release_notes, active, lock_version, created_at, updated_at]
      properties:
        id: {type: string, format: uuid}
        app_id: {type: string, format: uuid}
        package_type: {type: string, enum: [native_app, wgt]}
        platforms: {type: array, minItems: 1, uniqueItems: true, items: {type: string, enum: [android, ios, harmony]}}
        version: {type: string, pattern: '^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$'}
        minimum_native_version: {type: [string, 'null'], pattern: '^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$'}
        titles: {$ref: "#/components/schemas/LocalizedReleaseText"}
        contents: {$ref: "#/components/schemas/LocalizedReleaseText"}
        package_file_id: {type: [string, 'null'], format: uuid}
        external_url: {type: [string, 'null'], pattern: '^https://'}
        store_listing_ids: {type: array, maxItems: 100, items: {type: string, format: uuid}}
        create_env: {type: string, enum: [uni_stat, upgrade_center]}
        is_silently: {type: boolean}
        is_mandatory: {type: boolean}
        publish_status: {type: string, enum: [draft, online, partial, offline]}
        published_platforms: {type: array, items: {type: string, enum: [android, ios, harmony]}}
        ever_published_at: {type: [string, 'null'], format: date-time}
        last_published_at: {type: [string, 'null'], format: date-time}
        unpublished_at: {type: [string, 'null'], format: date-time}
        platform: {type: string, enum: [android, ios, harmony]}
        current_version: {type: string}
        minimum_version: {type: string}
        upgrade_url: {type: [string, 'null'], format: uri}
        release_notes: {$ref: "#/components/schemas/LocalizedReleaseText"}
        active: {type: boolean}
        lock_version: {type: integer, minimum: 1}
        created_at: {type: string, format: date-time}
        updated_at: {type: string, format: date-time}
    AdminMobileReleaseRequest:
      type: object
      additionalProperties: false
      oneOf:
        - required: [package_type, platforms, version, titles, contents]
        - required: [platform, current_version, minimum_version, release_notes, active]
      properties:
        package_type: {type: string, enum: [native_app, wgt]}
        platforms: {type: array, minItems: 1, maxItems: 3, uniqueItems: true, items: {type: string, enum: [android, ios, harmony]}}
        version: {type: string, pattern: '^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$'}
        minimum_native_version: {type: [string, 'null'], pattern: '^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$'}
        titles: {$ref: "#/components/schemas/LocalizedReleaseText"}
        contents: {$ref: "#/components/schemas/LocalizedReleaseText"}
        package_file_id: {type: [string, 'null'], format: uuid}
        external_url: {type: [string, 'null'], pattern: '^https://'}
        store_listing_ids: {type: array, maxItems: 100, uniqueItems: true, items: {type: string, format: uuid}}
        create_env: {type: string, enum: [uni_stat, upgrade_center], default: upgrade_center}
        is_silently: {type: boolean, default: false}
        is_mandatory: {type: boolean, default: false}
        publish_now: {type: boolean, default: false}
        platform: {type: string, enum: [android, ios, harmony]}
        current_version: {type: string, pattern: '^\d+\.\d+\.\d+$'}
        minimum_version: {type: string, pattern: '^\d+\.\d+\.\d+$'}
        upgrade_url: {type: [string, 'null'], pattern: '^https://'}
        release_notes: {$ref: "#/components/schemas/LocalizedReleaseText"}
        active: {type: boolean}
        lock_version: {type: integer, minimum: 1}
    LocalizedReleaseText:
      type: object
      additionalProperties: false
      required: [zh-CN, en-US]
      properties: {zh-CN: {type: string, minLength: 1}, en-US: {type: string, minLength: 1}}
    AdminMobileReleaseResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {$ref: "#/components/schemas/AdminMobileRelease"}, request_id: {type: string}}
    AdminMobileReleaseListResponse:
      type: object
      required: [code, message, data, request_id]
      properties: {code: {type: string}, message: {type: string}, data: {type: array, items: {$ref: "#/components/schemas/AdminMobileRelease"}}, request_id: {type: string}}
    AdminMobileReleasePageResponse:
      type: object
      required: [code, message, data, request_id]
      properties:
        code: {type: string}
        message: {type: string}
        data: {type: object, required: [items, page, page_size, total], properties: {items: {type: array, items: {$ref: "#/components/schemas/AdminMobileRelease"}}, page: {type: integer, minimum: 1}, page_size: {type: integer, minimum: 1}, total: {type: integer, minimum: 0}}}
        request_id: {type: string}
    UUIDBatchRequest:
      type: object
      additionalProperties: false
      required: [ids]
      properties: {ids: {type: array, minItems: 1, maxItems: 100, uniqueItems: true, items: {type: string, format: uuid}}}
    LockVersionRequest:
      type: object
      additionalProperties: false
      required: [lock_version]
      properties: {lock_version: {type: integer, minimum: 1}}
