openapi: 3.0.3
info:
  title: NVLP - Virtual Envelope Budgeting System API
  description: |
    NVLP is a modern digital implementation of the envelope budgeting method, providing users with granular control over their finances through virtual envelopes that represent spending categories.
    
    The API implements a zero-sum money flow model with the following transaction types:
    - **Income**: External Source → Available Pool
    - **Allocation**: Available Pool → Envelope  
    - **Expense**: Envelope → External Payee
    - **Transfer**: Envelope → Envelope
    - **Debt Payment**: Envelope → External Payee
    
    ## Authentication
    
    The API uses Supabase Auth with magic link authentication. All authenticated endpoints require a Bearer token in the Authorization header.
    
    ## API Architecture
    
    - **Edge Functions**: Complex business logic and validations (`/functions/v1/`)
    - **PostgREST**: Direct database access for simple CRUD operations (`/rest/v1/`)
    
  version: 1.0.0
  contact:
    name: NVLP API Support
    url: https://github.com/nvlp-app
  license:
    name: MIT
    url: https://opensource.org/licenses/MIT

servers:
  - url: https://{project-id}.supabase.co
    description: Supabase hosted instance
    variables:
      project-id:
        default: your-project
        description: Your Supabase project ID

security:
  - BearerAuth: []

paths:
  # Authentication Endpoints
  /functions/v1/auth-magic-link:
    post:
      tags:
        - Authentication
      summary: Send magic link email
      description: Sends a magic link to the specified email address for passwordless authentication
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - email
              properties:
                email:
                  type: string
                  format: email
                  description: Email address to send magic link to
                redirectTo:
                  type: string
                  format: uri
                  description: URL to redirect to after successful authentication
      responses:
        '200':
          description: Magic link sent successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: Magic link sent successfully
        '400':
          $ref: '#/components/responses/BadRequest'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /functions/v1/auth-user:
    get:
      tags:
        - Authentication
      summary: Get current user profile
      description: Retrieves the current user's profile information
      responses:
        '200':
          description: User profile retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /functions/v1/auth-user-update:
    patch:
      tags:
        - Authentication
      summary: Update user profile
      description: Updates the current user's profile information
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                display_name:
                  type: string
                  description: User's display name
                avatar_url:
                  type: string
                  format: uri
                  description: URL to user's avatar image
      responses:
        '200':
          description: User profile updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /functions/v1/auth-logout:
    post:
      tags:
        - Authentication
      summary: Logout user
      description: Signs out the current user and invalidates their session
      responses:
        '200':
          description: User logged out successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: Logged out successfully
        '401':
          $ref: '#/components/responses/Unauthorized'

  # Budget Endpoints
  /rest/v1/budgets:
    get:
      tags:
        - Budgets
      summary: List user's budgets
      description: Retrieves all budgets belonging to the current user
      parameters:
        - $ref: '#/components/parameters/SelectParam'
        - $ref: '#/components/parameters/OrderParam'
        - $ref: '#/components/parameters/LimitParam'
        - $ref: '#/components/parameters/OffsetParam'
      responses:
        '200':
          description: List of budgets
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Budget'
        '401':
          $ref: '#/components/responses/Unauthorized'

    post:
      tags:
        - Budgets
      summary: Create new budget
      description: Creates a new empty budget (no default objects)
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BudgetCreateRequest'
      responses:
        '201':
          description: Budget created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Budget'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /rest/v1/budgets/{budgetId}:
    get:
      tags:
        - Budgets
      summary: Get budget by ID
      parameters:
        - $ref: '#/components/parameters/BudgetIdPath'
        - $ref: '#/components/parameters/SelectParam'
      responses:
        '200':
          description: Budget details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Budget'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

    patch:
      tags:
        - Budgets
      summary: Update budget
      parameters:
        - $ref: '#/components/parameters/BudgetIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BudgetUpdateRequest'
      responses:
        '200':
          description: Budget updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Budget'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

    delete:
      tags:
        - Budgets
      summary: Delete budget
      parameters:
        - $ref: '#/components/parameters/BudgetIdPath'
      responses:
        '204':
          description: Budget deleted successfully
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  /functions/v1/budget-setup/{budgetId}/defaults:
    post:
      tags:
        - Budgets
      summary: Setup default budget objects
      description: Creates default categories, envelopes, income sources, and payees for a budget
      parameters:
        - $ref: '#/components/parameters/BudgetIdPath'
      responses:
        '200':
          description: Default objects created successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: Default budget setup completed
                  created:
                    type: object
                    properties:
                      categories:
                        type: integer
                      envelopes:
                        type: integer
                      income_sources:
                        type: integer
                      payees:
                        type: integer
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  /functions/v1/budget-setup/{budgetId}/demo:
    post:
      tags:
        - Budgets
      summary: Setup demo data
      description: Creates realistic demo transactions and scenarios for testing
      parameters:
        - $ref: '#/components/parameters/BudgetIdPath'
      responses:
        '200':
          description: Demo data created successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: Demo data setup completed
                  created:
                    type: object
                    properties:
                      transactions:
                        type: integer
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  # Envelope Endpoints
  /rest/v1/envelopes:
    get:
      tags:
        - Envelopes
      summary: List envelopes
      description: List envelopes for a specific budget
      parameters:
        - name: budget_id
          in: query
          required: true
          schema:
            type: string
            format: uuid
          description: Budget ID to filter envelopes
        - $ref: '#/components/parameters/SelectParam'
        - $ref: '#/components/parameters/OrderParam'
        - $ref: '#/components/parameters/LimitParam'
        - $ref: '#/components/parameters/OffsetParam'
      responses:
        '200':
          description: List of envelopes
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Envelope'
        '401':
          $ref: '#/components/responses/Unauthorized'

    post:
      tags:
        - Envelopes
      summary: Create envelope
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/EnvelopeCreateRequest'
                - type: object
                  required:
                    - budget_id
                  properties:
                    budget_id:
                      type: string
                      format: uuid
      responses:
        '201':
          description: Envelope created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Envelope'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /rest/v1/envelopes/{envelopeId}:
    get:
      tags:
        - Envelopes
      summary: Get envelope by ID
      parameters:
        - $ref: '#/components/parameters/EnvelopeIdPath'
        - $ref: '#/components/parameters/SelectParam'
      responses:
        '200':
          description: Envelope details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Envelope'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

    patch:
      tags:
        - Envelopes
      summary: Update envelope
      parameters:
        - $ref: '#/components/parameters/EnvelopeIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EnvelopeUpdateRequest'
      responses:
        '200':
          description: Envelope updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Envelope'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

    delete:
      tags:
        - Envelopes
      summary: Delete envelope
      description: Deletes an envelope (only if balance is zero)
      parameters:
        - $ref: '#/components/parameters/EnvelopeIdPath'
      responses:
        '204':
          description: Envelope deleted successfully
        '400':
          description: Cannot delete envelope with non-zero balance
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  # Transaction Endpoints
  /functions/v1/transactions:
    post:
      tags:
        - Transactions
      summary: Create transaction
      description: Creates a new transaction with automatic balance updates and validation
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/TransactionCreateRequest'
                - type: object
                  required:
                    - budget_id
                  properties:
                    budget_id:
                      type: string
                      format: uuid
      responses:
        '201':
          description: Transaction created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TransactionWithDetails'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /rest/v1/transactions:
    get:
      tags:
        - Transactions
      summary: List transactions
      description: List transactions with various filtering options
      parameters:
        - name: budget_id
          in: query
          required: true
          schema:
            type: string
            format: uuid
          description: Budget ID to filter transactions
        - name: transaction_type
          in: query
          schema:
            $ref: '#/components/schemas/TransactionType'
          description: Filter by transaction type
        - name: from_envelope_id
          in: query
          schema:
            type: string
            format: uuid
          description: Filter by source envelope
        - name: to_envelope_id
          in: query
          schema:
            type: string
            format: uuid
          description: Filter by destination envelope
        - name: payee_id
          in: query
          schema:
            type: string
            format: uuid
          description: Filter by payee
        - name: is_cleared
          in: query
          schema:
            type: boolean
          description: Filter by cleared status
        - name: is_deleted
          in: query
          schema:
            type: boolean
            default: false
          description: Include deleted transactions
        - name: transaction_date
          in: query
          schema:
            type: string
            format: date
          description: Filter by transaction date (use with gte/lte operators)
        - $ref: '#/components/parameters/SelectParam'
        - $ref: '#/components/parameters/OrderParam'
        - $ref: '#/components/parameters/LimitParam'
        - $ref: '#/components/parameters/OffsetParam'
      responses:
        '200':
          description: List of transactions
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Transaction'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /rest/v1/transactions/{transactionId}:
    get:
      tags:
        - Transactions
      summary: Get transaction by ID
      parameters:
        - $ref: '#/components/parameters/TransactionIdPath'
        - $ref: '#/components/parameters/SelectParam'
      responses:
        '200':
          description: Transaction details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TransactionWithDetails'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

    patch:
      tags:
        - Transactions
      summary: Update transaction
      parameters:
        - $ref: '#/components/parameters/TransactionIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TransactionUpdateRequest'
      responses:
        '200':
          description: Transaction updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TransactionWithDetails'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

    delete:
      tags:
        - Transactions
      summary: Soft delete transaction
      description: Marks a transaction as deleted (soft delete with audit trail)
      parameters:
        - $ref: '#/components/parameters/TransactionIdPath'
      responses:
        '200':
          description: Transaction deleted successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Transaction'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  /functions/v1/transactions/{transactionId}/restore:
    post:
      tags:
        - Transactions
      summary: Restore deleted transaction
      description: Restores a soft-deleted transaction
      parameters:
        - $ref: '#/components/parameters/TransactionIdPath'
      responses:
        '200':
          description: Transaction restored successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Transaction'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  # Dashboard & Reporting Endpoints
  /functions/v1/dashboard/{budgetId}:
    get:
      tags:
        - Dashboard
      summary: Get dashboard summary
      description: Retrieves dashboard data including budget overview, recent transactions, and key metrics
      parameters:
        - $ref: '#/components/parameters/BudgetIdPath'
      responses:
        '200':
          description: Dashboard data
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DashboardSummary'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  /functions/v1/dashboard/{budgetId}/stats/spending:
    get:
      tags:
        - Dashboard
      summary: Get spending statistics
      description: Retrieves spending analysis by category and time period
      parameters:
        - $ref: '#/components/parameters/BudgetIdPath'
        - name: period
          in: query
          schema:
            type: string
            enum: [week, month, quarter, year]
            default: month
          description: Time period for analysis
        - name: group_by
          in: query
          schema:
            type: string
            enum: [category, envelope, payee]
            default: category
          description: How to group spending data
      responses:
        '200':
          description: Spending statistics
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SpendingStats'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  /functions/v1/dashboard/{budgetId}/export/transactions:
    get:
      tags:
        - Export
      summary: Export transactions
      description: Exports transactions in CSV or JSON format
      parameters:
        - $ref: '#/components/parameters/BudgetIdPath'
        - name: format
          in: query
          schema:
            type: string
            enum: [csv, json]
            default: csv
          description: Export format
        - name: start_date
          in: query
          schema:
            type: string
            format: date
          description: Start date for export range
        - name: end_date
          in: query
          schema:
            type: string
            format: date
          description: End date for export range
      responses:
        '200':
          description: Exported transaction data
          content:
            text/csv:
              schema:
                type: string
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/TransactionWithDetails'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: Supabase JWT token obtained through magic link authentication

  parameters:
    BudgetIdPath:
      name: budgetId
      in: path
      required: true
      schema:
        type: string
        format: uuid
      description: Budget ID

    EnvelopeIdPath:
      name: envelopeId
      in: path
      required: true
      schema:
        type: string
        format: uuid
      description: Envelope ID

    TransactionIdPath:
      name: transactionId
      in: path
      required: true
      schema:
        type: string
        format: uuid
      description: Transaction ID

    SelectParam:
      name: select
      in: query
      schema:
        type: string
      description: PostgREST select parameter to specify which columns to return
      example: "id,name,created_at"

    OrderParam:
      name: order
      in: query
      schema:
        type: string
      description: PostgREST order parameter for sorting
      example: "created_at.desc"

    LimitParam:
      name: limit
      in: query
      schema:
        type: integer
        minimum: 1
        maximum: 1000
        default: 20
      description: Maximum number of results to return

    OffsetParam:
      name: offset
      in: query
      schema:
        type: integer
        minimum: 0
        default: 0
      description: Number of results to skip

  schemas:
    # Core Entities
    User:
      type: object
      properties:
        id:
          type: string
          format: uuid
        email:
          type: string
          format: email
        display_name:
          type: string
          nullable: true
        avatar_url:
          type: string
          format: uri
          nullable: true
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    Budget:
      type: object
      properties:
        id:
          type: string
          format: uuid
        user_id:
          type: string
          format: uuid
        name:
          type: string
        description:
          type: string
          nullable: true
        currency:
          type: string
          minLength: 3
          maxLength: 3
          example: "USD"
        available_amount:
          type: number
          format: decimal
          description: Calculated amount of unallocated money
        is_active:
          type: boolean
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    BudgetCreateRequest:
      type: object
      required:
        - name
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
        description:
          type: string
          maxLength: 1000
        currency:
          type: string
          minLength: 3
          maxLength: 3
          default: "USD"
        is_active:
          type: boolean
          default: true

    BudgetUpdateRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
        description:
          type: string
          maxLength: 1000
        currency:
          type: string
          minLength: 3
          maxLength: 3
        is_active:
          type: boolean

    EnvelopeType:
      type: string
      enum:
        - regular
        - debt
        - savings

    Envelope:
      type: object
      properties:
        id:
          type: string
          format: uuid
        budget_id:
          type: string
          format: uuid
        name:
          type: string
        description:
          type: string
          nullable: true
        current_balance:
          type: number
          format: decimal
          description: Current balance calculated from transactions
        target_amount:
          type: number
          format: decimal
          nullable: true
        envelope_type:
          $ref: '#/components/schemas/EnvelopeType'
        category_id:
          type: string
          format: uuid
          nullable: true
        icon:
          type: string
          nullable: true
        color:
          type: string
          nullable: true
          pattern: '^#[0-9A-Fa-f]{6}$'
        display_order:
          type: integer
        notify_on_low_balance:
          type: boolean
        low_balance_threshold:
          type: number
          format: decimal
          nullable: true
        is_active:
          type: boolean
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    EnvelopeCreateRequest:
      type: object
      required:
        - name
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
        description:
          type: string
          maxLength: 1000
        target_amount:
          type: number
          format: decimal
          minimum: 0
        envelope_type:
          $ref: '#/components/schemas/EnvelopeType'
          default: regular
        category_id:
          type: string
          format: uuid
        icon:
          type: string
        color:
          type: string
          pattern: '^#[0-9A-Fa-f]{6}$'
        display_order:
          type: integer
        notify_on_low_balance:
          type: boolean
          default: false
        low_balance_threshold:
          type: number
          format: decimal

    EnvelopeUpdateRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
        description:
          type: string
          maxLength: 1000
        target_amount:
          type: number
          format: decimal
          minimum: 0
        envelope_type:
          $ref: '#/components/schemas/EnvelopeType'
        category_id:
          type: string
          format: uuid
        icon:
          type: string
        color:
          type: string
          pattern: '^#[0-9A-Fa-f]{6}$'
        display_order:
          type: integer
        notify_on_low_balance:
          type: boolean
        low_balance_threshold:
          type: number
          format: decimal
        is_active:
          type: boolean

    TransactionType:
      type: string
      enum:
        - income
        - expense
        - transfer
        - allocation
        - debt_payment

    Transaction:
      type: object
      properties:
        id:
          type: string
          format: uuid
        budget_id:
          type: string
          format: uuid
        transaction_type:
          $ref: '#/components/schemas/TransactionType'
        amount:
          type: number
          format: decimal
          minimum: 0.01
        description:
          type: string
          nullable: true
        transaction_date:
          type: string
          format: date
        from_envelope_id:
          type: string
          format: uuid
          nullable: true
        to_envelope_id:
          type: string
          format: uuid
          nullable: true
        payee_id:
          type: string
          format: uuid
          nullable: true
        income_source_id:
          type: string
          format: uuid
          nullable: true
        category_id:
          type: string
          format: uuid
          nullable: true
        is_cleared:
          type: boolean
        is_reconciled:
          type: boolean
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        is_deleted:
          type: boolean
        deleted_at:
          type: string
          format: date-time
          nullable: true
        deleted_by:
          type: string
          format: uuid
          nullable: true

    TransactionCreateRequest:
      type: object
      required:
        - transaction_type
        - amount
        - transaction_date
      properties:
        transaction_type:
          $ref: '#/components/schemas/TransactionType'
        amount:
          type: number
          format: decimal
          minimum: 0.01
        description:
          type: string
          maxLength: 1000
        transaction_date:
          type: string
          format: date
        from_envelope_id:
          type: string
          format: uuid
          description: Required for EXPENSE, TRANSFER, DEBT_PAYMENT types
        to_envelope_id:
          type: string
          format: uuid
          description: Required for ALLOCATION, TRANSFER types
        payee_id:
          type: string
          format: uuid
          description: Required for EXPENSE, DEBT_PAYMENT types
        income_source_id:
          type: string
          format: uuid
          description: Required for INCOME type
        category_id:
          type: string
          format: uuid
        is_cleared:
          type: boolean
          default: false

    TransactionUpdateRequest:
      type: object
      properties:
        amount:
          type: number
          format: decimal
          minimum: 0.01
        description:
          type: string
          maxLength: 1000
        transaction_date:
          type: string
          format: date
        from_envelope_id:
          type: string
          format: uuid
        to_envelope_id:
          type: string
          format: uuid
        payee_id:
          type: string
          format: uuid
        income_source_id:
          type: string
          format: uuid
        category_id:
          type: string
          format: uuid
        is_cleared:
          type: boolean
        is_reconciled:
          type: boolean

    TransactionWithDetails:
      allOf:
        - $ref: '#/components/schemas/Transaction'
        - type: object
          properties:
            from_envelope:
              $ref: '#/components/schemas/Envelope'
              nullable: true
            to_envelope:
              $ref: '#/components/schemas/Envelope'
              nullable: true
            payee:
              $ref: '#/components/schemas/Payee'
              nullable: true
            income_source:
              $ref: '#/components/schemas/IncomeSource'
              nullable: true
            category:
              $ref: '#/components/schemas/Category'
              nullable: true

    # Supporting Entities
    Category:
      type: object
      properties:
        id:
          type: string
          format: uuid
        budget_id:
          type: string
          format: uuid
        name:
          type: string
        description:
          type: string
          nullable: true
        category_type:
          type: string
          enum: [income, expense, transfer, debt_payment]
        parent_category_id:
          type: string
          format: uuid
          nullable: true
        display_order:
          type: integer
        is_active:
          type: boolean
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    IncomeSource:
      type: object
      properties:
        id:
          type: string
          format: uuid
        budget_id:
          type: string
          format: uuid
        name:
          type: string
        description:
          type: string
          nullable: true
        expected_amount:
          type: number
          format: decimal
          nullable: true
        frequency_days:
          type: integer
          nullable: true
        last_received_date:
          type: string
          format: date
          nullable: true
        next_expected_date:
          type: string
          format: date
          nullable: true
        is_active:
          type: boolean
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    Payee:
      type: object
      properties:
        id:
          type: string
          format: uuid
        budget_id:
          type: string
          format: uuid
        name:
          type: string
        description:
          type: string
          nullable: true
        total_paid:
          type: number
          format: decimal
        last_payment_date:
          type: string
          format: date
          nullable: true
        is_active:
          type: boolean
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    # Dashboard & Analytics
    DashboardSummary:
      type: object
      properties:
        budget:
          $ref: '#/components/schemas/Budget'
        summary:
          type: object
          properties:
            total_income_this_month:
              type: number
              format: decimal
            total_expenses_this_month:
              type: number
              format: decimal
            total_allocated:
              type: number
              format: decimal
            available_to_allocate:
              type: number
              format: decimal
            envelope_count:
              type: integer
            negative_envelope_count:
              type: integer
        recent_transactions:
          type: array
          items:
            $ref: '#/components/schemas/TransactionWithDetails'
        envelope_balances:
          type: array
          items:
            type: object
            properties:
              envelope:
                $ref: '#/components/schemas/Envelope'
              balance:
                type: number
                format: decimal
              percentage_of_target:
                type: number
                format: decimal
                nullable: true

    SpendingStats:
      type: object
      properties:
        period:
          type: string
        total_spending:
          type: number
          format: decimal
        breakdown:
          type: array
          items:
            type: object
            properties:
              name:
                type: string
              amount:
                type: number
                format: decimal
              percentage:
                type: number
                format: decimal
              transaction_count:
                type: integer
        trends:
          type: array
          items:
            type: object
            properties:
              date:
                type: string
                format: date
              amount:
                type: number
                format: decimal

    # Error Responses
    Error:
      type: object
      properties:
        error:
          type: string
          description: Error message
        details:
          type: string
          description: Additional error details
          nullable: true
        code:
          type: string
          description: Error code
          nullable: true

  responses:
    BadRequest:
      description: Bad request
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: "Invalid request parameters"
            details: "Transaction type 'income' requires income_source_id"

    Unauthorized:
      description: Unauthorized - Invalid or missing authentication token
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: "Invalid or expired token"

    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: "Resource not found"

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

tags:
  - name: Authentication
    description: User authentication and profile management
  - name: Budgets
    description: Budget creation and management
  - name: Envelopes
    description: Virtual envelope management
  - name: Transactions
    description: Transaction creation and management
  - name: Dashboard
    description: Dashboard data and analytics
  - name: Export
    description: Data export functionality