openapi: 3.0.3
info:
  title: Exception Tracking API
  description: |
    A comprehensive exception tracking and notification system API for capturing, storing,
    and managing exceptions from multiple client applications.

    ## Authentication

    This API supports two authentication methods:

    ### 1. API Key Authentication (for exception ingestion)
    Use the `X-API-Key` header with your project's API key for sending exceptions.
    ```
    X-API-Key: your-api-key-here
    ```

    ### 2. Bearer Token Authentication (for user operations)
    Use Sanctum Bearer tokens for user-authenticated endpoints.
    ```
    Authorization: Bearer your-token-here
    ```

    ## Rate Limiting
    - API Key endpoints: 1000 requests per hour per key (configurable)
    - User endpoints: 60 requests per minute per user

    ## Base URL
    Production: `https://your-domain.com/api/v1`

  version: 1.0.0
  contact:
    name: API Support
    email: support@example.com
  license:
    name: MIT
    url: https://opensource.org/licenses/MIT

servers:
  - url: /api/v1
    description: API Version 1

tags:
  - name: Health
    description: Health check and status endpoints
  - name: Authentication
    description: User registration, login, and session management
  - name: Exception Ingestion
    description: Send exceptions to the tracking system (API Key auth)
  - name: Projects
    description: Project management operations
  - name: Mobile Projects
    description: Mobile-optimized project endpoints
  - name: Mobile Exceptions
    description: Mobile-optimized exception management
  - name: Statistics
    description: Analytics and statistics endpoints
  - name: Device Tokens
    description: Push notification device management
  - name: Notification Preferences
    description: User notification settings

paths:
  # Health Check
  /ping:
    get:
      tags:
        - Health
      summary: Health check
      description: Simple health check endpoint to verify API availability
      operationId: ping
      responses:
        '200':
          description: API is healthy
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: ok
                  timestamp:
                    type: string
                    format: date-time
                    example: "2024-01-15T10:30:00Z"

  # Exception Ingestion
  /exceptions:
    post:
      tags:
        - Exception Ingestion
      summary: Submit an exception
      description: |
        Submit a single exception to be tracked. Requires API Key authentication.
        The exception will be processed asynchronously and notifications will be sent based on alert rules.
      operationId: storeException
      security:
        - ApiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ExceptionInput'
            example:
              class: "App\\Exceptions\\PaymentFailedException"
              message: "Payment processing failed: Card declined"
              code: "PAYMENT_DECLINED"
              file: "/app/Services/PaymentService.php"
              line: 145
              severity: "error"
              environment: "production"
              stack_trace:
                - file: "/app/Services/PaymentService.php"
                  line: 145
                  function: "processPayment"
                  class: "App\\Services\\PaymentService"
                - file: "/app/Http/Controllers/CheckoutController.php"
                  line: 67
                  function: "checkout"
                  class: "App\\Http\\Controllers\\CheckoutController"
              request:
                method: "POST"
                url: "https://example.com/api/checkout"
                ip: "192.168.1.100"
              user:
                id: "user_12345"
                email: "john@example.com"
                name: "John Doe"
              context:
                order_id: "ORD-2024-001"
                amount: 99.99
              tags:
                payment_gateway: "stripe"
                retry_count: "2"
      responses:
        '202':
          description: Exception accepted for processing
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExceptionResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/TooManyRequests'

  /exceptions/batch:
    post:
      tags:
        - Exception Ingestion
      summary: Submit multiple exceptions
      description: |
        Submit multiple exceptions in a single request. Maximum 100 exceptions per batch.
        Each exception is processed independently - failures don't affect other exceptions in the batch.
      operationId: batchExceptions
      security:
        - ApiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - exceptions
              properties:
                exceptions:
                  type: array
                  minItems: 1
                  maxItems: 100
                  items:
                    $ref: '#/components/schemas/ExceptionInput'
            example:
              exceptions:
                - message: "Database connection failed"
                  severity: "critical"
                  environment: "production"
                - message: "Cache miss for key: user_session"
                  severity: "warning"
                  environment: "production"
      responses:
        '202':
          description: Batch accepted for processing
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BatchResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/ValidationError'

  # Authentication
  /auth/register:
    post:
      tags:
        - Authentication
      summary: Register a new user
      description: Create a new user account and receive an authentication token
      operationId: register
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - name
                - email
                - password
                - password_confirmation
                - device_name
              properties:
                name:
                  type: string
                  maxLength: 255
                  example: John Doe
                email:
                  type: string
                  format: email
                  maxLength: 255
                  example: john@example.com
                password:
                  type: string
                  format: password
                  minLength: 8
                  example: "SecurePass123!"
                password_confirmation:
                  type: string
                  format: password
                  example: "SecurePass123!"
                device_name:
                  type: string
                  maxLength: 255
                  example: "iPhone 15 Pro"
      responses:
        '201':
          description: User registered successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthResponse'
        '422':
          $ref: '#/components/responses/ValidationError'

  /auth/login:
    post:
      tags:
        - Authentication
      summary: Login user
      description: Authenticate user and receive an access token
      operationId: login
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - email
                - password
                - device_name
              properties:
                email:
                  type: string
                  format: email
                  example: john@example.com
                password:
                  type: string
                  format: password
                  example: "SecurePass123!"
                device_name:
                  type: string
                  maxLength: 255
                  example: "iPhone 15 Pro"
      responses:
        '200':
          description: Login successful
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthResponse'
        '422':
          description: Invalid credentials
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationError'

  /auth/user:
    get:
      tags:
        - Authentication
      summary: Get current user
      description: Retrieve the authenticated user's profile
      operationId: getUser
      security:
        - BearerAuth: []
      responses:
        '200':
          description: User profile
          content:
            application/json:
              schema:
                type: object
                properties:
                  user:
                    $ref: '#/components/schemas/User'
                  projects_count:
                    type: integer
                    example: 5
                  unread_notifications:
                    type: integer
                    example: 3
        '401':
          $ref: '#/components/responses/Unauthorized'

    patch:
      tags:
        - Authentication
      summary: Update user profile
      description: Update the authenticated user's profile information
      operationId: updateProfile
      security:
        - BearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  maxLength: 255
                email:
                  type: string
                  format: email
      responses:
        '200':
          description: Profile updated
          content:
            application/json:
              schema:
                type: object
                properties:
                  user:
                    $ref: '#/components/schemas/User'
                  message:
                    type: string
                    example: Profile updated successfully.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/ValidationError'

  /auth/user/password:
    patch:
      tags:
        - Authentication
      summary: Update password
      description: Change the authenticated user's password
      operationId: updatePassword
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - current_password
                - password
                - password_confirmation
              properties:
                current_password:
                  type: string
                  format: password
                password:
                  type: string
                  format: password
                  minLength: 8
                password_confirmation:
                  type: string
                  format: password
      responses:
        '200':
          description: Password updated
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: Password updated successfully.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/ValidationError'

  /auth/refresh:
    post:
      tags:
        - Authentication
      summary: Refresh token
      description: Get a new access token (revokes current token)
      operationId: refreshToken
      security:
        - BearerAuth: []
      responses:
        '200':
          description: New token issued
          content:
            application/json:
              schema:
                type: object
                properties:
                  token:
                    type: string
                    example: "1|abc123..."
                  token_type:
                    type: string
                    example: Bearer
        '401':
          $ref: '#/components/responses/Unauthorized'

  /auth/logout:
    post:
      tags:
        - Authentication
      summary: Logout current device
      description: Revoke the current access token
      operationId: logout
      security:
        - BearerAuth: []
      responses:
        '200':
          description: Logged out successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: Successfully logged out.
        '401':
          $ref: '#/components/responses/Unauthorized'

  /auth/logout-all:
    post:
      tags:
        - Authentication
      summary: Logout all devices
      description: Revoke all access tokens for the user
      operationId: logoutAll
      security:
        - BearerAuth: []
      responses:
        '200':
          description: Logged out from all devices
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: Successfully logged out from all devices.
        '401':
          $ref: '#/components/responses/Unauthorized'

  /auth/sessions:
    get:
      tags:
        - Authentication
      summary: List active sessions
      description: Get all active sessions/tokens for the user
      operationId: getSessions
      security:
        - BearerAuth: []
      responses:
        '200':
          description: List of active sessions
          content:
            application/json:
              schema:
                type: object
                properties:
                  sessions:
                    type: array
                    items:
                      $ref: '#/components/schemas/Session'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /auth/sessions/{tokenId}:
    delete:
      tags:
        - Authentication
      summary: Revoke a session
      description: Revoke a specific session/token (cannot revoke current session)
      operationId: revokeSession
      security:
        - BearerAuth: []
      parameters:
        - name: tokenId
          in: path
          required: true
          schema:
            type: integer
          example: 5
      responses:
        '200':
          description: Session revoked
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: Session revoked successfully.
        '400':
          description: Cannot revoke current session
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  # Projects
  /projects:
    get:
      tags:
        - Projects
      summary: List projects
      description: Get all projects for the authenticated user
      operationId: listProjects
      security:
        - BearerAuth: []
      responses:
        '200':
          description: List of projects
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Project'
        '401':
          $ref: '#/components/responses/Unauthorized'

    post:
      tags:
        - Projects
      summary: Create a project
      description: Create a new project. Returns the project and an initial API key.
      operationId: createProject
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - name
              properties:
                name:
                  type: string
                  maxLength: 255
                  example: My Web App
                description:
                  type: string
                  maxLength: 1000
                  example: Production web application
                platform:
                  type: string
                  enum: [php, node, python, javascript, ruby, java, go, dotnet, other]
                  example: php
      responses:
        '201':
          description: Project created
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/Project'
                  api_key:
                    $ref: '#/components/schemas/ApiKeyCreated'
                  message:
                    type: string
                    example: "Project created successfully. Save your API key - it will not be shown again."
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/ValidationError'

  /projects/{project}:
    get:
      tags:
        - Projects
      summary: Get project details
      description: Get detailed information about a specific project
      operationId: getProject
      security:
        - BearerAuth: []
      parameters:
        - $ref: '#/components/parameters/ProjectUuid'
      responses:
        '200':
          description: Project details
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/ProjectDetail'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'

    put:
      tags:
        - Projects
      summary: Update a project
      description: Update project settings. Only project owners can update.
      operationId: updateProject
      security:
        - BearerAuth: []
      parameters:
        - $ref: '#/components/parameters/ProjectUuid'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  maxLength: 255
                description:
                  type: string
                  maxLength: 1000
                platform:
                  type: string
                  enum: [php, node, python, javascript, ruby, java, go, dotnet, other]
                settings:
                  type: object
                  additionalProperties: true
      responses:
        '200':
          description: Project updated
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/Project'
                  message:
                    type: string
                    example: Project updated successfully.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'

    delete:
      tags:
        - Projects
      summary: Delete a project
      description: Permanently delete a project and all its data. Only project owners can delete.
      operationId: deleteProject
      security:
        - BearerAuth: []
      parameters:
        - $ref: '#/components/parameters/ProjectUuid'
      responses:
        '200':
          description: Project deleted
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: Project deleted successfully.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'

  /projects/{project}/archive:
    post:
      tags:
        - Projects
      summary: Archive a project
      description: Archive a project to stop receiving exceptions
      operationId: archiveProject
      security:
        - BearerAuth: []
      parameters:
        - $ref: '#/components/parameters/ProjectUuid'
      responses:
        '200':
          description: Project archived
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/Project'
                  message:
                    type: string
                    example: Project archived successfully.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  /projects/{project}/unarchive:
    post:
      tags:
        - Projects
      summary: Unarchive a project
      description: Restore an archived project
      operationId: unarchiveProject
      security:
        - BearerAuth: []
      parameters:
        - $ref: '#/components/parameters/ProjectUuid'
      responses:
        '200':
          description: Project unarchived
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/Project'
                  message:
                    type: string
                    example: Project unarchived successfully.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  # Mobile Projects
  /mobile/projects:
    get:
      tags:
        - Mobile Projects
      summary: List projects (mobile-optimized)
      description: Get user's projects with summary stats optimized for mobile displays
      operationId: mobileListProjects
      security:
        - BearerAuth: []
      responses:
        '200':
          description: List of projects
          content:
            application/json:
              schema:
                type: object
                properties:
                  projects:
                    type: array
                    items:
                      $ref: '#/components/schemas/MobileProjectSummary'
                  total:
                    type: integer
                    example: 5
        '401':
          $ref: '#/components/responses/Unauthorized'

  /mobile/projects/{project}:
    get:
      tags:
        - Mobile Projects
      summary: Get project (mobile-optimized)
      description: Get project details with stats optimized for mobile
      operationId: mobileGetProject
      security:
        - BearerAuth: []
      parameters:
        - $ref: '#/components/parameters/ProjectUuid'
      responses:
        '200':
          description: Project details
          content:
            application/json:
              schema:
                type: object
                properties:
                  project:
                    $ref: '#/components/schemas/MobileProjectDetail'
                  user_role:
                    type: string
                    enum: [owner, manager, member]
                    example: owner
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  /mobile/projects/{project}/quick-stats:
    get:
      tags:
        - Mobile Projects
      summary: Get quick stats
      description: Get quick project stats for dashboard widgets
      operationId: mobileQuickStats
      security:
        - BearerAuth: []
      parameters:
        - $ref: '#/components/parameters/ProjectUuid'
      responses:
        '200':
          description: Quick stats
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/QuickStats'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  # Mobile Exceptions
  /mobile/projects/{project}/exceptions:
    get:
      tags:
        - Mobile Exceptions
      summary: List exception groups
      description: Get paginated exception groups for a project (cursor-based pagination)
      operationId: mobileListExceptions
      security:
        - BearerAuth: []
      parameters:
        - $ref: '#/components/parameters/ProjectUuid'
        - name: status
          in: query
          schema:
            type: string
            enum: [unresolved, resolved, ignored, muted]
          description: Filter by status
        - name: severity
          in: query
          schema:
            type: string
            enum: [debug, info, warning, error, critical, fatal]
          description: Filter by severity
        - name: search
          in: query
          schema:
            type: string
            maxLength: 255
          description: Search in class and message
        - name: per_page
          in: query
          schema:
            type: integer
            minimum: 10
            maximum: 50
            default: 20
        - name: cursor
          in: query
          schema:
            type: string
          description: Cursor for pagination
      responses:
        '200':
          description: Exception groups
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/ExceptionGroup'
                  next_cursor:
                    type: string
                    nullable: true
                  has_more:
                    type: boolean
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  /mobile/projects/{project}/exceptions/{fingerprint}:
    get:
      tags:
        - Mobile Exceptions
      summary: Get exception group details
      description: Get detailed information about an exception group including latest occurrence and timeline
      operationId: mobileGetException
      security:
        - BearerAuth: []
      parameters:
        - $ref: '#/components/parameters/ProjectUuid'
        - $ref: '#/components/parameters/Fingerprint'
      responses:
        '200':
          description: Exception group details
          content:
            application/json:
              schema:
                type: object
                properties:
                  group:
                    $ref: '#/components/schemas/ExceptionGroupDetail'
                  latest_occurrence:
                    $ref: '#/components/schemas/ExceptionOccurrence'
                  timeline:
                    type: object
                    additionalProperties:
                      type: integer
                    example:
                      "2024-01-10": 5
                      "2024-01-11": 12
                      "2024-01-12": 3
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  /mobile/projects/{project}/exceptions/{fingerprint}/occurrences:
    get:
      tags:
        - Mobile Exceptions
      summary: List occurrences
      description: Get paginated list of occurrences for an exception group
      operationId: mobileListOccurrences
      security:
        - BearerAuth: []
      parameters:
        - $ref: '#/components/parameters/ProjectUuid'
        - $ref: '#/components/parameters/Fingerprint'
        - name: per_page
          in: query
          schema:
            type: integer
            minimum: 10
            maximum: 50
            default: 20
        - name: cursor
          in: query
          schema:
            type: string
      responses:
        '200':
          description: List of occurrences
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/ExceptionOccurrenceCompact'
                  next_cursor:
                    type: string
                    nullable: true
                  has_more:
                    type: boolean
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  /mobile/projects/{project}/occurrence/{uuid}:
    get:
      tags:
        - Mobile Exceptions
      summary: Get occurrence details
      description: Get full details of a single exception occurrence
      operationId: mobileGetOccurrence
      security:
        - BearerAuth: []
      parameters:
        - $ref: '#/components/parameters/ProjectUuid'
        - name: uuid
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Occurrence details
          content:
            application/json:
              schema:
                type: object
                properties:
                  exception:
                    $ref: '#/components/schemas/ExceptionOccurrenceFull'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  /mobile/projects/{project}/exceptions/{fingerprint}/resolve:
    post:
      tags:
        - Mobile Exceptions
      summary: Resolve exception
      description: Mark an exception group as resolved
      operationId: mobileResolveException
      security:
        - BearerAuth: []
      parameters:
        - $ref: '#/components/parameters/ProjectUuid'
        - $ref: '#/components/parameters/Fingerprint'
      responses:
        '200':
          description: Exception resolved
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: Exception marked as resolved.
                  group:
                    $ref: '#/components/schemas/ExceptionGroup'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'

  /mobile/projects/{project}/exceptions/{fingerprint}/unresolve:
    post:
      tags:
        - Mobile Exceptions
      summary: Unresolve exception
      description: Mark an exception group as unresolved
      operationId: mobileUnresolveException
      security:
        - BearerAuth: []
      parameters:
        - $ref: '#/components/parameters/ProjectUuid'
        - $ref: '#/components/parameters/Fingerprint'
      responses:
        '200':
          description: Exception unresolved
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: Exception marked as unresolved.
                  group:
                    $ref: '#/components/schemas/ExceptionGroup'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  /mobile/projects/{project}/exceptions/{fingerprint}/ignore:
    post:
      tags:
        - Mobile Exceptions
      summary: Ignore exception
      description: Mark an exception group as ignored
      operationId: mobileIgnoreException
      security:
        - BearerAuth: []
      parameters:
        - $ref: '#/components/parameters/ProjectUuid'
        - $ref: '#/components/parameters/Fingerprint'
      responses:
        '200':
          description: Exception ignored
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: Exception marked as ignored.
                  group:
                    $ref: '#/components/schemas/ExceptionGroup'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  /mobile/projects/{project}/exceptions/{fingerprint}/mute:
    post:
      tags:
        - Mobile Exceptions
      summary: Mute exception
      description: Temporarily mute notifications for an exception group
      operationId: mobileMuteException
      security:
        - BearerAuth: []
      parameters:
        - $ref: '#/components/parameters/ProjectUuid'
        - $ref: '#/components/parameters/Fingerprint'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                hours:
                  type: integer
                  minimum: 1
                  maximum: 720
                  default: 24
                  description: Hours to mute (max 30 days)
      responses:
        '200':
          description: Exception muted
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: "Exception muted for 24 hours."
                  group:
                    $ref: '#/components/schemas/ExceptionGroup'
                  muted_until:
                    type: string
                    format: date-time
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  # Statistics
  /projects/{project}/stats/overview:
    get:
      tags:
        - Statistics
      summary: Get overview statistics
      description: Get project statistics overview with comparison to previous period
      operationId: statsOverview
      security:
        - BearerAuth: []
      parameters:
        - $ref: '#/components/parameters/ProjectUuid'
        - name: days
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 90
            default: 30
      responses:
        '200':
          description: Overview statistics
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StatsOverview'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  /projects/{project}/stats/timeline:
    get:
      tags:
        - Statistics
      summary: Get timeline statistics
      description: Get exception counts over time
      operationId: statsTimeline
      security:
        - BearerAuth: []
      parameters:
        - $ref: '#/components/parameters/ProjectUuid'
        - name: days
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 90
            default: 30
        - name: period
          in: query
          schema:
            type: string
            enum: [hour, day, week]
            default: day
      responses:
        '200':
          description: Timeline statistics
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StatsTimeline'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  /projects/{project}/stats/severity:
    get:
      tags:
        - Statistics
      summary: Get severity breakdown
      description: Get exception counts by severity level
      operationId: statsSeverity
      security:
        - BearerAuth: []
      parameters:
        - $ref: '#/components/parameters/ProjectUuid'
        - name: days
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 90
            default: 30
      responses:
        '200':
          description: Severity breakdown
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StatsSeverity'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  /projects/{project}/stats/environment:
    get:
      tags:
        - Statistics
      summary: Get environment breakdown
      description: Get exception counts by environment
      operationId: statsEnvironment
      security:
        - BearerAuth: []
      parameters:
        - $ref: '#/components/parameters/ProjectUuid'
        - name: days
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 90
            default: 30
      responses:
        '200':
          description: Environment breakdown
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StatsEnvironment'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  /projects/{project}/stats/top-exceptions:
    get:
      tags:
        - Statistics
      summary: Get top exceptions
      description: Get most frequent exceptions
      operationId: statsTopExceptions
      security:
        - BearerAuth: []
      parameters:
        - $ref: '#/components/parameters/ProjectUuid'
        - name: days
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 90
            default: 30
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 50
            default: 10
      responses:
        '200':
          description: Top exceptions
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StatsTopExceptions'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  /projects/{project}/stats/trends:
    get:
      tags:
        - Statistics
      summary: Get trend analysis
      description: Get trend analysis with moving averages
      operationId: statsTrends
      security:
        - BearerAuth: []
      parameters:
        - $ref: '#/components/parameters/ProjectUuid'
        - name: days
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 90
            default: 30
      responses:
        '200':
          description: Trend analysis
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StatsTrends'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  # Device Tokens
  /user/devices:
    get:
      tags:
        - Device Tokens
      summary: List device tokens
      description: Get all registered device tokens for push notifications
      operationId: listDevices
      security:
        - BearerAuth: []
      responses:
        '200':
          description: List of device tokens
          content:
            application/json:
              schema:
                type: object
                properties:
                  device_tokens:
                    type: array
                    items:
                      $ref: '#/components/schemas/DeviceToken'
        '401':
          $ref: '#/components/responses/Unauthorized'

    post:
      tags:
        - Device Tokens
      summary: Register device token
      description: Register a device token for push notifications
      operationId: registerDevice
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - token
                - platform
              properties:
                token:
                  type: string
                  maxLength: 512
                  description: The push notification token
                platform:
                  type: string
                  enum: [ios, android, web]
                device_name:
                  type: string
                  maxLength: 255
                  example: "iPhone 15 Pro"
      responses:
        '201':
          description: Device registered
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: Device token registered
                  device_token:
                    $ref: '#/components/schemas/DeviceToken'
        '200':
          description: Device token updated (already existed)
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: Device token updated
                  device_token:
                    $ref: '#/components/schemas/DeviceToken'
        '401':
          $ref: '#/components/responses/Unauthorized'

    delete:
      tags:
        - Device Tokens
      summary: Deactivate all device tokens
      description: Deactivate all device tokens for the user
      operationId: deactivateAllDevices
      security:
        - BearerAuth: []
      responses:
        '200':
          description: All devices deactivated
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: All device tokens deactivated
        '401':
          $ref: '#/components/responses/Unauthorized'

  /user/devices/{device}:
    delete:
      tags:
        - Device Tokens
      summary: Deactivate device token
      description: Deactivate a specific device token
      operationId: deactivateDevice
      security:
        - BearerAuth: []
      parameters:
        - name: device
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Device deactivated
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: Device token deactivated
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  # Notification Preferences
  /notifications/preferences:
    get:
      tags:
        - Notification Preferences
      summary: Get all preferences
      description: Get notification preferences for all projects
      operationId: getNotificationPreferences
      security:
        - BearerAuth: []
      responses:
        '200':
          description: Notification preferences
          content:
            application/json:
              schema:
                type: object
                properties:
                  global_preferences:
                    $ref: '#/components/schemas/GlobalNotificationPreferences'
                  project_preferences:
                    type: array
                    items:
                      $ref: '#/components/schemas/ProjectNotificationPreferences'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /notifications/preferences/global:
    patch:
      tags:
        - Notification Preferences
      summary: Update global preferences
      description: Update global notification settings
      operationId: updateGlobalPreferences
      security:
        - BearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                default_email_enabled:
                  type: boolean
                default_push_enabled:
                  type: boolean
                timezone:
                  type: string
                  example: "America/New_York"
      responses:
        '200':
          description: Preferences updated
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  global_preferences:
                    $ref: '#/components/schemas/GlobalNotificationPreferences'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /notifications/preferences/bulk:
    patch:
      tags:
        - Notification Preferences
      summary: Bulk update preferences
      description: Update preferences for multiple projects at once
      operationId: bulkUpdatePreferences
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - project_uuids
                - preferences
              properties:
                project_uuids:
                  type: array
                  items:
                    type: string
                    format: uuid
                preferences:
                  $ref: '#/components/schemas/NotificationPreferences'
      responses:
        '200':
          description: Preferences updated
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  updated_count:
                    type: integer
        '401':
          $ref: '#/components/responses/Unauthorized'

  /notifications/preferences/{project}:
    get:
      tags:
        - Notification Preferences
      summary: Get project preferences
      description: Get notification preferences for a specific project
      operationId: getProjectPreferences
      security:
        - BearerAuth: []
      parameters:
        - $ref: '#/components/parameters/ProjectUuid'
      responses:
        '200':
          description: Project preferences
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProjectNotificationPreferences'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

    patch:
      tags:
        - Notification Preferences
      summary: Update project preferences
      description: Update notification preferences for a specific project
      operationId: updateProjectPreferences
      security:
        - BearerAuth: []
      parameters:
        - $ref: '#/components/parameters/ProjectUuid'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/NotificationPreferences'
      responses:
        '200':
          description: Preferences updated
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  preferences:
                    $ref: '#/components/schemas/NotificationPreferences'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  /notifications/preferences/{project}/reset:
    post:
      tags:
        - Notification Preferences
      summary: Reset project preferences
      description: Reset notification preferences for a project to defaults
      operationId: resetProjectPreferences
      security:
        - BearerAuth: []
      parameters:
        - $ref: '#/components/parameters/ProjectUuid'
      responses:
        '200':
          description: Preferences reset
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  preferences:
                    $ref: '#/components/schemas/NotificationPreferences'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: API Key for exception ingestion endpoints

    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: Token
      description: Sanctum Bearer token for user-authenticated endpoints

  parameters:
    ProjectUuid:
      name: project
      in: path
      required: true
      schema:
        type: string
        format: uuid
      description: Project UUID
      example: "550e8400-e29b-41d4-a716-446655440000"

    Fingerprint:
      name: fingerprint
      in: path
      required: true
      schema:
        type: string
      description: Exception group fingerprint (SHA-256 hash)
      example: "a1b2c3d4e5f6..."

  responses:
    Unauthorized:
      description: Authentication required or invalid credentials
      content:
        application/json:
          schema:
            type: object
            properties:
              message:
                type: string
                example: Unauthenticated.

    Forbidden:
      description: Access denied
      content:
        application/json:
          schema:
            type: object
            properties:
              error:
                type: string
                example: Forbidden

    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            type: object
            properties:
              message:
                type: string
                example: Not found.

    ValidationError:
      description: Validation error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ValidationError'

    TooManyRequests:
      description: Rate limit exceeded
      content:
        application/json:
          schema:
            type: object
            properties:
              message:
                type: string
                example: Too Many Attempts.
      headers:
        X-RateLimit-Limit:
          schema:
            type: integer
          description: Request limit per hour
        X-RateLimit-Remaining:
          schema:
            type: integer
          description: Remaining requests
        Retry-After:
          schema:
            type: integer
          description: Seconds until rate limit resets

  schemas:
    # Auth Schemas
    User:
      type: object
      properties:
        id:
          type: integer
          example: 1
        name:
          type: string
          example: John Doe
        email:
          type: string
          format: email
          example: john@example.com
        email_verified_at:
          type: string
          format: date-time
          nullable: true
        created_at:
          type: string
          format: date-time

    AuthResponse:
      type: object
      properties:
        user:
          $ref: '#/components/schemas/User'
        token:
          type: string
          example: "1|abc123xyz456..."
        token_type:
          type: string
          example: Bearer

    Session:
      type: object
      properties:
        id:
          type: integer
          example: 5
        name:
          type: string
          example: "iPhone 15 Pro"
        last_used_at:
          type: string
          format: date-time
          nullable: true
        created_at:
          type: string
          format: date-time
        is_current:
          type: boolean
          example: true

    # Project Schemas
    Project:
      type: object
      properties:
        uuid:
          type: string
          format: uuid
        name:
          type: string
          example: My Web App
        slug:
          type: string
          example: my-web-app
        platform:
          type: string
          enum: [php, node, python, javascript, ruby, java, go, dotnet, other]
        exceptions_count:
          type: integer
          example: 1234
        unresolved_count:
          type: integer
          example: 23
        last_exception_at:
          type: string
          format: date-time
          nullable: true
        is_archived:
          type: boolean
          example: false
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        role:
          type: string
          enum: [owner, manager, member]
          description: User's role in this project (when applicable)

    ProjectDetail:
      allOf:
        - $ref: '#/components/schemas/Project'
        - type: object
          properties:
            description:
              type: string
              nullable: true
            settings:
              type: object
              additionalProperties: true
            exception_groups_count:
              type: integer
              example: 45

    ApiKeyCreated:
      type: object
      properties:
        id:
          type: integer
          example: 1
        name:
          type: string
          example: Production
        key:
          type: string
          description: The full API key (only shown once!)
          example: "proj_abc123xyz456..."
        prefix:
          type: string
          example: "proj_abc"

    MobileProjectSummary:
      type: object
      properties:
        uuid:
          type: string
          format: uuid
        name:
          type: string
        platform:
          type: string
        unresolved_count:
          type: integer
        today_count:
          type: integer
        last_exception_at:
          type: string
          format: date-time
          nullable: true
        role:
          type: string
          enum: [owner, manager, member]
        is_critical:
          type: boolean

    MobileProjectDetail:
      type: object
      properties:
        uuid:
          type: string
          format: uuid
        name:
          type: string
        slug:
          type: string
        platform:
          type: string
        stats:
          type: object
          properties:
            total_groups:
              type: integer
            unresolved:
              type: integer
            resolved:
              type: integer
            today:
              type: integer
            this_week:
              type: integer
        severity_breakdown:
          type: object
          properties:
            fatal:
              type: integer
            critical:
              type: integer
            error:
              type: integer
            warning:
              type: integer
            info:
              type: integer
            debug:
              type: integer
        critical_alert:
          type: object
          nullable: true
        created_at:
          type: string
          format: date-time
        last_exception_at:
          type: string
          format: date-time
          nullable: true

    QuickStats:
      type: object
      properties:
        today_count:
          type: integer
          example: 45
        yesterday_count:
          type: integer
          example: 38
        change_percent:
          type: number
          format: float
          example: 18.4
        trend:
          type: string
          enum: [up, down, stable]
        unresolved_count:
          type: integer
          example: 12
        latest_exception:
          type: object
          nullable: true
          properties:
            fingerprint:
              type: string
            class:
              type: string
            severity:
              type: string
            last_seen_at:
              type: string
              format: date-time

    # Exception Schemas
    ExceptionInput:
      type: object
      required:
        - message
      properties:
        class:
          type: string
          maxLength: 500
          description: Exception class name
          example: "App\\Exceptions\\PaymentException"
        message:
          type: string
          maxLength: 65535
          description: Exception message
        code:
          type: string
          maxLength: 100
          description: Error code
        file:
          type: string
          maxLength: 1000
          description: File where exception occurred
        line:
          type: integer
          minimum: 0
          description: Line number
        stack_trace:
          type: array
          items:
            $ref: '#/components/schemas/StackFrame'
        environment:
          type: string
          maxLength: 50
          example: production
        server:
          type: object
          properties:
            name:
              type: string
            ip:
              type: string
        request:
          type: object
          properties:
            method:
              type: string
              example: POST
            url:
              type: string
              format: uri
            headers:
              type: object
              additionalProperties:
                type: string
            body:
              type: object
            ip:
              type: string
        user:
          type: object
          properties:
            id:
              type: string
            email:
              type: string
              format: email
            name:
              type: string
        context:
          type: object
          additionalProperties: true
          description: Additional context data
        breadcrumbs:
          type: array
          items:
            $ref: '#/components/schemas/Breadcrumb'
        tags:
          type: object
          additionalProperties:
            type: string
          description: Key-value tags
        severity:
          type: string
          enum: [debug, info, warning, error, critical, emergency]
          default: error
        handled:
          type: boolean
          default: true
        occurred_at:
          type: string
          format: date-time
          description: When the exception occurred (defaults to now)
        app_version:
          type: string
          maxLength: 50
        sdk:
          type: object
          properties:
            name:
              type: string
            version:
              type: string

    StackFrame:
      type: object
      properties:
        file:
          type: string
        line:
          type: integer
        function:
          type: string
        class:
          type: string
        type:
          type: string
          description: "->" or "::"
        args:
          type: array
          items: {}

    Breadcrumb:
      type: object
      properties:
        timestamp:
          type: string
        category:
          type: string
          example: http
        message:
          type: string
        data:
          type: object

    ExceptionResponse:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Exception occurrence ID
        group_id:
          type: string
          description: Exception group ID
        is_new_group:
          type: boolean
          description: Whether this created a new exception group
        is_regression:
          type: boolean
          description: Whether this is a regression of a resolved issue
        received_at:
          type: string
          format: date-time

    BatchResponse:
      type: object
      properties:
        processed:
          type: integer
          description: Number of successfully processed exceptions
          example: 8
        total:
          type: integer
          description: Total number of exceptions in batch
          example: 10
        results:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
                format: uuid
                nullable: true
              group_id:
                type: string
                nullable: true
              status:
                type: string
                enum: [accepted, failed]
              error:
                type: string
                nullable: true

    ExceptionGroup:
      type: object
      properties:
        fingerprint:
          type: string
        class:
          type: string
        message:
          type: string
        file:
          type: string
        line:
          type: integer
        severity:
          type: string
          enum: [debug, info, warning, error, critical, fatal]
        status:
          type: string
          enum: [unresolved, resolved, ignored, muted]
        occurrences_count:
          type: integer
        affected_users_count:
          type: integer
        first_seen_at:
          type: string
          format: date-time
        last_seen_at:
          type: string
          format: date-time

    ExceptionGroupDetail:
      allOf:
        - $ref: '#/components/schemas/ExceptionGroup'
        - type: object
          properties:
            short_class:
              type: string
            message_template:
              type: string
            resolved_at:
              type: string
              format: date-time
              nullable: true
            muted_until:
              type: string
              format: date-time
              nullable: true

    ExceptionOccurrence:
      type: object
      properties:
        uuid:
          type: string
          format: uuid
        message:
          type: string
        file:
          type: string
        line:
          type: integer
        environment:
          type: string
        severity:
          type: string
        user_identifier:
          type: string
          nullable: true
        request_url:
          type: string
          nullable: true
        request_method:
          type: string
          nullable: true
        occurred_at:
          type: string
          format: date-time
        stack_trace_preview:
          type: array
          items:
            $ref: '#/components/schemas/StackFrame'
          description: First 5 frames of stack trace

    ExceptionOccurrenceCompact:
      type: object
      properties:
        uuid:
          type: string
          format: uuid
        message:
          type: string
        environment:
          type: string
        severity:
          type: string
        user_identifier:
          type: string
          nullable: true
        occurred_at:
          type: string
          format: date-time

    ExceptionOccurrenceFull:
      allOf:
        - $ref: '#/components/schemas/ExceptionOccurrence'
        - type: object
          properties:
            class:
              type: string
            handled:
              type: boolean
            user_data:
              type: object
              nullable: true
            request:
              type: object
              properties:
                url:
                  type: string
                method:
                  type: string
                ip:
                  type: string
            server_name:
              type: string
              nullable: true
            context:
              type: object
              nullable: true
            breadcrumbs:
              type: array
              items:
                $ref: '#/components/schemas/Breadcrumb'
              nullable: true
            tags:
              type: object
              nullable: true
            stack_trace:
              type: array
              items:
                $ref: '#/components/schemas/StackFrame'
            group:
              type: object
              properties:
                fingerprint:
                  type: string
                class:
                  type: string
                status:
                  type: string
                severity:
                  type: string

    # Statistics Schemas
    StatsOverview:
      type: object
      properties:
        current:
          type: object
          properties:
            total_exceptions:
              type: integer
            total_groups:
              type: integer
            unresolved_groups:
              type: integer
            unique_users_affected:
              type: integer
        previous:
          type: object
          properties:
            total_exceptions:
              type: integer
            total_groups:
              type: integer
        changes:
          type: object
          properties:
            exceptions:
              type: number
              format: float
              description: Percentage change
            groups:
              type: number
              format: float
        period_days:
          type: integer

    StatsTimeline:
      type: object
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              period:
                type: string
              occurrences:
                type: integer
              unique_users:
                type: integer
              new_groups:
                type: integer
              resolved_groups:
                type: integer
        period_type:
          type: string
          enum: [hour, day, week]
        start_date:
          type: string
          format: date

    StatsSeverity:
      type: object
      properties:
        data:
          type: object
          properties:
            debug:
              type: integer
            info:
              type: integer
            warning:
              type: integer
            error:
              type: integer
            critical:
              type: integer
            fatal:
              type: integer
        total:
          type: integer
        period_days:
          type: integer

    StatsEnvironment:
      type: object
      properties:
        data:
          type: object
          additionalProperties:
            type: integer
          example:
            production: 150
            staging: 45
            development: 12
        total:
          type: integer
        period_days:
          type: integer

    StatsTopExceptions:
      type: object
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              fingerprint:
                type: string
              class:
                type: string
              message_template:
                type: string
              severity:
                type: string
              status:
                type: string
              occurrences:
                type: integer
              first_seen:
                type: string
              last_seen:
                type: string
        period_days:
          type: integer

    StatsTrends:
      type: object
      properties:
        daily_data:
          type: array
          items:
            type: object
            properties:
              date:
                type: string
                format: date
              occurrences:
                type: integer
              unique_users:
                type: integer
        moving_avg_7:
          type: array
          items:
            type: number
            format: float
        moving_avg_30:
          type: array
          items:
            type: number
            format: float
        trend:
          type: string
          enum: [increasing, decreasing, stable]
        summary:
          type: object
          properties:
            recent_avg:
              type: number
              format: float
            previous_avg:
              type: number
              format: float
            total:
              type: integer

    # Device Token Schemas
    DeviceToken:
      type: object
      properties:
        id:
          type: integer
        platform:
          type: string
          enum: [ios, android, web]
        device_name:
          type: string
          nullable: true
        is_active:
          type: boolean
        last_used_at:
          type: string
          format: date-time
          nullable: true
        created_at:
          type: string
          format: date-time

    # Notification Preferences Schemas
    NotificationPreferences:
      type: object
      properties:
        email_enabled:
          type: boolean
          default: true
        push_enabled:
          type: boolean
          default: true
        new_exception:
          type: boolean
          default: true
        regression:
          type: boolean
          default: true
        critical_severity:
          type: boolean
          default: true
        threshold_alerts:
          type: boolean
          default: true
        digest_daily:
          type: boolean
          default: false
        digest_weekly:
          type: boolean
          default: true
        quiet_hours_enabled:
          type: boolean
          default: false
        quiet_hours_start:
          type: string
          example: "22:00"
        quiet_hours_end:
          type: string
          example: "08:00"

    GlobalNotificationPreferences:
      type: object
      properties:
        default_email_enabled:
          type: boolean
          default: true
        default_push_enabled:
          type: boolean
          default: true
        timezone:
          type: string
          example: "UTC"

    ProjectNotificationPreferences:
      type: object
      properties:
        project_uuid:
          type: string
          format: uuid
        project_name:
          type: string
        preferences:
          $ref: '#/components/schemas/NotificationPreferences'

    # Error Schemas
    ValidationError:
      type: object
      properties:
        message:
          type: string
          example: The given data was invalid.
        errors:
          type: object
          additionalProperties:
            type: array
            items:
              type: string
          example:
            email:
              - The email field is required.
            password:
              - The password must be at least 8 characters.
