asyncapi: 2.6.0
info:
  title: DMS Simulation — real-time API
  version: 1.0.0
  description: |
    Transport is **Socket.IO** (Engine.IO), not a raw WebSocket.

    - HTTP path: `/ws/socket.io`
    - Namespace: `/simulation`
    - Requires `ENABLE_SOCKET_TIMER=true` on the server for the endpoint to be mounted.

    **Authentication (on connect)**  
    JWT access token via either:
    - `Authorization: Bearer <token>`, or
    - query parameter `token=<jwt>`

    Disconnect closes any open simulation attempt (server-side).

defaultContentType: application/json

servers:
  local:
    url: localhost:{port}/ws/socket.io
    protocol: ws
    variables:
      port:
        default: "8000"
        description: Same as APP_PORT (uvicorn/gunicorn).

channels:
  "simulation:start":
    publish:
      summary: Client starts a simulation attempt
      message:
        name: simulationStart
        payload:
          type: object
          required:
            - simulation_id
          properties:
            simulation_id:
              type: integer
              description: Simulation module id.
            allocation_id:
              type: integer
              description: Optional licence allocation id (B2B).

  "simulation:started":
    subscribe:
      summary: Server returns new attempt id after simulation:start
      message:
        name: simulationStarted
        payload:
          type: object
          properties:
            attempt_id:
              type: integer

  "simulation:error":
    subscribe:
      summary: Server rejects simulation:start (validation / business rule)
      message:
        name: simulationError
        payload:
          type: object
          properties:
            error:
              type: string

  "simulation:first_cta":
    publish:
      summary: Record first CTA for timing
      message:
        name: simulationFirstCta
        payload:
          type: object
          properties:
            attempt_id:
              type: integer
              description: Uses session attempt id if omitted.

  "simulation:first_cta_recorded":
    subscribe:
      summary: Server confirms first CTA
      message:
        name: simulationFirstCtaRecorded
        payload:
          type: object
          properties:
            attempt_id:
              type: integer

  "simulation:heartbeat":
    publish:
      summary: Keep-alive / presence for session timing
      message:
        name: simulationHeartbeat
        payload:
          type: object
          properties:
            attempt_id:
              type: integer

  "simulation:complete":
    publish:
      summary: Finalise attempt with optional score and metadata
      message:
        name: simulationComplete
        payload:
          type: object
          properties:
            attempt_id:
              type: integer
            score:
              type: number
            metadata:
              description: Arbitrary JSON-serialisable metadata (stored truncated server-side).

  "simulation:completed":
    subscribe:
      summary: Server confirms completion
      message:
        name: simulationCompleted
        payload:
          type: object
          properties:
            attempt_id:
              type: integer
            ok:
              type: boolean
