Skip to content

Latest commit

 

History

History
586 lines (543 loc) · 15.5 KB

File metadata and controls

586 lines (543 loc) · 15.5 KB

CogFlow Platform API (Day 3 Contract Freeze)

This file defines the current v1 contract for the Week 1 vertical slice and matches the implementation in backend/project/api_views.py.

Local Integration Ports

  • cogflow-platform API: http://127.0.0.1:8000
  • cogflow-builder-app local UI: typically http://127.0.0.1:5500 (VS Code Live Server)
  • cogflow-interpreter-app local UI: use http://127.0.0.1:5501 when running side-by-side (or :5500 when run alone)

Builder and Interpreter call the API on port 8000 (as shown in frontend/builder/publish_stub.html and frontend/interpreter/runtime_stub.html).

DRF Schema Output

  • Live schema endpoint: GET /api/schema
  • Name in Django URLs: openapi-schema
  • JSON output uses DRF's built-in OpenAPI generator.

Generate a checked-in schema artifact:

cd /home/kamisalibayeva/GitHub/cogflow-platform

docker compose exec -T api python manage.py generateschema --format openapi-json > docs/openapi.json

OpenAPI 3.0 Schema

openapi: 3.0.3
info:
  title: CogFlow Platform API
  version: 1.0.0-day3
  description: |
    Day 3 contract-first API for the Week 1 vertical slice.
    Covers publish, start-run, submit-result, studies list, and health.
servers:
  - url: http://127.0.0.1:8000
    description: Local Docker compose API
  - url: http://localhost:8000
    description: Local Docker compose API (alt hostname)
tags:
  - name: Ops
  - name: Auth
  - name: Studies
  - name: Builder
  - name: Interpreter
paths:
  /healthz:
    get:
      tags: [Ops]
      summary: Service health check
      responses:
        '200':
          description: Service is healthy
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                    example: true
                required: [ok]

  /api/v1/studies:
    get:
      tags: [Studies]
      summary: List studies visible in portal
      responses:
        '200':
          description: Studies list
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StudiesListResponse'

  /api/v1/auth/login:
    post:
      tags: [Auth]
      summary: Session login for platform users
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AuthLoginRequest'
      responses:
        '200':
          description: Login succeeded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthLoginResponse'
        '401':
          description: Invalid credentials
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'

  /api/v1/auth/logout:
    post:
      tags: [Auth]
      summary: Logout current session
      responses:
        '200':
          description: Logout succeeded

  /api/v1/auth/mfa/setup:
    post:
      tags: [Auth]
      summary: Generate TOTP setup secret and provisioning URI for authenticated user
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TotpSetupRequest'
      responses:
        '200':
          description: Setup data returned
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TotpSetupResponse'
        '401':
          description: Authentication required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'

  /api/v1/auth/mfa/verify:
    post:
      tags: [Auth]
      summary: Verify TOTP code and mark MFA verified in current session
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TotpVerifyRequest'
      responses:
        '200':
          description: TOTP verification succeeded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TotpVerifyResponse'
        '401':
          description: Invalid code or not authenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'
        '400':
          description: TOTP not set up
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'

  /api/v1/configs/publish:
    post:
      tags: [Builder]
      summary: Publish a Builder config and upsert study linkage
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PublishConfigRequest'
      responses:
        '201':
          description: Config accepted and study linkage upserted
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublishConfigResponse'
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationError'

  /api/v1/runs/start:
    post:
      tags: [Interpreter]
      summary: Start a run session for a published study
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StartRunRequest'
      responses:
        '201':
          description: Run session created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StartRunResponse'
        '400':
          description: Validation error or no published config
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ValidationError'
                  - $ref: '#/components/schemas/ErrorMessage'
        '404':
          description: Study not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'

  /api/v1/results/submit:
    post:
      tags: [Interpreter]
      summary: Submit aggregate and optional per-trial result payloads
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SubmitResultRequest'
      responses:
        '201':
          description: Result stored
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SubmitResultResponse'
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationError'
        '404':
          description: Run session not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'

  /api/v1/results/decrypt:
    post:
      tags: [Interpreter]
      summary: Protected decrypt/read endpoint for stored result payloads
      description: |
        Requires authenticated user session and successful TOTP verification.
        Decrypt access is denied unless MFA is enabled and verified within the
        configured `MFA_REAUTH_SECONDS` window.
        All denied and successful decrypt attempts are recorded in `AuditEvent`.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DecryptResultRequest'
      responses:
        '200':
          description: Decrypted payload returned
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DecryptResultResponse'
        '403':
          description: MFA verification required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'
        '401':
          description: Authentication required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'
        '404':
          description: Run session or result envelope not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'

components:
  schemas:
    RuntimeMode:
      type: string
      enum: [django, jatos, hybrid, home_gear_lsl]

    RunStatus:
      type: string
      enum: [completed, failed]

    ErrorMessage:
      type: object
      properties:
        error:
          type: string
      required: [error]

    ValidationError:
      type: object
      additionalProperties: true
      description: DRF validation error object keyed by field name.

    AuthLoginRequest:
      type: object
      required: [username, password]
      properties:
        username:
          type: string
        password:
          type: string

    AuthLoginResponse:
      type: object
      properties:
        ok:
          type: boolean
        username:
          type: string
        mfa_enabled:
          type: boolean
      required: [ok, username, mfa_enabled]

    TotpSetupRequest:
      type: object
      properties:
        regenerate:
          type: boolean
          default: false

    TotpSetupResponse:
      type: object
      properties:
        ok:
          type: boolean
        username:
          type: string
        totp_secret:
          type: string
        otpauth_uri:
          type: string
      required: [ok, username, totp_secret, otpauth_uri]

    TotpVerifyRequest:
      type: object
      required: [code]
      properties:
        code:
          type: string

    TotpVerifyResponse:
      type: object
      properties:
        ok:
          type: boolean
        username:
          type: string
        mfa_enabled:
          type: boolean
        mfa_verified_at:
          type: string
          format: date-time
      required: [ok, username, mfa_enabled, mfa_verified_at]

    PublishConfigRequest:
      type: object
      required:
        - study_slug
        - study_name
        - config_version_label
        - config
      properties:
        study_slug:
          type: string
          pattern: '^[a-zA-Z0-9_-]+$'
          example: attention-battery-pilot
        study_name:
          type: string
          maxLength: 255
          example: Attention Battery Pilot
        config_version_label:
          type: string
          maxLength: 50
          example: v1
        builder_version:
          type: string
          maxLength: 50
          example: 2026.03.13
        runtime_mode:
          $ref: '#/components/schemas/RuntimeMode'
        config:
          type: object
          additionalProperties: true

    PublishConfigResponse:
      type: object
      properties:
        study_id:
          type: integer
          example: 12
        config_version_id:
          type: integer
          example: 54
        study_slug:
          type: string
          example: attention-battery-pilot
        dashboard_url:
          type: string
          example: /portal/studies/attention-battery-pilot
      required: [study_id, config_version_id, study_slug, dashboard_url]

    StartRunRequest:
      type: object
      required: [study_slug]
      properties:
        study_slug:
          type: string
          example: attention-battery-pilot
        participant_external_id:
          type: string
          nullable: true
          example: participant-001

    StartRunResponse:
      type: object
      properties:
        run_session_id:
          type: string
          format: uuid
        study_slug:
          type: string
        config_version_id:
          type: integer
        config:
          type: object
          additionalProperties: true
        participant_key:
          type: string
          description: Salted SHA-256 pseudonym key.
      required: [run_session_id, study_slug, config_version_id, config, participant_key]

    TrialPayload:
      type: object
      additionalProperties: true
      description: Arbitrary task-specific trial data.

    SubmitResultRequest:
      type: object
      required:
        - run_session_id
        - status
        - trial_count
        - result_payload
      properties:
        run_session_id:
          type: string
          format: uuid
        status:
          $ref: '#/components/schemas/RunStatus'
        trial_count:
          type: integer
          minimum: 0
          example: 240
        result_summary:
          type: object
          additionalProperties: true
        result_payload:
          type: object
          additionalProperties: true
        trials:
          type: array
          items:
            $ref: '#/components/schemas/TrialPayload'
          default: []

    SubmitResultResponse:
      type: object
      properties:
        run_session_id:
          type: string
          format: uuid
        status:
          type: string
        stored:
          type: boolean
          example: true
        trial_records_stored:
          type: integer
          minimum: 0
          example: 240
      required: [run_session_id, status, stored, trial_records_stored]

    DecryptResultRequest:
      type: object
      required: [run_session_id]
      properties:
        run_session_id:
          type: string
          format: uuid
        include_trials:
          type: boolean
          default: false

    DecryptResultResponse:
      type: object
      properties:
        run_session_id:
          type: string
          format: uuid
        study_slug:
          type: string
        status:
          type: string
        result_payload:
          type: object
          additionalProperties: true
        trials:
          nullable: true
          oneOf:
            - type: array
              items:
                type: object
                additionalProperties: true
            - type: 'null'
      required: [run_session_id, study_slug, status, result_payload, trials]

    StudyListItem:
      type: object
      properties:
        study_slug:
          type: string
        study_name:
          type: string
        runtime_mode:
          $ref: '#/components/schemas/RuntimeMode'
        latest_config_version:
          type: string
          nullable: true
        run_count:
          type: integer
          minimum: 0
        last_result_at:
          type: string
          format: date-time
          nullable: true
        last_activity_at:
          type: string
          format: date-time
        dashboard_url:
          type: string
      required:
        - study_slug
        - study_name
        - runtime_mode
        - latest_config_version
        - run_count
        - last_result_at
        - last_activity_at
        - dashboard_url

    StudiesListResponse:
      type: object
      properties:
        studies:
          type: array
          items:
            $ref: '#/components/schemas/StudyListItem'
      required: [studies]

Day 3 Contract Notes

  • POST /api/v1/configs/publish is upsert-safe by study_slug and config_version_label.
  • POST /api/v1/runs/start uses study_slug (not study_id) in v1.
  • POST /api/v1/results/submit supports optional trials[] for per-trial persistence.
  • POST /api/v1/results/decrypt requires user session auth + TOTP MFA verification.
  • Day 3 and onward endpoints are covered by integration tests in backend/project/tests/test_day3_api_contract.py and backend/project/tests/test_day4_integration.py.