openapi: 3.1.0
jsonSchemaDialect: https://json-schema.org/draft/2020-12/schema
info:
  title: Nasak Platform API
  version: 1.0.0-alpha.1
  description: Platform health, developer onboarding, and API client governance.
  contact:
    name: Nasak Platform Operations
    url: https://developers.nasak.ir
  license:
    name: Proprietary
servers:
  - url: https://api.nasak.ir
    description: Production
tags:
  - name: Health
  - name: Client requests
  - name: Migration telemetry
paths:
  /v1/platform/live:
    get:
      tags: [Health]
      operationId: getPlatformLiveness
      summary: Check whether the platform process is alive
      security: []
      responses:
        '200':
          description: Process is alive.
          headers:
            X-Request-ID:
              $ref: './common.yaml#/components/headers/RequestId'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Health'
  /v1/platform/ready:
    get:
      tags: [Health]
      operationId: getPlatformReadiness
      summary: Check platform dependencies
      security: []
      responses:
        '200':
          description: Dependencies are ready.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Health'
        '503':
          description: At least one required dependency is unavailable.
          content:
            application/problem+json:
              schema:
                $ref: './common.yaml#/components/schemas/Problem'
  /v1/platform/client-requests:
    get:
      tags: [Client requests]
      operationId: listClientRequests
      summary: List API client requests awaiting or completing review
      security:
        - oauth2: [platform.clients.approve]
      parameters:
        - name: status
          in: query
          schema:
            type: string
            enum: [PENDING, APPROVED, REJECTED]
        - $ref: './common.yaml#/components/parameters/Limit'
      responses:
        '200':
          description: Client requests, newest first.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: false
                required: [items, page]
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/ClientRequest'
                  page:
                    $ref: './common.yaml#/components/schemas/CursorPage'
        '401':
          $ref: './common.yaml#/components/responses/Unauthorized'
        '403':
          $ref: './common.yaml#/components/responses/Forbidden'
    post:
      tags: [Client requests]
      operationId: createClientRequest
      summary: Request approval for a new API client
      security:
        - oauth2: [platform.clients.request]
      parameters:
        - $ref: './common.yaml#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ClientRequestInput'
      responses:
        '202':
          description: Request accepted for administrative review.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClientRequest'
        '400':
          $ref: './common.yaml#/components/responses/BadRequest'
        '401':
          $ref: './common.yaml#/components/responses/Unauthorized'
        '403':
          $ref: './common.yaml#/components/responses/Forbidden'
        '429':
          $ref: './common.yaml#/components/responses/TooManyRequests'
  /v1/platform/client-requests/{requestId}:
    patch:
      tags: [Client requests]
      operationId: reviewClientRequest
      summary: Approve or reject an API client request
      security:
        - oauth2: [platform.clients.approve]
      parameters:
        - name: requestId
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - $ref: './common.yaml#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required: [decision]
              properties:
                decision:
                  type: string
                  enum: [APPROVED, REJECTED]
                note:
                  type: string
                  maxLength: 2000
      responses:
        '200':
          description: Review decision stored.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClientRequest'
        '400':
          $ref: './common.yaml#/components/responses/BadRequest'
        '401':
          $ref: './common.yaml#/components/responses/Unauthorized'
        '403':
          $ref: './common.yaml#/components/responses/Forbidden'
  /v1/platform/legacy-usage:
    post:
      tags: [Migration telemetry]
      operationId: submitLegacyUsage
      summary: Submit privacy-safe aggregated legacy route usage
      security:
        - oauth2: [platform.telemetry.write]
      parameters:
        - $ref: './common.yaml#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required: [events]
              properties:
                events:
                  type: array
                  minItems: 1
                  maxItems: 100
                  items:
                    $ref: '#/components/schemas/LegacyUsageEvent'
      responses:
        '202':
          description: Aggregates accepted.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: false
                required: [accepted]
                properties:
                  accepted:
                    type: integer
                    minimum: 1
                    maximum: 100
        '400':
          $ref: './common.yaml#/components/responses/BadRequest'
        '401':
          $ref: './common.yaml#/components/responses/Unauthorized'
        '403':
          $ref: './common.yaml#/components/responses/Forbidden'
        '429':
          $ref: './common.yaml#/components/responses/TooManyRequests'
    get:
      tags: [Migration telemetry]
      operationId: listLegacyUsage
      summary: List aggregated legacy route usage for migration decisions
      security:
        - oauth2: [platform.telemetry.read]
      parameters:
        - name: service
          in: query
          schema:
            $ref: '#/components/schemas/ServiceName'
        - name: clientId
          in: query
          schema:
            type: string
            maxLength: 100
        - name: from
          in: query
          schema:
            type: string
            format: date-time
        - name: to
          in: query
          schema:
            type: string
            format: date-time
        - $ref: './common.yaml#/components/parameters/Limit'
      responses:
        '200':
          description: Aggregated usage, newest buckets first.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: false
                required: [items, page]
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/LegacyUsageAggregate'
                  page:
                    $ref: './common.yaml#/components/schemas/CursorPage'
        '401':
          $ref: './common.yaml#/components/responses/Unauthorized'
        '403':
          $ref: './common.yaml#/components/responses/Forbidden'
components:
  securitySchemes:
    oauth2:
      $ref: './common.yaml#/components/securitySchemes/oauth2'
  schemas:
    ServiceName:
      type: string
      enum: [library, commerce, hr, hse, messaging, platform]
    LegacyUsageEvent:
      type: object
      additionalProperties: false
      required: [service, legacyRoute, versionedRoute, method, clientId, occurredAt]
      properties:
        service:
          $ref: '#/components/schemas/ServiceName'
        legacyRoute:
          type: string
          minLength: 1
          maxLength: 255
        versionedRoute:
          type: string
          pattern: '^/v1/'
          maxLength: 255
        method:
          type: string
          enum: [GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS]
        clientId:
          type: string
          minLength: 1
          maxLength: 100
        occurredAt:
          type: string
          format: date-time
        requestCount:
          type: integer
          minimum: 1
          maximum: 100000
          default: 1
        errorCount:
          type: integer
          minimum: 0
          maximum: 100000
          default: 0
    LegacyUsageAggregate:
      allOf:
        - $ref: '#/components/schemas/LegacyUsageEvent'
        - type: object
          required: [bucketHour, lastSeenAt, requestCount, errorCount]
          properties:
            bucketHour:
              type: string
              format: date-time
            lastSeenAt:
              type: string
              format: date-time
    Health:
      type: object
      additionalProperties: false
      required: [status, time]
      properties:
        status:
          type: string
          enum: [ok]
        time:
          type: string
          format: date-time
    ClientRequestInput:
      type: object
      additionalProperties: false
      required: [name, ownerEmail, scopes, origins, description]
      properties:
        name:
          type: string
          minLength: 3
          maxLength: 100
        ownerEmail:
          type: string
          format: email
        scopes:
          type: array
          minItems: 1
          maxItems: 30
          uniqueItems: true
          items:
            type: string
            pattern: '^[a-z][a-z0-9.-]+$'
        origins:
          type: array
          maxItems: 20
          uniqueItems: true
          items:
            type: string
            format: uri
        description:
          type: string
          minLength: 20
          maxLength: 2000
    ClientRequest:
      allOf:
        - $ref: '#/components/schemas/ClientRequestInput'
        - type: object
          required: [id, status, createdAt]
          properties:
            id:
              type: string
              format: uuid
            status:
              type: string
              enum: [PENDING, APPROVED, REJECTED]
            createdAt:
              type: string
              format: date-time
