openapi: "3.0.3"
info:
  title: QA Copilot API
  version: "1.0.0"
  description: >
    QA Copilot — AI-powered test-generation platform.
    Provides chat, webhook, and agent-based test generation,
    authentication, billing, monitoring, and legal endpoints.

servers:
  - url: http://localhost:5174
    description: Local development server

security:
  - bearerAuth: []

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: JWT token obtained from /api/auth/login
    apiKeyAuth:
      type: apiKey
      in: header
      name: X-Api-Key
      description: Per-user API key for programmatic access

  schemas:
    Error:
      type: object
      properties:
        error:
          type: string

    HealthResponse:
      type: object
      properties:
        status:
          type: string
          example: ok

    LoginRequest:
      type: object
      required: [email, password]
      properties:
        email:
          type: string
          format: email
        password:
          type: string

    TokenResponse:
      type: object
      properties:
        token:
          type: string
        user:
          type: object

    ChatRequest:
      type: object
      required: [message]
      properties:
        message:
          type: string
        model:
          type: string
        provider:
          type: string

    GenerateRequest:
      type: object
      required: [prompt]
      properties:
        prompt:
          type: string
        framework:
          type: string
        model:
          type: string

    JobStatusResponse:
      type: object
      properties:
        job_id:
          type: string
        status:
          type: string
          enum: [pending, running, done, error]
        result:
          type: object

    ContactRequest:
      type: object
      required: [name, email, message]
      properties:
        name:
          type: string
        email:
          type: string
          format: email
        message:
          type: string

    MonitoringStatsResponse:
      type: object
      properties:
        total_requests:
          type: integer
        active_users:
          type: integer

paths:
  # ── Public ───────────────────────────────────────────────
  /api/health:
    get:
      summary: Health check
      security: []
      tags: [Public]
      responses:
        "200":
          description: Server is healthy
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HealthResponse"

  /api/docs:
    get:
      summary: Serve this OpenAPI spec
      security: []
      tags: [Public]
      responses:
        "200":
          description: YAML OpenAPI document
          content:
            text/yaml:
              schema:
                type: string

  /api/legal/{doc}:
    get:
      summary: Serve a legal document (terms, privacy, etc.)
      security: []
      tags: [Public]
      parameters:
        - name: doc
          in: path
          required: true
          schema:
            type: string
            enum: [terms, privacy, acceptable-use, dpa]
      responses:
        "200":
          description: Legal document content
        "404":
          description: Document not found

  # ── Auth ─────────────────────────────────────────────────
  /api/auth/login:
    post:
      summary: Authenticate and receive a JWT token
      security: []
      tags: [Auth]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/LoginRequest"
      responses:
        "200":
          description: Login successful
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TokenResponse"
        "401":
          description: Invalid credentials

  /api/auth/register:
    post:
      summary: Register a new user account
      security: []
      tags: [Auth]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [email, password, name]
              properties:
                email:
                  type: string
                password:
                  type: string
                name:
                  type: string
      responses:
        "201":
          description: Account created
        "409":
          description: Email already registered

  /api/auth/me:
    get:
      summary: Get current authenticated user profile
      tags: [Auth]
      responses:
        "200":
          description: User profile
        "401":
          description: Not authenticated

  /api/auth/forgot-password:
    post:
      summary: Request a password-reset email
      security: []
      tags: [Auth]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [email]
              properties:
                email:
                  type: string
                  format: email
      responses:
        "200":
          description: Reset email sent (always returns 200 to avoid enumeration)

  /api/auth/reset-password:
    post:
      summary: Reset password using a token
      security: []
      tags: [Auth]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [token, password]
              properties:
                token:
                  type: string
                password:
                  type: string
      responses:
        "200":
          description: Password updated
        "400":
          description: Invalid or expired token

  # ── Chat / Generation ────────────────────────────────────
  /api/chat:
    post:
      summary: Send a chat message (non-streaming)
      tags: [Generation]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ChatRequest"
      responses:
        "200":
          description: Chat response

  /api/stream:
    post:
      summary: Send a chat message (SSE streaming)
      tags: [Generation]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ChatRequest"
      responses:
        "200":
          description: Server-sent event stream
          content:
            text/event-stream: {}

  /api/json:
    post:
      summary: Generate structured JSON test output
      tags: [Generation]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/GenerateRequest"
      responses:
        "200":
          description: Structured test-case JSON

  # ── Webhook generation ───────────────────────────────────
  /api/webhook/generate:
    post:
      summary: Trigger async test generation via webhook
      tags: [Webhook]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/GenerateRequest"
      responses:
        "202":
          description: Job accepted
          content:
            application/json:
              schema:
                type: object
                properties:
                  job_id:
                    type: string

  /api/webhook/jobs/{job_id}:
    get:
      summary: Poll webhook job status
      tags: [Webhook]
      parameters:
        - name: job_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Job status
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/JobStatusResponse"
        "404":
          description: Job not found

  /api/webhook/xray-results:
    post:
      summary: Receive Xray test-execution results callback
      tags: [Webhook]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
      responses:
        "200":
          description: Results acknowledged

  # ── Agent generation ─────────────────────────────────────
  /api/agent/generate:
    post:
      summary: Trigger agent-based test generation
      tags: [Agent]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/GenerateRequest"
      responses:
        "202":
          description: Agent job accepted
          content:
            application/json:
              schema:
                type: object
                properties:
                  job_id:
                    type: string

  /api/agent/jobs/{job_id}:
    get:
      summary: Poll agent job status
      tags: [Agent]
      parameters:
        - name: job_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Job status
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/JobStatusResponse"
        "404":
          description: Job not found

  # ── Xray push ───────────────────────────────────────────
  /api/xray-push:
    post:
      summary: Push generated tests to Jira/Xray
      tags: [Integrations]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
      responses:
        "200":
          description: Tests pushed successfully
        "400":
          description: Push failed

  # ── Billing ──────────────────────────────────────────────
  /api/billing/checkout:
    post:
      summary: Create a Stripe checkout session
      tags: [Billing]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                plan:
                  type: string
      responses:
        "200":
          description: Checkout session URL
        "400":
          description: Invalid plan

  # ── Contact ──────────────────────────────────────────────
  /api/contact:
    post:
      summary: Submit a contact-form message
      security: []
      tags: [Public]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ContactRequest"
      responses:
        "200":
          description: Message received

  # ── GDPR ─────────────────────────────────────────────────
  /api/user/data/export:
    get:
      summary: Export all personal data (GDPR)
      tags: [GDPR]
      responses:
        "200":
          description: JSON export of user data (history, stats, contact messages)

  /api/user/data:
    delete:
      summary: Delete all personal data (GDPR)
      tags: [GDPR]
      responses:
        "200":
          description: Data deleted

  # ── Contract Testing ────────────────────────────────────
  /api/contract/generate:
    post:
      summary: Generate API contract tests from OpenAPI spec
      tags: [Generation]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [spec]
              properties:
                spec:
                  type: object
                  description: OpenAPI 3.x spec as JSON
                framework:
                  type: string
                  default: restassured
                provider:
                  type: string
                model:
                  type: string
      responses:
        "200":
          description: Generated contract tests
        "400":
          description: Invalid spec or no endpoints found

  # ── Onboarding ──────────────────────────────────────────
  /api/onboarding:
    get:
      summary: Get onboarding wizard state
      tags: [Onboarding]
      responses:
        "200":
          description: Current step and completion status

  /api/onboarding/complete-step:
    post:
      summary: Mark an onboarding step as complete
      tags: [Onboarding]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                step:
                  type: integer
      responses:
        "200":
          description: Updated onboarding state

  /api/onboarding/skip:
    post:
      summary: Skip the onboarding wizard
      tags: [Onboarding]
      responses:
        "200":
          description: Onboarding marked complete

  # ── Test Runs ───────────────────────────────────────────
  /api/test-runs:
    post:
      summary: Record a test execution run
      tags: [Test Runs]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [project, results]
              properties:
                project:
                  type: string
                suite:
                  type: string
                results:
                  type: array
                  items:
                    type: object
                    required: [name, status, duration_ms]
                    properties:
                      name:
                        type: string
                      status:
                        type: string
                        enum: [passed, failed, skipped]
                      duration_ms:
                        type: integer
                      error:
                        type: string
                      healed:
                        type: boolean
      responses:
        "200":
          description: Run recorded
    get:
      summary: Query test runs (list, trend, flaky, healing)
      tags: [Test Runs]
      parameters:
        - name: project
          in: query
          schema:
            type: string
        - name: action
          in: query
          schema:
            type: string
            enum: [list, trend, flaky, healing]
      responses:
        "200":
          description: Query results

  # ── Workspace ───────────────────────────────────────────
  /api/workspace/share:
    post:
      summary: Share a generation for team review
      tags: [Workspace]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                story_key:
                  type: string
                generated:
                  type: object
                module:
                  type: string
      responses:
        "200":
          description: Generation shared

  /api/workspace/review:
    post:
      summary: Submit a review verdict
      tags: [Workspace]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [gen_id, verdict]
              properties:
                gen_id:
                  type: string
                verdict:
                  type: string
                  enum: [approved, rejected]
                comment:
                  type: string
      responses:
        "200":
          description: Review submitted

  /api/workspace/history:
    get:
      summary: Get shared generation history
      tags: [Workspace]
      responses:
        "200":
          description: List of shared generations

  /api/workspace/pending-reviews:
    get:
      summary: Get generations awaiting review
      tags: [Workspace]
      responses:
        "200":
          description: List of pending reviews

  # ── Performance Results ─────────────────────────────────
  /api/perf-results:
    post:
      summary: Ingest a performance test result
      tags: [Performance]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [tool, scenario, metrics]
              properties:
                tool:
                  type: string
                  enum: [k6, gatling, jmeter]
                scenario:
                  type: string
                metrics:
                  type: object
      responses:
        "200":
          description: Result ingested
    get:
      summary: Query performance results and trends
      tags: [Performance]
      parameters:
        - name: tool
          in: query
          schema:
            type: string
        - name: scenario
          in: query
          schema:
            type: string
        - name: action
          in: query
          schema:
            type: string
            enum: [list, trend]
      responses:
        "200":
          description: Query results

  # ── Visual Regression ───────────────────────────────────
  /api/visual-regression/baseline:
    post:
      summary: Save a screenshot as baseline
      tags: [Visual Regression]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, screenshot_path]
              properties:
                name:
                  type: string
                screenshot_path:
                  type: string
      responses:
        "200":
          description: Baseline saved

  /api/visual-regression/compare:
    post:
      summary: Compare screenshot against baseline
      tags: [Visual Regression]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, screenshot_path]
              properties:
                name:
                  type: string
                screenshot_path:
                  type: string
                threshold:
                  type: number
                  default: 0.5
      responses:
        "200":
          description: Comparison result (match, diff_percent, diff_path)

  # ── Mobile Recorder ─────────────────────────────────────
  /api/mobile/generate:
    post:
      summary: Generate Appium tests from recorded mobile actions
      tags: [Mobile]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [actions]
              properties:
                actions:
                  type: array
                  items:
                    type: object
                    properties:
                      type:
                        type: string
                        enum: [tap, input, swipe, assert]
                      locator:
                        type: string
                      value:
                        type: string
                      description:
                        type: string
                app_name:
                  type: string
                platform:
                  type: string
                  enum: [android, ios]
      responses:
        "200":
          description: Generated mobile test cases

  # ── Monitoring (admin) ───────────────────────────────────
  /api/monitoring/stats:
    get:
      summary: Aggregated platform statistics
      tags: [Monitoring]
      responses:
        "200":
          description: Stats payload
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MonitoringStatsResponse"
        "403":
          description: Admin role required

  /api/monitoring/health:
    get:
      summary: Detailed health of backend services
      tags: [Monitoring]
      responses:
        "200":
          description: Service health map
        "403":
          description: Admin role required
