openapi: 3.0.3
info:
  title: R2Devops Backend API
  description: Complete API specification for R2Devops backend compliance and security platform
  version: 1.0.0
  contact:
    name: R2Devops
    url: https://r2devops.io

servers:
  - url: /api
    description: API base path

tags:
  - name: Health
    description: Health check endpoints
  - name: Metadata
    description: Application metadata
  - name: Authentication
    description: User authentication
  - name: User
    description: User management
  - name: Job
    description: Marketplace job management
  - name: Repo
    description: Repository management
  - name: Project
    description: Project management and compliance
  - name: Analysis
    description: Security analysis operations
  - name: Organization
    description: Organization settings and assets
  - name: Issue
    description: Policy issue management
  - name: Framework
    description: Compliance framework management
  - name: Requirement
    description: Framework requirements
  - name: Control
    description: Security controls
  - name: Label
    description: Label management
  - name: Authorization
    description: Authorization rules
  - name: Portfolio
    description: Portfolio management

security:
  - bearerAuth: []

paths:
  # ==================== HEALTH ENDPOINTS ====================
  /health/alive:
    get:
      tags: [Health]
      summary: Liveness probe
      description: Check if the API is alive
      security: []
      responses:
        '200':
          description: API is alive
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HealthResponse'

  /health/ready:
    get:
      tags: [Health]
      summary: Readiness probe
      description: Check if the API is ready to accept requests
      security: []
      responses:
        '200':
          description: API is ready
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HealthResponse'

  # ==================== METADATA ENDPOINTS ====================
  /metadata:
    get:
      tags: [Metadata]
      summary: Get API metadata
      description: Returns version and metadata information
      security: []
      responses:
        '200':
          description: Metadata retrieved
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MetadataResponse'

  # ==================== AUTHENTICATION ENDPOINTS ====================
  /auth/gitlab/login:
    get:
      tags: [Authentication]
      summary: Initiate GitLab OAuth login
      description: Redirects to GitLab OAuth authorization page
      security: []
      responses:
        '302':
          description: Redirect to GitLab OAuth

  /auth/gitlab/callback:
    get:
      tags: [Authentication]
      summary: GitLab OAuth callback
      description: Handles GitLab OAuth callback
      security: []
      parameters:
        - name: code
          in: query
          schema:
            type: string
        - name: state
          in: query
          schema:
            type: string
      responses:
        '200':
          description: Authentication successful
        '302':
          description: Redirect after authentication

  /auth/logout:
    post:
      tags: [Authentication]
      summary: Logout user
      description: Logout the current user
      responses:
        '200':
          description: Logged out successfully

  # ==================== USER ENDPOINTS ====================
  /user:
    get:
      tags: [User]
      summary: Get current user
      description: Returns information about the authenticated user
      responses:
        '200':
          description: User information
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserResponse'

  /user/invalidateCache:
    post:
      tags: [User]
      summary: Invalidate user cache
      description: Clears cached user data
      responses:
        '200':
          description: Cache invalidated

  # ==================== JOB ENDPOINTS (MARKETPLACE) ====================
  /job:
    get:
      tags: [Job]
      summary: List jobs
      description: Returns a paginated list of marketplace jobs
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
        - name: search
          in: query
          schema:
            type: string
          description: Search term
        - name: labels
          in: query
          schema:
            type: string
          description: Filter by labels (comma-separated)
      responses:
        '200':
          description: List of jobs
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListJobResponse'

  /job/*:
    get:
      tags: [Job]
      summary: Get job by path
      description: Returns a specific job by its path
      parameters:
        - name: '*'
          in: path
          required: true
          schema:
            type: string
          description: Job path (e.g., "namespace/job-name")
      responses:
        '200':
          description: Job details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JobResponse'
        '404':
          $ref: '#/components/responses/NotFound'

  /job/{jobid}/rating:
    get:
      tags: [Job]
      summary: Get job ratings
      description: Returns ratings for a specific job
      parameters:
        - name: jobid
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: List of ratings
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/RatingResponse'

    post:
      tags: [Job]
      summary: Create job rating
      description: Rate a job (up or down)
      parameters:
        - name: jobid
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [value]
              properties:
                value:
                  type: string
                  enum: [up, down]
      responses:
        '201':
          description: Rating created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RatingResponse'

    delete:
      tags: [Job]
      summary: Delete job rating
      description: Remove user's rating for a job
      parameters:
        - name: jobid
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Rating deleted

  # ==================== REPO ENDPOINTS ====================
  /repo:
    get:
      tags: [Repo]
      summary: List repositories
      description: Returns a paginated list of repositories
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
      responses:
        '200':
          description: List of repositories
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListRepoResponse'

    post:
      tags: [Repo]
      summary: Create repository
      description: Add a new repository to track
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [platform, idOnPlatform]
              properties:
                platform:
                  type: string
                  enum: [gitlab]
                idOnPlatform:
                  type: integer
      responses:
        '201':
          description: Repository created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RepoResponse'

  /repo/{repoID}:
    get:
      tags: [Repo]
      summary: Get repository
      description: Returns details of a specific repository
      parameters:
        - name: repoID
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Repository details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RepoResponse'

    patch:
      tags: [Repo]
      summary: Refresh repository
      description: Trigger a repository sync/refresh
      parameters:
        - name: repoID
          in: path
          required: true
          schema:
            type: integer
      responses:
        '202':
          description: Refresh initiated

    delete:
      tags: [Repo]
      summary: Delete repository
      description: Remove a repository from tracking
      parameters:
        - name: repoID
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Repository deleted

  /repo/{repoID}/sync:
    get:
      tags: [Repo]
      summary: Get repository sync history
      description: Returns sync history for a repository
      parameters:
        - name: repoID
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Sync history
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/RepoSyncResponse'

  # ==================== PROJECT ENDPOINTS ====================
  /project:
    get:
      tags: [Project]
      summary: List projects
      description: Returns paginated list of projects with issue counts and compliance
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
        - name: search
          in: query
          schema:
            type: string
          description: Search by project name or path
        - name: projectId
          in: query
          schema:
            type: string
          description: Filter by specific project IDs (JSON array)
        - name: frameworkId
          in: query
          schema:
            type: string
          description: Filter by framework IDs (JSON array)
        - name: portfolioId
          in: query
          schema:
            type: integer
          description: Filter by portfolio ID
        - name: sortField
          in: query
          schema:
            type: string
            enum: [name, issueCount, compliance]
        - name: sortOrder
          in: query
          schema:
            type: string
            enum: [ASC, DESC]
      responses:
        '200':
          description: List of projects
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListProjectResponse'

  /project/{projectId}/compliance:
    get:
      tags: [Project]
      summary: Get project compliance details
      description: Returns detailed compliance information for a project across all frameworks
      parameters:
        - name: projectId
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Project compliance details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProjectComplianceResponse'

  # ==================== ANALYSIS ENDPOINTS ====================
  /analysis:
    get:
      tags: [Analysis]
      summary: List analyses
      description: Returns paginated list of security analyses
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
      responses:
        '200':
          description: List of analyses
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListAnalysisResponse'

  /analysis/run:
    post:
      tags: [Analysis]
      summary: Run security analysis
      description: Trigger a new security analysis for projects
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                projectIds:
                  type: array
                  items:
                    type: integer
                  description: Specific project IDs to analyze (empty for all projects)
      responses:
        '202':
          description: Analysis started
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AnalysisRunResponse'
        '409':
          description: Analysis already running or asset sync in progress

  /analysis/cleanup:
    post:
      tags: [Analysis]
      summary: Trigger analysis cleanup
      description: Clean up old analysis data
      responses:
        '202':
          description: Cleanup initiated

  /analysis/data/gitlabPipelineImage/data/image:
    get:
      tags: [Analysis]
      summary: Get pipeline image data
      description: Returns data grouped by Docker image
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
      responses:
        '200':
          description: Image data

  /analysis/data/gitlabPipelineImage/metrics:
    get:
      tags: [Analysis]
      summary: Get pipeline image metrics
      description: Returns metrics about pipeline images
      responses:
        '200':
          description: Image metrics

  /analysis/data/gitlabVariable/data/variable:
    get:
      tags: [Analysis]
      summary: Get GitLab variable data
      description: Returns data grouped by variable
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
      responses:
        '200':
          description: Variable data

  /analysis/data/gitlabVariable/metrics:
    get:
      tags: [Analysis]
      summary: Get GitLab variable metrics
      description: Returns metrics about GitLab variables
      responses:
        '200':
          description: Variable metrics

  /analysis/data/gitlabCiPlatform/data/project:
    get:
      tags: [Analysis]
      summary: Get CI platform data by project
      description: Returns CI platform data grouped by project
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
      responses:
        '200':
          description: CI platform data

  /analysis/data/gitlabCiPlatform/metrics:
    get:
      tags: [Analysis]
      summary: Get CI platform metrics
      description: Returns CI platform metrics
      responses:
        '200':
          description: CI platform metrics

  /analysis/data/gitlabPipelineOrigin/data/origin:
    get:
      tags: [Analysis]
      summary: Get pipeline origin data
      description: Returns data about pipeline origins
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
      responses:
        '200':
          description: Pipeline origin data

  /analysis/data/gitlabPipelineOrigin/data/hardcodedJob:
    get:
      tags: [Analysis]
      summary: Get hardcoded job data
      description: Returns data about hardcoded jobs in pipelines
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
      responses:
        '200':
          description: Hardcoded job data

  /analysis/data/gitlabPipelineOrigin/metrics:
    get:
      tags: [Analysis]
      summary: Get pipeline origin metrics
      description: Returns pipeline origin metrics
      responses:
        '200':
          description: Pipeline origin metrics

  # ==================== ORGANIZATION ENDPOINTS ====================
  /organization:
    get:
      tags: [Organization]
      summary: Get current organization
      description: Returns organization details, settings, and license information
      responses:
        '200':
          description: Organization details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrganizationResponse'

  /organization/users:
    get:
      tags: [Organization]
      summary: List organization users
      description: Returns all users in the organization
      responses:
        '200':
          description: List of users
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrganizationUsersResponse'

  /organization/settings:
    put:
      tags: [Organization]
      summary: Update organization settings
      description: Update organization settings (AI, notifications, patterns, etc.)
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                settings:
                  $ref: '#/components/schemas/OrganizationSettingsRequest'
      responses:
        '200':
          description: Settings updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrganizationResponse'

  /organization/scheduledAnalysis:
    put:
      tags: [Organization]
      summary: Update scheduled analysis settings
      description: Configure scheduled analysis cron job
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                enabled:
                  type: boolean
                cron:
                  type: string
                  maxLength: 100
                token:
                  type: string
                  maxLength: 100
      responses:
        '200':
          description: Scheduled analysis updated

  /organization/officialCatalogResource:
    put:
      tags: [Organization]
      summary: Update official catalog
      description: Set which projects are part of the official catalog
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [projects]
              properties:
                projects:
                  type: array
                  items:
                    type: integer
      responses:
        '200':
          description: Official catalog updated

  # ==================== ORGANIZATION ASSETS ====================
  /organization/assets/groups:
    get:
      tags: [Organization]
      summary: List organization groups
      description: Returns hierarchical list of groups with project counts
      parameters:
        - name: groupId
          in: query
          schema:
            type: integer
          description: Filter by parent group ID
        - name: search
          in: query
          schema:
            type: string
          description: Search by group name or path
      responses:
        '200':
          description: List of groups
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GroupListResponse'

  /organization/assets/projects:
    get:
      tags: [Organization]
      summary: List organization projects
      description: Returns paginated list of projects with metadata
      parameters:
        - name: groupId
          in: query
          schema:
            type: integer
          description: Filter by group ID
        - name: search
          in: query
          schema:
            type: string
          description: Search by project name or path
        - name: archived
          in: query
          schema:
            type: boolean
          description: Filter archived projects
        - name: cursor
          in: query
          schema:
            type: string
          description: Cursor for pagination
        - name: limit
          in: query
          schema:
            type: integer
            default: 50
          description: Number of results per page
      responses:
        '200':
          description: List of projects
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProjectListResponse'

  /organization/assets/groups/search:
    post:
      tags: [Organization]
      summary: Search organization groups
      description: Advanced search for groups with complex filters
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                groupIds:
                  type: array
                  items:
                    type: integer
                search:
                  type: string
      responses:
        '200':
          description: Filtered groups
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GroupListResponse'

  /organization/assets/projects/search:
    post:
      tags: [Organization]
      summary: Search organization projects
      description: Advanced search for projects with complex filters
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                projectIds:
                  type: array
                  items:
                    type: integer
                search:
                  type: string
                archived:
                  type: boolean
      responses:
        '200':
          description: Filtered projects
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProjectListResponse'

  /organization/assets/sync:
    post:
      tags: [Organization]
      summary: Trigger asset sync
      description: Manually trigger synchronization of assets from GitLab
      responses:
        '202':
          description: Sync initiated
        '409':
          description: Sync already in progress

  /organization/assets/sync/status:
    get:
      tags: [Organization]
      summary: Get asset sync status
      description: Check if asset sync is currently running
      responses:
        '200':
          description: Sync status
          content:
            application/json:
              schema:
                type: object
                properties:
                  running:
                    type: boolean

  /organization/assets/sync/history:
    get:
      tags: [Organization]
      summary: Get asset sync history
      description: Returns history of past synchronizations
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
      responses:
        '200':
          description: Sync history
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AssetSyncListResponse'

  # ==================== PORTFOLIO ENDPOINTS ====================
  /organization/assets/portfolio:
    get:
      tags: [Portfolio]
      summary: List portfolios
      description: Returns all portfolios for the organization
      responses:
        '200':
          description: List of portfolios
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/PortfolioResponse'

    post:
      tags: [Portfolio]
      summary: Create portfolio
      description: Create a new portfolio
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PortfolioCreateRequest'
      responses:
        '201':
          description: Portfolio created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PortfolioResponse'

  /organization/assets/portfolio/{portfolioId}:
    get:
      tags: [Portfolio]
      summary: Get portfolio details
      description: Returns details of a specific portfolio
      parameters:
        - name: portfolioId
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Portfolio details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PortfolioDetailResponse'

    put:
      tags: [Portfolio]
      summary: Update portfolio
      description: Update portfolio details and assignments
      parameters:
        - name: portfolioId
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PortfolioUpdateRequest'
      responses:
        '200':
          description: Portfolio updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PortfolioResponse'

    delete:
      tags: [Portfolio]
      summary: Delete portfolio
      description: Delete a portfolio
      parameters:
        - name: portfolioId
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Portfolio deleted

  # ==================== AUTHORIZATION ENDPOINTS ====================
  /organization/authorization/group:
    get:
      tags: [Authorization]
      summary: List authorization groups
      description: Returns GitLab groups authorized for access
      responses:
        '200':
          description: List of authorized groups
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/AuthorizationGitlabGroupResponse'

    post:
      tags: [Authorization]
      summary: Create authorization group
      description: Add a GitLab group to authorization rules
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [groupId]
              properties:
                groupId:
                  type: integer
      responses:
        '201':
          description: Authorization created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthorizationGitlabGroupResponse'

  /organization/authorization/group/{authorizationGitlabGroupId}:
    delete:
      tags: [Authorization]
      summary: Delete authorization group
      description: Remove a GitLab group from authorization rules
      parameters:
        - name: authorizationGitlabGroupId
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Authorization deleted

  # ==================== ISSUE ENDPOINTS ====================
  /issue:
    get:
      tags: [Issue]
      summary: List policy issues
      description: Returns paginated list of policy issues with filtering and sorting
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
        - name: issueTypeId
          in: query
          schema:
            type: string
          description: Filter by issue type IDs (JSON array)
        - name: statusId
          in: query
          schema:
            type: integer
          description: Filter by status ID
        - name: projectId
          in: query
          schema:
            type: string
          description: Filter by project IDs (JSON array)
        - name: groupId
          in: query
          schema:
            type: string
          description: Filter by group IDs (JSON array)
        - name: ownerId
          in: query
          schema:
            type: integer
          description: Filter by owner user ID
        - name: fixDurationId
          in: query
          schema:
            type: integer
          description: Filter by fix duration ID
        - name: severityId
          in: query
          schema:
            type: integer
          description: Filter by severity ID
        - name: fixable
          in: query
          schema:
            type: boolean
          description: Filter by fixable issues
        - name: controlId
          in: query
          schema:
            type: integer
          description: Filter by control ID
        - name: requirementId
          in: query
          schema:
            type: integer
          description: Filter by requirement ID
        - name: frameworkId
          in: query
          schema:
            type: string
          description: Filter by framework IDs (JSON array)
        - name: portfolioId
          in: query
          schema:
            type: integer
          description: Filter by portfolio ID
        - name: search
          in: query
          schema:
            type: string
          description: Search in issue data
        - name: sortField
          in: query
          schema:
            type: string
            enum: [createdAt, updatedAt]
        - name: sortOrder
          in: query
          schema:
            type: string
            enum: [ASC, DESC]
      responses:
        '200':
          description: List of issues
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListPolicyIssueResponse'

  /issue/chart:
    get:
      tags: [Issue]
      summary: Get issues chart data
      description: Returns time-series data for issue trends
      parameters:
        - name: frameworkId
          in: query
          schema:
            type: string
          description: Filter by framework IDs (JSON array)
        - name: days
          in: query
          schema:
            type: integer
            default: 30
          description: Number of days for chart
      responses:
        '200':
          description: Chart data
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IssueChartResponse'

  /issue/type:
    get:
      tags: [Issue]
      summary: Get issues grouped by type
      description: Returns issue counts grouped by type
      parameters:
        - name: frameworkId
          in: query
          schema:
            type: string
          description: Filter by framework IDs (JSON array)
        - name: projectId
          in: query
          schema:
            type: string
          description: Filter by project IDs (JSON array)
      responses:
        '200':
          description: Issues grouped by type
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/IssueTypeWithCountResponse'

  /issue/fixDuration:
    get:
      tags: [Issue]
      summary: List fix durations
      description: Returns available fix duration categories
      responses:
        '200':
          description: Fix durations
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FixDurationListResponse'

  /issue/severity:
    get:
      tags: [Issue]
      summary: List severities
      description: Returns available severity levels
      responses:
        '200':
          description: Severities
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SeverityListResponse'

  /issue/owner:
    put:
      tags: [Issue]
      summary: Update issue owner
      description: Assign or remove owner from issues
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [issueIds]
              properties:
                issueIds:
                  type: array
                  items:
                    type: integer
                ownerId:
                  type: integer
                  description: User ID to assign (0 to remove owner)
      responses:
        '200':
          description: Owner updated

  /issue/status:
    post:
      tags: [Issue]
      summary: Create issue status move
      description: Change status and/or add comment to issues
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [issueIds]
              properties:
                issueIds:
                  type: array
                  items:
                    type: integer
                statusId:
                  type: integer
                  description: New status ID (optional if only adding comment)
                comment:
                  type: string
                  maxLength: 1000
      responses:
        '200':
          description: Status updated
          content:
            application/json:
              schema:
                type: object
                properties:
                  updatedCount:
                    type: integer

  /issue/fix:
    post:
      tags: [Issue]
      summary: Trigger fix
      description: Trigger automated fix for issues
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: array
              items:
                type: object
                required: [issueId]
                properties:
                  issueId:
                    type: integer
                  inputs:
                    type: object
                    additionalProperties: true
      responses:
        '202':
          description: Fix triggered
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TriggerFixResponse'

  /issue/cleanup/r2devops:
    delete:
      tags: [Issue]
      summary: Cleanup R2Devops issues
      description: Clean up internal R2Devops issues
      responses:
        '200':
          description: Cleanup completed

  # ==================== FRAMEWORK ENDPOINTS ====================
  /framework:
    get:
      tags: [Framework]
      summary: List frameworks
      description: Returns all compliance frameworks for the organization
      parameters:
        - name: compliance
          in: query
          schema:
            type: boolean
            default: false
          description: Calculate compliance scores (slower)
        - name: sortField
          in: query
          schema:
            type: string
            enum: [name, compliance]
        - name: sortOrder
          in: query
          schema:
            type: string
            enum: [ASC, DESC]
      responses:
        '200':
          description: List of frameworks
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ListFrameworkBasicResponse'
                  - $ref: '#/components/schemas/ListFrameworkResponse'

    post:
      tags: [Framework]
      summary: Create framework
      description: Create a new compliance framework
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/FrameworkCreateRequest'
      responses:
        '201':
          description: Framework created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FrameworkResponse'

  /framework/bulk:
    post:
      tags: [Framework]
      summary: Create framework with requirements and controls
      description: Create a complete framework structure in one request
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/FrameworkBulkCreateRequest'
      responses:
        '201':
          description: Framework created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FrameworkResponse'

  /framework/compliance/history:
    get:
      tags: [Framework]
      summary: Get compliance history for all frameworks
      description: Returns time-series compliance data for all frameworks
      parameters:
        - name: days
          in: query
          schema:
            type: integer
            default: 30
      responses:
        '200':
          description: Compliance history
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FrameworkComplianceHistoryResponse'

  /framework/{frameworkId}:
    get:
      tags: [Framework]
      summary: Get framework details
      description: Returns details of a specific framework
      parameters:
        - name: frameworkId
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Framework details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FrameworkResponse'

    put:
      tags: [Framework]
      summary: Update framework
      description: Update framework details
      parameters:
        - name: frameworkId
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/FrameworkUpdateRequest'
      responses:
        '200':
          description: Framework updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FrameworkResponse'

    delete:
      tags: [Framework]
      summary: Delete framework
      description: Delete a framework (initiates async deletion)
      parameters:
        - name: frameworkId
          in: path
          required: true
          schema:
            type: integer
      responses:
        '202':
          description: Deletion initiated

  /framework/{frameworkId}/compliance:
    get:
      tags: [Framework]
      summary: Get framework compliance details
      description: Returns detailed compliance with all requirements and controls
      parameters:
        - name: frameworkId
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Framework compliance details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FrameworkComplianceResponse'

  /framework/{frameworkId}/compliance/history:
    get:
      tags: [Framework]
      summary: Get single framework compliance history
      description: Returns time-series compliance data for a specific framework
      parameters:
        - name: frameworkId
          in: path
          required: true
          schema:
            type: integer
        - name: days
          in: query
          schema:
            type: integer
            default: 30
      responses:
        '200':
          description: Compliance history
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SingleFrameworkComplianceHistoryResponse'

  # ==================== REQUIREMENT ENDPOINTS ====================
  /framework/{frameworkId}/requirement:
    post:
      tags: [Requirement]
      summary: Create requirement
      description: Add a new requirement to a framework
      parameters:
        - name: frameworkId
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RequirementCreateRequest'
      responses:
        '201':
          description: Requirement created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RequirementResponse'

  /requirement/{requirementId}:
    put:
      tags: [Requirement]
      summary: Update requirement
      description: Update requirement details
      parameters:
        - name: requirementId
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RequirementUpdateRequest'
      responses:
        '200':
          description: Requirement updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RequirementResponse'

    delete:
      tags: [Requirement]
      summary: Delete requirement
      description: Delete a requirement (initiates async deletion)
      parameters:
        - name: requirementId
          in: path
          required: true
          schema:
            type: integer
      responses:
        '202':
          description: Deletion initiated

  # ==================== CONTROL ENDPOINTS ====================
  /controlTypes:
    get:
      tags: [Control]
      summary: List control types
      description: Returns available control types for creating controls
      responses:
        '200':
          description: Control types
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/ControlTypeResponse'

  /framework/{frameworkId}/requirement/{requirementId}/control:
    post:
      tags: [Control]
      summary: Create control
      description: Add a new control to a requirement
      parameters:
        - name: frameworkId
          in: path
          required: true
          schema:
            type: integer
        - name: requirementId
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ControlCreateRequest'
      responses:
        '201':
          description: Control created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ControlResponse'

  /control/{controlId}:
    put:
      tags: [Control]
      summary: Update control
      description: Update control configuration
      parameters:
        - name: controlId
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ControlUpdateRequest'
      responses:
        '200':
          description: Control updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ControlResponse'

    delete:
      tags: [Control]
      summary: Delete control
      description: Delete a control (initiates async deletion)
      parameters:
        - name: controlId
          in: path
          required: true
          schema:
            type: integer
      responses:
        '202':
          description: Deletion initiated

  /control/{controlId}/compliance:
    get:
      tags: [Control]
      summary: Get control compliance
      description: Returns compliance details for a control across all assets
      parameters:
        - name: controlId
          in: path
          required: true
          schema:
            type: integer
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
      responses:
        '200':
          description: Control compliance details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ControlComplianceResponse'

  /control/{controlId}/compliance/summary:
    get:
      tags: [Control]
      summary: Get control compliance summary
      description: Returns aggregated compliance summary for a control
      parameters:
        - name: controlId
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Control compliance summary
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ControlComplianceSummaryResponse'

  # ==================== LABEL ENDPOINTS ====================
  /label:
    get:
      tags: [Label]
      summary: List labels
      description: Returns all available labels
      responses:
        '200':
          description: List of labels
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListLabelResponse'

    post:
      tags: [Label]
      summary: Create label
      description: Create a new label
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name]
              properties:
                name:
                  type: string
                  maxLength: 50
      responses:
        '201':
          description: Label created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LabelResponse'

  /label/{labelName}:
    delete:
      tags: [Label]
      summary: Delete label
      description: Delete a label
      parameters:
        - name: labelName
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Label deleted

# ==================== COMPONENTS ====================
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

  parameters:
    PageParam:
      name: page
      in: query
      schema:
        type: integer
        minimum: 1
        default: 1
      description: Page number for pagination

    PerPageParam:
      name: per_page
      in: query
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 20
      description: Number of items per page

  responses:
    BadRequest:
      description: Bad request - Invalid parameters
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'

    Unauthorized:
      description: Unauthorized - Authentication required
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'

    Forbidden:
      description: Forbidden - Insufficient permissions
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'

    NotFound:
      description: Not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'

    Conflict:
      description: Conflict - Resource already exists or operation not allowed
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'

    InternalServerError:
      description: Internal server error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'

  schemas:
    # ==================== COMMON SCHEMAS ====================
    ErrorResponse:
      type: object
      properties:
        error:
          type: string

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

    MetadataResponse:
      type: object
      properties:
        version:
          type: string

    # ==================== USER SCHEMAS ====================
    UserResponse:
      type: object
      properties:
        id:
          type: integer
        gitlabId:
          type: integer
        name:
          type: string
        email:
          type: string
        avatarURL:
          type: string
        accessToken:
          type: string
        accessTokenExpiration:
          type: string
          format: date-time
        role:
          type: integer
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time

    UserWithoutTokenResponse:
      type: object
      properties:
        id:
          type: integer
        gitlabId:
          type: integer
        name:
          type: string
        email:
          type: string
        avatarURL:
          type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time

    # ==================== ORGANIZATION SCHEMAS ====================
    OrganizationResponse:
      type: object
      properties:
        id:
          type: integer
        type:
          type: string
        groupPath:
          type: string
        groupPathId:
          type: integer
        scheduledAnalysisEnabled:
          type: boolean
        scheduledAnalysisCron:
          type: string
        settings:
          $ref: '#/components/schemas/OrganizationSettingsResponse'
        license:
          $ref: '#/components/schemas/OrganizationLicenseResponse'
        hasToken:
          type: boolean

    OrganizationSettingsResponse:
      type: object
      properties:
        issueAutoAssignEnabled:
          type: boolean
        aiEnabled:
          type: boolean
        aiStandard:
          type: string
          enum: [openai, bedrock]
        aiEndpoint:
          type: string
        aiModel:
          type: string
        aiModelLight:
          type: string
        aiBedrockRegion:
          type: string
        aiBedrockModel:
          type: string
        aiBedrockModelLight:
          type: string
        commitPattern:
          type: string
        branchNamePattern:
          type: string
        enableProjectMRNotification:
          type: boolean
        enableProjectIssue:
          type: boolean
        enableProjectBadge:
          type: boolean

    OrganizationSettingsRequest:
      type: object
      properties:
        issueAutoAssignEnabled:
          type: boolean
        aiEnabled:
          type: boolean
        aiStandard:
          type: string
          enum: [openai, bedrock]
        aiEndpoint:
          type: string
        aiModel:
          type: string
        aiModelLight:
          type: string
        aiApiKey:
          type: string
        aiBedrockRegion:
          type: string
        aiBedrockModel:
          type: string
        aiBedrockModelLight:
          type: string
        aiBedrockAccessKeyID:
          type: string
        aiBedrockSecretAccessKey:
          type: string
        aiBedrockSessionToken:
          type: string
        commitPattern:
          type: string
        branchNamePattern:
          type: string
        license:
          type: string
        enableProjectMRNotification:
          type: boolean
        enableProjectIssue:
          type: boolean
        enableProjectBadge:
          type: boolean

    OrganizationLicenseResponse:
      type: object
      properties:
        owner:
          type: string
        projectLimit:
          type: integer
        currentProjectUsage:
          type: integer
        currentProjectUsageIDs:
          type: array
          items:
            type: integer
        expiresAt:
          type: string

    OrganizationUsersResponse:
      type: object
      properties:
        users:
          type: array
          items:
            $ref: '#/components/schemas/UserWithoutTokenResponse'

    AuthorizationGitlabGroupResponse:
      type: object
      properties:
        id:
          type: integer
        groupId:
          type: integer
        level:
          type: integer
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time

    # ==================== JOB SCHEMAS ====================
    JobResponse:
      type: object
      properties:
        id:
          type: integer
        repo:
          $ref: '#/components/schemas/RepoResponse'
        path:
          type: string
        description:
          type: string
        deprecated:
          type: boolean
        icon:
          type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        labels:
          type: array
          items:
            type: string
        rateUp:
          type: integer
        rateDown:
          type: integer
        license:
          type: string
        readToken:
          type: string
        versions:
          type: array
          items:
            $ref: '#/components/schemas/VersionJobResponse'

    ListJobResponse:
      type: object
      properties:
        count:
          type: integer
        jobs:
          type: array
          items:
            $ref: '#/components/schemas/JobResponse'

    VersionJobResponse:
      type: object
      properties:
        tag:
          type: string
        gitTag:
          type: string
        confPath:
          type: string
        readmePath:
          type: string
        changelogPath:
          type: string
        stages:
          type: array
          items:
            type: string
        images:
          type: array
          items:
            type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time

    # ==================== REPO SCHEMAS ====================
    RepoResponse:
      type: object
      properties:
        id:
          type: integer
        path:
          type: string
        namespace:
          type: string
        name:
          type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        platform:
          type: string
        idOnPlatform:
          type: integer
        tier:
          type: string
        defaultBranch:
          type: string
        visibility:
          type: string
        ciConfPath:
          type: string
        lastActivityAt:
          type: string
          format: date-time

    ListRepoResponse:
      type: object
      properties:
        count:
          type: integer
        repos:
          type: array
          items:
            $ref: '#/components/schemas/RepoResponse'

    RepoSyncResponse:
      type: object
      properties:
        id:
          type: integer
        repoId:
          type: integer
        templateFileAmount:
          type: integer
        createdAt:
          type: string
          format: date-time
        analyze:
          type: array
          items:
            type: object

    RatingResponse:
      type: object
      properties:
        id:
          type: integer
        jobID:
          type: integer
        userName:
          type: string
        value:
          type: boolean
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time

    # ==================== PROJECT SCHEMAS ====================
    ListProjectResponse:
      type: object
      properties:
        count:
          type: integer
        projects:
          type: array
          items:
            $ref: '#/components/schemas/ProjectWithIssueCountResponse'
        page:
          type: integer
        perPage:
          type: integer

    ProjectWithIssueCountResponse:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        path:
          type: string
        gitlabId:
          type: integer
        groupIds:
          type: array
          items:
            type: integer
        visibility:
          type: string
        defaultBranch:
          type: string
        ciConfPath:
          type: string
        lastActivityAt:
          type: string
        archived:
          type: boolean
        issueCount:
          type: integer
        compliance:
          type: number
          format: float
          nullable: true

    ProjectComplianceResponse:
      type: object
      properties:
        project:
          $ref: '#/components/schemas/ProjectInfoResponse'
        frameworks:
          type: array
          items:
            $ref: '#/components/schemas/FrameworkInfoResponse'

    ProjectInfoResponse:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        path:
          type: string
        gitlabId:
          type: integer
        groupIdOnPlatform:
          type: integer
        visibility:
          type: string
        defaultBranch:
          type: string
        ciConfPath:
          type: string
        lastActivityAt:
          type: string
        archived:
          type: boolean
        issueCount:
          type: integer
        compliance:
          type: number
          format: float
          nullable: true

    # ==================== ANALYSIS SCHEMAS ====================
    ListAnalysisResponse:
      type: object
      properties:
        count:
          type: integer
        analyses:
          type: array
          items:
            $ref: '#/components/schemas/AnalysisResponse'

    AnalysisResponse:
      type: object
      properties:
        id:
          type: integer
        organizationId:
          type: integer
        done:
          type: boolean
        failed:
          type: boolean
        scheduled:
          type: boolean
        version:
          type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        totalAssets:
          type: integer
        remainingAssets:
          type: integer
        assets:
          type: object
          properties:
            projects:
              type: array
              items:
                type: integer
            groups:
              type: array
              items:
                type: integer

    AnalysisRunResponse:
      type: object
      properties:
        projectIds:
          type: array
          items:
            type: integer

    # ==================== ISSUE SCHEMAS ====================
    ListPolicyIssueResponse:
      type: object
      properties:
        count:
          type: integer
        issues:
          type: array
          items:
            $ref: '#/components/schemas/PolicyIssueResponse'

    PolicyIssueResponse:
      type: object
      properties:
        id:
          type: integer
        project:
          $ref: '#/components/schemas/OrganizationProjectResponse'
        group:
          $ref: '#/components/schemas/OrganizationGroupResponse'
        type:
          $ref: '#/components/schemas/PolicyIssueTypeResponse'
        control:
          $ref: '#/components/schemas/PolicyIssueControlResponse'
        data:
          type: object
        owner:
          $ref: '#/components/schemas/UserWithoutTokenResponse'
          nullable: true
        statusMoves:
          type: array
          items:
            $ref: '#/components/schemas/PolicyIssueStatusMoveResponse'
        fixes:
          type: array
          items:
            $ref: '#/components/schemas/FixResponse'
        analysisInProgress:
          type: boolean
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time

    PolicyIssueTypeResponse:
      type: object
      properties:
        id:
          type: integer
        description:
          type: string
        fixDuration:
          $ref: '#/components/schemas/FixDurationResponse'
          nullable: true
        severity:
          $ref: '#/components/schemas/SeverityResponse'
          nullable: true

    PolicyIssueControlResponse:
      type: object
      properties:
        id:
          type: integer
        requirement:
          $ref: '#/components/schemas/PolicyIssueRequirementResponse'

    PolicyIssueRequirementResponse:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        framework:
          $ref: '#/components/schemas/PolicyIssueFrameworkResponse'

    PolicyIssueFrameworkResponse:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        color:
          type: string

    PolicyIssueStatusMoveResponse:
      type: object
      properties:
        id:
          type: integer
        user:
          $ref: '#/components/schemas/UserWithoutTokenResponse'
        status:
          type: object
          properties:
            id:
              type: integer
            name:
              type: string
        comment:
          type: string
        createdAt:
          type: string
          format: date-time

    FixResponse:
      type: object
      properties:
        id:
          type: integer
        issueId:
          type: integer
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        version:
          type: string
        done:
          type: boolean
        failed:
          type: boolean
        error:
          type: string
        inputs:
          type: object
        outputs:
          type: object

    TriggerFixResponse:
      type: object
      properties:
        triggeredIds:
          type: array
          items:
            type: integer
        notTriggeredIds:
          type: array
          items:
            type: integer

    IssueChartResponse:
      type: object
      properties:
        chart:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
              color:
                type: string
              data:
                type: array
                items:
                  type: object
                  properties:
                    x:
                      type: string
                    y:
                      type: number

    IssueTypeWithCountResponse:
      type: object
      properties:
        policyIssueTypeId:
          type: integer
        policyIssueTypeDescription:
          type: string
        issueCount:
          type: integer

    FixDurationResponse:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        description:
          type: string
        order:
          type: integer

    FixDurationListResponse:
      type: object
      properties:
        fixDurations:
          type: array
          items:
            $ref: '#/components/schemas/FixDurationResponse'

    SeverityResponse:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        description:
          type: string
        level:
          type: integer

    SeverityListResponse:
      type: object
      properties:
        severities:
          type: array
          items:
            $ref: '#/components/schemas/SeverityResponse'

    # ==================== FRAMEWORK SCHEMAS ====================
    ListFrameworkBasicResponse:
      type: object
      properties:
        count:
          type: integer
        deletionTimeout:
          type: integer
          description: Deletion timeout in seconds
        frameworks:
          type: array
          items:
            $ref: '#/components/schemas/FrameworkBasicResponse'

    ListFrameworkResponse:
      type: object
      properties:
        count:
          type: integer
        frameworks:
          type: array
          items:
            $ref: '#/components/schemas/FrameworkResponse'

    FrameworkBasicResponse:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        description:
          type: string
        color:
          type: string
        status:
          type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        requirements:
          type: array
          items:
            $ref: '#/components/schemas/RequirementResponse'
        projectIds:
          type: array
          items:
            type: integer
        groupIds:
          type: array
          items:
            type: integer
        portfolioIds:
          type: array
          items:
            type: integer

    FrameworkResponse:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        description:
          type: string
        color:
          type: string
        status:
          type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        requirements:
          type: array
          items:
            $ref: '#/components/schemas/RequirementResponse'
        projectIds:
          type: array
          items:
            type: integer
        groupIds:
          type: array
          items:
            type: integer
        portfolioIds:
          type: array
          items:
            type: integer
        compliance:
          type: number
          format: float

    FrameworkComplianceResponse:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        description:
          type: string
        color:
          type: string
        status:
          type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        requirements:
          type: array
          items:
            $ref: '#/components/schemas/RequirementComplianceResponse'
        projectIds:
          type: array
          items:
            type: integer
        groupIds:
          type: array
          items:
            type: integer
        portfolioIds:
          type: array
          items:
            type: integer
        compliance:
          type: number
          format: float

    FrameworkInfoResponse:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        description:
          type: string
        color:
          type: string
        status:
          type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        compliance:
          type: number
          format: float
        requirements:
          type: array
          items:
            $ref: '#/components/schemas/RequirementInfoResponse'

    FrameworkCreateRequest:
      type: object
      required:
        - name
        - color
      properties:
        name:
          type: string
          maxLength: 100
        description:
          type: string
          maxLength: 2000
        color:
          type: string
          maxLength: 20
          pattern: '^#[0-9A-Fa-f]{6}$'
        projectIds:
          type: array
          items:
            type: integer
        groupIds:
          type: array
          items:
            type: integer
        portfolioIds:
          type: array
          items:
            type: integer

    FrameworkUpdateRequest:
      type: object
      properties:
        name:
          type: string
          maxLength: 1000
        description:
          type: string
          maxLength: 20000
        color:
          type: string
          maxLength: 20
          pattern: '^#[0-9A-Fa-f]{6}$'
        projectIds:
          type: array
          items:
            type: integer
        groupIds:
          type: array
          items:
            type: integer
        portfolioIds:
          type: array
          items:
            type: integer

    FrameworkBulkCreateRequest:
      type: object
      required:
        - name
        - requirements
      properties:
        name:
          type: string
          maxLength: 100
        description:
          type: string
          maxLength: 2000
        color:
          type: string
          maxLength: 20
          pattern: '^#[0-9A-Fa-f]{6}$'
        projectIds:
          type: array
          items:
            type: integer
        groupIds:
          type: array
          items:
            type: integer
        portfolioIds:
          type: array
          items:
            type: integer
        requirements:
          type: array
          items:
            type: object
            required:
              - name
              - controls
            properties:
              name:
                type: string
                maxLength: 100
              description:
                type: string
                maxLength: 2000
              controls:
                type: array
                items:
                  type: object
                  required:
                    - controlTypeId
                  properties:
                    controlTypeId:
                      type: integer
                    configuration:
                      type: object

    FrameworkComplianceHistoryResponse:
      type: object
      properties:
        chart:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
              color:
                type: string
              data:
                type: array
                items:
                  type: object
                  properties:
                    x:
                      type: string
                    y:
                      type: number

    SingleFrameworkComplianceHistoryResponse:
      type: object
      properties:
        frameworkId:
          type: integer
        name:
          type: string
        color:
          type: string
        chart:
          type: array
          items:
            type: object
            properties:
              x:
                type: string
              y:
                type: number

    # ==================== REQUIREMENT SCHEMAS ====================
    RequirementResponse:
      type: object
      properties:
        id:
          type: integer
        frameworkId:
          type: integer
        name:
          type: string
        description:
          type: string
        status:
          type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        controls:
          type: array
          items:
            $ref: '#/components/schemas/ControlResponse'

    RequirementComplianceResponse:
      type: object
      properties:
        id:
          type: integer
        frameworkId:
          type: integer
        name:
          type: string
        description:
          type: string
        status:
          type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        controls:
          type: array
          items:
            $ref: '#/components/schemas/ControlComplianceResponse'
        compliance:
          type: number
          format: float

    RequirementInfoResponse:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        description:
          type: string
        status:
          type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        compliance:
          type: number
          format: float
        controls:
          type: array
          items:
            $ref: '#/components/schemas/ControlInfoResponse'

    RequirementCreateRequest:
      type: object
      required:
        - name
      properties:
        name:
          type: string
          maxLength: 2000
        description:
          type: string
          maxLength: 20000

    RequirementUpdateRequest:
      type: object
      properties:
        name:
          type: string
          maxLength: 2000
        description:
          type: string
          maxLength: 20000

    # ==================== CONTROL SCHEMAS ====================
    ControlResponse:
      type: object
      properties:
        id:
          type: integer
        controlTypeId:
          type: integer
        requirementId:
          type: integer
        status:
          type: string
        configuration:
          type: object
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        controlType:
          $ref: '#/components/schemas/ControlTypeResponse'

    ControlComplianceResponse:
      type: object
      properties:
        control:
          $ref: '#/components/schemas/ControlResponse'
        summary:
          $ref: '#/components/schemas/ControlComplianceSummaryDataResponse'
          nullable: true
        totalAssets:
          type: integer
        page:
          type: integer
        perPage:
          type: integer
        assets:
          type: array
          items:
            $ref: '#/components/schemas/AssetComplianceResponse'

    ControlComplianceSummaryResponse:
      type: object
      properties:
        control:
          $ref: '#/components/schemas/ControlResponse'
        summary:
          $ref: '#/components/schemas/ControlComplianceSummaryDataResponse'

    ControlComplianceSummaryDataResponse:
      type: object
      properties:
        projectsCompliant:
          type: integer
        projectsPartialCompliant:
          type: integer
        projectsNonCompliant:
          type: integer
        projectsCIMissing:
          type: integer
        projectsCIInvalid:
          type: integer
        projectsArchived:
          type: integer

    ControlInfoResponse:
      type: object
      properties:
        id:
          type: integer
        controlTypeId:
          type: integer
        controlType:
          $ref: '#/components/schemas/ControlTypeResponse'
        status:
          type: string
        version:
          type: string
        configuration:
          type: object
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        compliance:
          type: number
          format: float
        error:
          type: string
        data:
          type: object
        metrics:
          type: object

    AssetComplianceResponse:
      type: object
      properties:
        type:
          type: string
          enum: [project, group]
        id:
          type: integer
        name:
          type: string
        path:
          type: string
        gitlabId:
          type: integer
        groupIdOnPlatform:
          type: integer
        visibility:
          type: string
        compliance:
          type: number
          format: float
          nullable: true
        controlVersion:
          type: string
        error:
          type: string
        data:
          type: object
        metrics:
          type: object
        defaultBranch:
          type: string
        ciConfPath:
          type: string
        lastActivityAt:
          type: string
        archived:
          type: boolean

    ControlTypeResponse:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        description:
          type: string
        project:
          type: boolean
        group:
          type: boolean
        version:
          type: string

    ControlCreateRequest:
      type: object
      required:
        - controlTypeId
      properties:
        controlTypeId:
          type: integer
        configuration:
          type: object

    ControlUpdateRequest:
      type: object
      properties:
        controlTypeId:
          type: integer
        configuration:
          type: object

    # ==================== LABEL SCHEMAS ====================
    LabelResponse:
      type: object
      properties:
        name:
          type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        displayed:
          type: boolean

    ListLabelResponse:
      type: object
      properties:
        count:
          type: integer
        labels:
          type: array
          items:
            $ref: '#/components/schemas/LabelResponse'

    # ==================== ASSET SCHEMAS ====================
    OrganizationProjectResponse:
      type: object
      properties:
        id:
          type: integer
        idOnPlatform:
          type: integer
        groupIdOnPlatform:
          type: integer
        path:
          type: string
        name:
          type: string
        visibility:
          type: string
        defaultBranch:
          type: string
        ciConfPath:
          type: string
        lastActivityAt:
          type: string
          format: date-time
        archived:
          type: boolean
        isCatalogResource:
          type: boolean
        isOfficialCatalogResource:
          type: boolean
        latestHeadCommitSha:
          type: string
        languages:
          type: array
          items:
            type: object
            properties:
              name:
                type: string
              percentage:
                type: number

    OrganizationGroupResponse:
      type: object
      properties:
        id:
          type: integer
        idOnPlatform:
          type: integer
        groupIdOnPlatform:
          type: integer
        path:
          type: string
        name:
          type: string
        visibility:
          type: string

    GroupListResponse:
      type: object
      properties:
        groups:
          type: array
          items:
            type: object
            properties:
              id:
                type: integer
              idOnPlatform:
                type: integer
              groupIds:
                type: array
                items:
                  type: integer
              path:
                type: string
              name:
                type: string
              visibility:
                type: string
              projectCount:
                type: integer
              subGroupCount:
                type: integer
              lastSeenAt:
                type: string
                format: date-time
                nullable: true
              groupCreatedAt:
                type: string
                format: date-time
              createdAt:
                type: string
                format: date-time
              updatedAt:
                type: string
                format: date-time

    ProjectListResponse:
      type: object
      properties:
        projects:
          type: array
          items:
            type: object
            properties:
              id:
                type: integer
              idOnPlatform:
                type: integer
              groupIds:
                type: array
                items:
                  type: integer
              path:
                type: string
              name:
                type: string
              visibility:
                type: string
              defaultBranch:
                type: string
              ciConfPath:
                type: string
              lastActivityAt:
                type: string
                format: date-time
              archived:
                type: boolean
              isCatalogResource:
                type: boolean
              isOfficialCatalogResource:
                type: boolean
              latestHeadCommitSha:
                type: string
              languages:
                type: array
                items:
                  type: object
              lastSeenAt:
                type: string
                format: date-time
                nullable: true
              projectCreatedAt:
                type: string
                format: date-time
              createdAt:
                type: string
                format: date-time
              updatedAt:
                type: string
                format: date-time
        nextCursor:
          type: string
        hasMore:
          type: boolean

    AssetSyncListResponse:
      type: object
      properties:
        count:
          type: integer
        syncs:
          type: array
          items:
            type: object
            properties:
              id:
                type: integer
              organizationId:
                type: integer
              done:
                type: boolean
              failed:
                type: boolean
              scheduled:
                type: boolean
              projectCount:
                type: integer
              groupCount:
                type: integer
              startedAt:
                type: string
                format: date-time
                nullable: true
              completedAt:
                type: string
                format: date-time
                nullable: true
              errorMessage:
                type: string
              version:
                type: string
              createdAt:
                type: string
                format: date-time
              updatedAt:
                type: string
                format: date-time

    # ==================== PORTFOLIO SCHEMAS ====================
    PortfolioResponse:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        color:
          type: string
        groupIds:
          type: array
          items:
            type: integer
        projectIds:
          type: array
          items:
            type: integer

    PortfolioDetailResponse:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        color:
          type: string
        groupIds:
          type: array
          items:
            type: integer
        projectIds:
          type: array
          items:
            type: integer
        compliance:
          type: number
          format: float

    PortfolioCreateRequest:
      type: object
      required:
        - name
        - color
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
        color:
          type: string
          minLength: 1
          maxLength: 50
        projectIds:
          type: array
          items:
            type: integer
        groupIds:
          type: array
          items:
            type: integer

    PortfolioUpdateRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
        color:
          type: string
          minLength: 1
          maxLength: 50
        projectIds:
          type: array
          items:
            type: integer
        groupIds:
          type: array
          items:
            type: integer

