openapi: 3.0.3
info:
  title: Carbob API - Complete Documentation
  description: |
    Documentação completa da API Carbob.
    
    A API utiliza Laravel Passport para autenticação OAuth2 com suporte a multi-tenancy.
    Todas as rotas protegidas requerem os headers `Authorization` (Bearer token) e `X-TENANT-ID`.
    
    ## Versionamento da API
    
    A API suporta acesso aos endpoints de duas formas:
    - **Rotas versionadas**: `/v1/{resource}` - Sempre funcionam, garantem compatibilidade total
    - **Rotas sem versão**: `/{resource}` - Apontam para a versão padrão configurada (atualmente v1)
    
    Exemplos:
    - `POST /v1/register` ou `POST /register` - Ambas funcionam
    - `GET /v1/clients` ou `GET /clients` - Ambas funcionam
    
    **Nota:** Rotas OAuth (`/oauth/*`) não têm versão.
    
    ## Funcionalidades principais:
    - Autenticação e gestão de utilizadores
    - Gestão de planos e contratos
    - Sistema de multi-tenancy
    - Gestão de projetos
    - Subscrições e validação de features
  version: 2.0.0
  contact:
    name: Carbob API Support
    email: support@carbob.pt
  license:
    name: MIT
    url: https://opensource.org/licenses/MIT

servers:
  - url: https://api.carbob.pt
    description: Production server
  - url: http://localhost:8000
    description: Development server

security:
  - BearerAuth: []
  - TenantAuth: []

paths:
  /v1/register:
    post:
      tags:
        - Authentication
      summary: Register new user and tenant
      description: |
        Creates a new tenant and user account in the system.
        This endpoint is public and does not require authentication.
        
        **Note:** This endpoint is also available without version prefix as `POST /register`, 
        which points to the default API version (currently v1).
      operationId: registerUser
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - tenant_name
                - name
                - email
                - password
                - password_confirmation
              properties:
                tenant_name:
                  type: string
                  maxLength: 255
                  description: Name of the tenant/company
                  example: "Empresa ABC"
                name:
                  type: string
                  maxLength: 255
                  description: Full name of the user
                  example: "João Silva"
                email:
                  type: string
                  format: email
                  maxLength: 255
                  description: User email address
                  example: "joao@empresa.com"
                password:
                  type: string
                  minLength: 8
                  description: User password
                  example: "senha123456"
                password_confirmation:
                  type: string
                  description: Password confirmation
                  example: "senha123456"
      responses:
        '201':
          description: Account created successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: "Account created successfully"
                  tenant_id:
                    type: integer
                    example: 1
                  tenant_name:
                    type: string
                    example: "Empresa ABC"
                  email:
                    type: string
                    format: email
                    example: "joao@empresa.com"
                  user_id:
                    type: integer
                    example: 1
                  contract_id:
                    type: integer
                    example: 1
                  plan_type:
                    type: string
                    example: "turbo"
                  is_trial:
                    type: boolean
                    example: true
                  trial_end_date:
                    type: string
                    format: date
                    example: "2025-02-14"
        '422':
          description: Validation error
          content:
            application/json:
              schema:
                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."]

  /v1/health:
    get:
      tags:
        - System
      summary: Health check
      description: Check API health status
      operationId: healthCheck
      responses:
        '200':
          description: API is healthy
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: "ok"
                  time:
                    type: string
                    format: date-time
                    example: "2024-01-15T10:30:00.000000Z"

  /v1/ping:
    get:
      tags:
        - System
      summary: Ping endpoint
      description: Simple ping endpoint to check connectivity
      operationId: ping
      responses:
        '200':
          description: Pong response
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: "pong"
                  timestamp:
                    type: string
                    format: date-time
                    example: "2024-01-15T10:30:00.000000Z"

  /v1/forgot-password:
    post:
      tags:
        - Authentication
      summary: Request password reset
      description: Send password reset link to user email
      operationId: forgotPassword
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - email
              properties:
                email:
                  type: string
                  format: email
                  example: "joao@empresa.com"
      responses:
        '200':
          description: Reset link sent successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: "Password reset link sent to your email"
        '422':
          description: Validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationError'

  /v1/reset-password:
    post:
      tags:
        - Authentication
      summary: Reset password
      description: Reset user password using reset token
      operationId: resetPassword
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - email
                - password
                - password_confirmation
                - token
              properties:
                email:
                  type: string
                  format: email
                  example: "joao@empresa.com"
                password:
                  type: string
                  minLength: 8
                  example: "newpassword123"
                password_confirmation:
                  type: string
                  example: "newpassword123"
                token:
                  type: string
                  example: "reset_token_here"
      responses:
        '200':
          description: Password reset successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: "Password reset successfully"
        '422':
          description: Validation error or invalid token
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationError'

  /v1/test-auth:
    get:
      tags:
        - Authentication
      summary: Test authentication
      description: Test if authentication is working correctly
      operationId: testAuth
      security:
        - BearerAuth: []
      responses:
        '200':
          description: Authentication is working
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: "Auth working"
                  user:
                    type: string
                    example: "usuario@exemplo.com"
        '401':
          description: Not authenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'

  /v1/debug-token:
    get:
      tags:
        - Authentication
      summary: Debug token information
      description: Get debug information about the current token
      operationId: debugToken
      responses:
        '200':
          description: Token debug information
          content:
            application/json:
              schema:
                type: object
                properties:
                  has_auth_header:
                    type: boolean
                    example: true
                  auth_header:
                    type: string
                    example: "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9..."
                  bearer_token:
                    type: string
                    example: "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9..."
                  user:
                    type: string
                    example: "usuario@exemplo.com"
                  guard:
                    type: string
                    example: "api"

  /oauth/token:
    post:
      tags:
        - OAuth2
      summary: OAuth2 token endpoint
      description: Standard OAuth2 token endpoint using Laravel Passport
      operationId: oauthToken
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              properties:
                grant_type:
                  type: string
                  example: "password"
                client_id:
                  type: string
                  example: "1"
                client_secret:
                  type: string
                  example: "secret"
                username:
                  type: string
                  example: "usuario@exemplo.com"
                password:
                  type: string
                  example: "senha123456"
                scope:
                  type: string
                  example: "*"
      responses:
        '200':
          description: Token generated successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  token_type:
                    type: string
                    example: "Bearer"
                  expires_in:
                    type: integer
                    example: 31536000
                  access_token:
                    type: string
                    example: "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9..."
                  refresh_token:
                    type: string
                    example: "def50200..."

  /oauth/token/refresh:
    post:
      tags:
        - OAuth2
      summary: Refresh OAuth2 token
      description: Refresh an expired OAuth2 token
      operationId: refreshToken
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              properties:
                grant_type:
                  type: string
                  example: "refresh_token"
                refresh_token:
                  type: string
                  example: "def50200..."
                client_id:
                  type: string
                  example: "1"
                client_secret:
                  type: string
                  example: "secret"
      responses:
        '200':
          description: Token refreshed successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  token_type:
                    type: string
                    example: "Bearer"
                  expires_in:
                    type: integer
                    example: 31536000
                  access_token:
                    type: string
                    example: "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9..."
                  refresh_token:
                    type: string
                    example: "def50200..."

  /v1/plans:
    get:
      tags:
        - Plans
      summary: List all available plans
      description: Get a list of all available subscription plans with their features and pricing
      operationId: getPlans
      responses:
        '200':
          description: Plans retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Plan'

  /v1/plans/compare:
    get:
      tags:
        - Plans
      summary: Compare all plans
      description: Get a detailed comparison of all plans with features and limits
      operationId: comparePlans
      responses:
        '200':
          description: Plan comparison retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  plans:
                    type: array
                    items:
                      $ref: '#/components/schemas/Plan'
                  comparison:
                    type: object
                    description: Feature comparison matrix

  /v1/plans/{type}:
    get:
      tags:
        - Plans
      summary: Get specific plan details
      description: Get detailed information about a specific plan
      operationId: getPlan
      parameters:
        - name: type
          in: path
          required: true
          description: Plan type
          schema:
            type: string
            enum: [ignition, cruise, turbo]
            example: turbo
      responses:
        '200':
          description: Plan details retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/Plan'
        '404':
          description: Plan not found
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: "Plan not found"

  /v1/tenant/status:
    get:
      tags:
        - Subscription Management
      summary: Get tenant subscription status
      description: |
        Get the current subscription status for the authenticated tenant (from X-TENANT-ID header).
        This endpoint is accessible even when subscription is expired.
      operationId: getTenantSubscriptionStatus
      security:
        - BearerAuth: []
        - TenantAuth: []
      responses:
        '200':
          description: Subscription status retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  valid:
                    type: boolean
                    description: Whether the subscription is valid
                    example: true
                  reason:
                    type: string
                    description: Reason for validity status
                    example: "valid"
                  start_date:
                    type: string
                    format: date
                    description: Subscription start date
                    example: "2025-01-15"
                  end_date:
                    type: string
                    format: date
                    nullable: true
                    description: Subscription end date (null if no end)
                    example: "2025-12-31"
                  is_trial:
                    type: boolean
                    description: Whether account is in trial period
                    example: true
                  trial_end:
                    type: string
                    format: date-time
                    nullable: true
                    description: Trial end date
                    example: "2025-02-14T00:00:00+00:00"
                  account_status:
                    type: string
                    description: Account status
                    example: "active"
                  lifecycle_state:
                    type: string
                    description: Lifecycle state
                    example: "client"
        '403':
          description: Unauthorized - user doesn't belong to tenant
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '404':
          description: Tenant not found
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: "Tenant not found"

  /v1/tenant/subscription:
    put:
      tags:
        - Subscription Management
      summary: Update tenant subscription
      description: |
        Update subscription details for the authenticated tenant (from X-TENANT-ID header).
        This endpoint is accessible even when subscription is expired.
      operationId: updateTenantSubscription
      security:
        - BearerAuth: []
        - TenantAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - account_status
                - lifecycle_state
              properties:
                account_status:
                  type: string
                  enum: [active, inactive]
                  description: Account activation status
                  example: "active"
                lifecycle_state:
                  type: string
                  enum: [lead, client, churn, lead_lost]
                  description: Business lifecycle stage
                  example: "client"
                start_date:
                  type: string
                  format: date
                  description: Subscription start date
                  example: "2025-01-15"
                end_date:
                  type: string
                  format: date
                  nullable: true
                  description: Subscription end date (null for no end)
                  example: "2025-12-31"
      responses:
        '200':
          description: Subscription updated successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: "Subscription updated successfully"
                  subscription:
                    type: object
                    properties:
                      valid:
                        type: boolean
                        example: true
                      reason:
                        type: string
                        example: "valid"
                      start_date:
                        type: string
                        format: date
                        example: "2025-01-15"
                      end_date:
                        type: string
                        format: date
                        example: "2025-12-31"
                      is_trial:
                        type: boolean
                        example: false
                      account_status:
                        type: string
                        example: "active"
                      lifecycle_state:
                        type: string
                        example: "client"
        '403':
          description: Unauthorized - user doesn't belong to tenant
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '404':
          description: Tenant not found
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: "Tenant not found"
        '422':
          description: Validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationError'

  /v1/contracts:
    get:
      tags:
        - Contract Management
      summary: Get tenant contracts
      description: Get all contracts for the authenticated tenant (from X-TENANT-ID header)
      operationId: getTenantContracts
      security:
        - BearerAuth: []
        - TenantAuth: []
      responses:
        '200':
          description: Contracts retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Contract'
                  meta:
                    type: object
                    properties:
                      total:
                        type: integer
                        example: 1
                      tenant_id:
                        type: integer
                        example: 1
                      current_contract_id:
                        type: integer
                        example: 1
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '404':
          description: Tenant not found
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: "TENANT_NOT_FOUND"
                  message:
                    type: string
                    example: "Tenant not found"

    post:
      tags:
        - Contract Management
      summary: Create new contract
      description: Create a new contract for the authenticated tenant (from X-TENANT-ID header)
      operationId: createTenantContract
      security:
        - BearerAuth: []
        - TenantAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - plan_type
                - billing_cycle
              properties:
                plan_type:
                  type: string
                  enum: [ignition, cruise, turbo]
                  example: ignition
                billing_cycle:
                  type: string
                  enum: [monthly, quarterly, annual]
                  example: monthly
                is_trial:
                  type: boolean
                  example: false
                add_ons:
                  type: array
                  items:
                    type: string
                  example: ["advanced_analytics"]
                notes:
                  type: string
                  maxLength: 1000
                  example: "New contract created via API"
      responses:
        '201':
          description: Contract created successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: "Contract created successfully"
                  data:
                    $ref: '#/components/schemas/Contract'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
        '404':
          description: Tenant not found
        '422':
          description: Validation error

  /v1/contracts/{contract}:
    delete:
      tags:
        - Contract Management
      summary: Cancel contract
      description: Cancel a specific contract for the authenticated tenant (from X-TENANT-ID header)
      operationId: cancelTenantContract
      security:
        - BearerAuth: []
        - TenantAuth: []
      parameters:
        - name: contract
          in: path
          required: true
          description: Contract ID
          schema:
            type: integer
            example: 1
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                notes:
                  type: string
                  example: "Contract cancelled via API"
      responses:
        '200':
          description: Contract cancelled successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: "Contract cancelled successfully"
                  data:
                    type: object
                    properties:
                      contract_id:
                        type: integer
                        example: 1
                      cancelled_at:
                        type: string
                        format: date-time
                      status:
                        type: string
                        example: "cancelled"
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
        '404':
          description: Contract not found
        '422':
          description: Contract already cancelled

  /v1/contracts/upgrade:
    post:
      tags:
        - Contract Management
      summary: Upgrade tenant plan
      description: Upgrade authenticated tenant to a higher plan with prorated credit (tenant from X-TENANT-ID header)
      operationId: upgradeTenantPlan
      security:
        - BearerAuth: []
        - TenantAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - plan_type
                - billing_cycle
              properties:
                plan_type:
                  type: string
                  enum: [ignition, cruise, turbo]
                  example: turbo
                billing_cycle:
                  type: string
                  enum: [monthly, quarterly, annual]
                  example: monthly
                add_ons:
                  type: array
                  items:
                    type: string
                  example: ["advanced_analytics"]
                notes:
                  type: string
                  example: "Upgrade from trial to Turbo plan"
      responses:
        '200':
          description: Plan upgraded successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: "Plan upgraded successfully"
                  data:
                    $ref: '#/components/schemas/Contract'
                  meta:
                    type: object
                    properties:
                      previous_plan:
                        type: string
                        example: "turbo"
                      credit_applied:
                        type: number
                        example: 15.50
                      upgrade_date:
                        type: string
                        format: date-time
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
        '404':
          description: Tenant not found
        '422':
          description: Upgrade not allowed or no active contract

  /v1/contracts/downgrade:
    post:
      tags:
        - Contract Management
      summary: Downgrade tenant plan
      description: Downgrade authenticated tenant to a lower plan with prorated credit (tenant from X-TENANT-ID header)
      operationId: downgradeTenantPlan
      security:
        - BearerAuth: []
        - TenantAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - plan_type
                - billing_cycle
              properties:
                plan_type:
                  type: string
                  enum: [ignition, cruise, turbo]
                  example: ignition
                billing_cycle:
                  type: string
                  enum: [monthly, quarterly, annual]
                  example: monthly
                add_ons:
                  type: array
                  items:
                    type: string
                  example: []
                notes:
                  type: string
                  example: "Downgrade to reduce costs"
      responses:
        '200':
          description: Plan downgraded successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: "Plan downgraded successfully"
                  data:
                    $ref: '#/components/schemas/Contract'
                  meta:
                    type: object
                    properties:
                      previous_plan:
                        type: string
                        example: "turbo"
                      credit_applied:
                        type: number
                        example: 150.00
                      downgrade_date:
                        type: string
                        format: date-time
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
        '404':
          description: Tenant not found
        '422':
          description: Downgrade not allowed or no active contract

  /v1/user:
    get:
      tags:
        - User Management
      summary: Get authenticated user
      description: Get current authenticated user details
      operationId: getUser
      security:
        - BearerAuth: []
        - TenantAuth: []
      responses:
        '200':
          description: User retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/User'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
    
    put:
      tags:
        - User Management
      summary: Update user profile
      description: Update authenticated user profile information
      operationId: updateUser
      security:
        - BearerAuth: []
        - TenantAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  maxLength: 255
                  example: "João Silva"
                email:
                  type: string
                  format: email
                  maxLength: 255
                  example: "joao@empresa.com"
      responses:
        '200':
          description: User updated successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: "User updated successfully"
                  data:
                    $ref: '#/components/schemas/User'
        '401':
          description: Unauthorized
        '422':
          description: Validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationError'

  /v1/user/change-password:
    post:
      tags:
        - User Management
      summary: Change user password
      description: Change the authenticated user's password
      operationId: changePassword
      security:
        - BearerAuth: []
        - TenantAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - current_password
                - password
                - password_confirmation
              properties:
                current_password:
                  type: string
                  description: Current password
                  example: "oldpassword123"
                password:
                  type: string
                  minLength: 8
                  description: New password
                  example: "newpassword123"
                password_confirmation:
                  type: string
                  description: New password confirmation
                  example: "newpassword123"
      responses:
        '200':
          description: Password changed successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: "Password changed successfully"
        '401':
          description: Unauthorized or incorrect current password
        '422':
          description: Validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationError'

  /v1/users:
    get:
      tags:
        - User Management
      summary: List users
      description: |
        Get all users for the authenticated tenant.
        Requires `manage_users` permission.
      operationId: getUsers
      security:
        - BearerAuth: []
        - TenantAuth: []
      responses:
        '200':
          description: Users retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  users:
                    type: array
                    items:
                      $ref: '#/components/schemas/UserWithRoles'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '403':
          description: Forbidden - missing manage_users permission
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'

    post:
      tags:
        - User Management
      summary: Create user
      description: |
        Create a new user in the authenticated tenant.
        Requires `manage_users` permission.
      operationId: createUser
      security:
        - BearerAuth: []
        - TenantAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - name
                - email
                - password
                - password_confirmation
                - users_role_ids
              properties:
                name:
                  type: string
                  maxLength: 255
                  example: "Maria Santos"
                email:
                  type: string
                  format: email
                  maxLength: 255
                  description: Must be globally unique
                  example: "maria@empresa.com"
                password:
                  type: string
                  minLength: 8
                  example: "senha123456"
                password_confirmation:
                  type: string
                  example: "senha123456"
                users_role_ids:
                  type: array
                  minItems: 1
                  items:
                    type: integer
                  description: Array of role IDs to assign to the user
                  example: [2, 3]
                send_welcome_email:
                  type: boolean
                  default: false
                  example: true
      responses:
        '201':
          description: User created successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: "User created successfully"
                  user:
                    $ref: '#/components/schemas/UserWithRoles'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden - missing manage_users permission
        '422':
          description: Validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationError'

  /v1/users/{user}:
    get:
      tags:
        - User Management
      summary: Get user details
      description: |
        Get details of a specific user in the authenticated tenant.
        Requires `manage_users` permission.
      operationId: getUserDetails
      security:
        - BearerAuth: []
        - TenantAuth: []
      parameters:
        - name: user
          in: path
          required: true
          description: User ID
          schema:
            type: integer
            example: 1
      responses:
        '200':
          description: User retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserWithRoles'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden - user doesn't belong to tenant or missing permission
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: "Unauthorized"
        '404':
          description: User not found
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: "User not found"

  /v1/users/{user}/roles:
    put:
      tags:
        - User Management
      summary: Update user roles
      description: |
        Update roles assigned to a user in the authenticated tenant.
        Requires `manage_users` permission.
      operationId: updateUserRoles
      security:
        - BearerAuth: []
        - TenantAuth: []
      parameters:
        - name: user
          in: path
          required: true
          description: User ID
          schema:
            type: integer
            example: 1
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - users_role_ids
              properties:
                users_role_ids:
                  type: array
                  minItems: 1
                  items:
                    type: integer
                  description: Array of role IDs to assign to the user
                  example: [1, 2]
      responses:
        '200':
          description: User roles updated successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: "User roles updated"
        '401':
          description: Unauthorized
        '403':
          description: Forbidden - user doesn't belong to tenant or missing permission
        '404':
          description: User not found
        '422':
          description: Validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationError'

  /v1/users/{user}/deactivate:
    patch:
      tags:
        - User Management
      summary: Deactivate user
      description: |
        Deactivate a user in the authenticated tenant.
        Cannot deactivate the tenant owner.
        Requires `manage_users` permission.
      operationId: deactivateUser
      security:
        - BearerAuth: []
        - TenantAuth: []
      parameters:
        - name: user
          in: path
          required: true
          description: User ID
          schema:
            type: integer
            example: 1
      responses:
        '200':
          description: User deactivated successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: "User deactivated"
        '400':
          description: Bad request - cannot deactivate owner
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: "Cannot deactivate owner"
        '401':
          description: Unauthorized
        '403':
          description: Forbidden - user doesn't belong to tenant or missing permission
        '404':
          description: User not found

  /v1/users/invitations:
    post:
      tags:
        - User Management
      summary: Invite user
      description: |
        Create a user invitation for the authenticated tenant.
        Email must be globally unique (rejects if user already exists).
        Rejects duplicate pending invitations for the same tenant and email.
        Requires `manage_users` permission.
      operationId: inviteUser
      security:
        - BearerAuth: []
        - TenantAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - email
                - users_role_id
              properties:
                email:
                  type: string
                  format: email
                  description: Must be globally unique
                  example: "newuser@example.com"
                users_role_id:
                  type: integer
                  description: Role ID to assign to the invited user
                  example: 2
      responses:
        '201':
          description: User invitation created successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: "User invitation created"
                  invitation:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 10
                      email:
                        type: string
                        format: email
                        example: "newuser@example.com"
                      expires_at:
                        type: string
                        format: date-time
                        example: "2025-11-01T00:00:00.000000Z"
        '401':
          description: Unauthorized
        '403':
          description: Forbidden - missing manage_users permission
        '422':
          description: Validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationError'
                example:
                  message: "The given data was invalid."
                  errors:
                    email: ["This email is already associated with a user."]

  /v1/users/roles:
    get:
      tags:
        - User Management
      summary: List available roles
      description: |
        Get all available roles for the authenticated tenant (system roles + tenant custom roles).
        Requires `manage_users` permission.
      operationId: getUsersRoles
      security:
        - BearerAuth: []
        - TenantAuth: []
      responses:
        '200':
          description: Roles retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  roles:
                    type: array
                    items:
                      $ref: '#/components/schemas/Role'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '403':
          description: Forbidden - missing manage_users permission
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'

  /v1/users/roles/system:
    get:
      tags:
        - User Management
      summary: List system roles
      description: |
        Get only the fixed system roles (Administrator, Manager, Backoffice, Mechanic).
        This endpoint returns only roles with `is_system_role = true` and `tenant_id = null`.
        Requires `manage_users` permission.
      operationId: getSystemRoles
      security:
        - BearerAuth: []
        - TenantAuth: []
      responses:
        '200':
          description: System roles retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  roles:
                    type: array
                    items:
                      $ref: '#/components/schemas/Role'
                    description: Array containing only system roles
                    example:
                      - id: 1
                        name: "administrator"
                        display_name: "Administrator"
                        description: "Full access to all features and settings"
                        is_system_role: true
                        permissions: ["manage_users", "manage_settings", "view_analytics", "view_reports", "view_clients", "manage_clients", "view_clients_fleets", "manage_clients_fleets", "manage_billing", "manage_contracts", "view_own_tasks"]
                      - id: 2
                        name: "manager"
                        display_name: "Manager"
                        description: null
                        is_system_role: true
                        permissions: ["view_analytics", "view_reports", "view_clients", "manage_clients", "view_clients_fleets", "manage_clients_fleets"]
                      - id: 3
                        name: "backoffice"
                        display_name: "Backoffice"
                        description: "Handles administrative tasks and billing"
                        is_system_role: true
                        permissions: ["manage_billing", "view_reports", "manage_contracts"]
                      - id: 4
                        name: "mechanic"
                        display_name: "Mechanic"
                        description: "Works on tasks"
                        is_system_role: true
                        permissions: ["view_own_tasks"]
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '403':
          description: Forbidden - missing manage_users permission
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'

  /v1/clients:
    get:
      tags:
        - Clients
      summary: List all clients
      description: Get all clients for the authenticated tenant
      operationId: getClients
      security:
        - BearerAuth: []
        - TenantAuth: []
      responses:
        '200':
          description: Clients retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Client'
        '401':
          description: Unauthorized
        '403':
          description: Subscription expired or feature not available

    post:
      tags:
        - Clients
      summary: Create new client
      description: Create a new client for the authenticated tenant
      operationId: createClient
      security:
        - BearerAuth: []
        - TenantAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - name
                - type
              properties:
                name:
                  type: string
                  maxLength: 255
                  example: "Jane"
                lastname:
                  type: string
                  maxLength: 255
                  nullable: true
                  example: "Doe"
                email:
                  type: string
                  format: email
                  nullable: true
                  example: "jane.doe@example.com"
                phone:
                  type: string
                  maxLength: 50
                  nullable: true
                  example: "+351912345678"
                address:
                  type: string
                  nullable: true
                  example: "Rua das Flores 10"
                postal_code:
                  type: string
                  maxLength: 20
                  nullable: true
                  example: "1000-001"
                local:
                  type: string
                  maxLength: 255
                  nullable: true
                  example: "Lisboa"
                country:
                  type: string
                  maxLength: 100
                  nullable: true
                  example: "Portugal"
                fiscal_id:
                  type: string
                  maxLength: 50
                  nullable: true
                  example: "123456789"
                type:
                  type: string
                  enum: [individual, business]
                  example: "individual"
      responses:
        '201':
          description: Client created successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/Client'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden or subscription expired
        '422':
          description: Validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationError'

  /v1/clients/{client}:
    get:
      tags:
        - Clients
      summary: Get client details
      description: Get details of a specific client
      operationId: getClient
      security:
        - BearerAuth: []
        - TenantAuth: []
      parameters:
        - name: client
          in: path
          required: true
          description: Client ID
          schema:
            type: integer
            example: 42
      responses:
        '200':
          description: Client retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/Client'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden or subscription expired
        '404':
          description: Client not found

    put:
      tags:
        - Clients
      summary: Update client
      description: Update an existing client
      operationId: updateClient
      security:
        - BearerAuth: []
        - TenantAuth: []
      parameters:
        - name: client
          in: path
          required: true
          description: Client ID
          schema:
            type: integer
            example: 42
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  maxLength: 255
                  example: "Jane"
                lastname:
                  type: string
                  maxLength: 255
                  nullable: true
                  example: "Doe"
                email:
                  type: string
                  format: email
                  nullable: true
                  example: "jane.doe@example.com"
                phone:
                  type: string
                  maxLength: 50
                  nullable: true
                  example: "+351913333333"
                address:
                  type: string
                  nullable: true
                  example: "Rua das Flores 10"
                postal_code:
                  type: string
                  maxLength: 20
                  nullable: true
                  example: "1000-001"
                local:
                  type: string
                  maxLength: 255
                  nullable: true
                  example: "Lisboa"
                country:
                  type: string
                  maxLength: 100
                  nullable: true
                  example: "Portugal"
                fiscal_id:
                  type: string
                  maxLength: 50
                  nullable: true
                  example: "123456789"
                type:
                  type: string
                  enum: [individual, business]
                  example: "business"
      responses:
        '200':
          description: Client updated successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/Client'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden or subscription expired
        '404':
          description: Client not found
        '422':
          description: Validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationError'

    delete:
      tags:
        - Clients
      summary: Delete client
      description: Delete an existing client
      operationId: deleteClient
      security:
        - BearerAuth: []
        - TenantAuth: []
      parameters:
        - name: client
          in: path
          required: true
          description: Client ID
          schema:
            type: integer
            example: 42
      responses:
        '200':
          description: Client deleted successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: "Client deleted successfully"
        '401':
          description: Unauthorized
        '403':
          description: Forbidden or subscription expired
        '404':
          description: Client not found

  /v1/fleets:
    get:
      tags:
        - Fleets
      summary: List all client fleet assignments
      description: Get all client fleet assignments for the authenticated tenant
      operationId: getClientsFleets
      security:
        - BearerAuth: []
        - TenantAuth: []
      responses:
        '200':
          description: Client fleet assignments retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/ClientsFleet'
        '401':
          description: Unauthorized
        '403':
          description: Subscription expired or feature not available

    post:
      tags:
        - Fleets
      summary: Create new client fleet assignment
      description: Create a new client fleet assignment for the authenticated tenant
      operationId: createClientsFleet
      security:
        - BearerAuth: []
        - TenantAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - fleet_id
                - client_id
                - name
              properties:
                fleet_id:
                  type: integer
                  example: 12345
                client_id:
                  type: integer
                  example: 42
                name:
                  type: string
                  maxLength: 255
                  example: "Fleet Lisbon"
                status:
                  type: string
                  enum: [active, inactive]
                  example: "active"
      responses:
        '201':
          description: Client fleet assignment created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClientsFleet'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden or subscription expired
        '422':
          description: Validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationError'

  /v1/clients/{client}/fleets:
    get:
      tags:
        - Clients
      summary: List client fleet assignments for a specific client
      description: Get all client fleet assignments for the provided client within the authenticated tenant
      operationId: getClientFleets
      security:
        - BearerAuth: []
        - TenantAuth: []
      parameters:
        - name: client
          in: path
          required: true
          description: Client identifier (`clients.client_id`)
          schema:
            type: integer
            example: 42
      responses:
        '200':
          description: Client fleet assignments retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/ClientsFleet'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden or subscription expired
        '404':
          description: Client not found

    post:
      tags:
        - Clients
      summary: Create client fleet assignment for a specific client
      description: Create a new client fleet assignment for the provided client
      operationId: createClientFleetForClient
      security:
        - BearerAuth: []
        - TenantAuth: []
      parameters:
        - name: client
          in: path
          required: true
          description: Client identifier (`clients.client_id`)
          schema:
            type: integer
            example: 42
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - fleet_id
                - name
              properties:
                fleet_id:
                  type: integer
                  example: 12345
                name:
                  type: string
                  maxLength: 255
                  example: "Fleet Lisbon"
                status:
                  type: string
                  enum: [active, inactive]
                  example: "active"
      responses:
        '201':
          description: Client fleet assignment created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClientsFleet'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden or subscription expired
        '404':
          description: Client not found
        '422':
          description: Validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationError'

  /v1/fleets/{fleet}:
    get:
      tags:
        - Fleets
      summary: Get client fleet assignment details
      description: Get details of a specific client fleet assignment
      operationId: getClientsFleet
      security:
        - BearerAuth: []
        - TenantAuth: []
      parameters:
        - name: fleet
          in: path
          required: true
          description: Client fleet assignment ID
          schema:
            type: integer
            example: 7
      responses:
        '200':
          description: Client fleet assignment retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClientsFleet'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden or subscription expired
        '404':
          description: Client fleet assignment not found

    put:
      tags:
        - Fleets
      summary: Update client fleet assignment
      description: Update an existing client fleet assignment
      operationId: updateClientsFleet
      security:
        - BearerAuth: []
        - TenantAuth: []
      parameters:
        - name: fleet
          in: path
          required: true
          description: Client fleet assignment ID
          schema:
            type: integer
            example: 7
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                fleet_id:
                  type: integer
                  example: 54321
                client_id:
                  type: integer
                  example: 42
                name:
                  type: string
                  maxLength: 255
                  example: "Fleet Lisbon - VIP"
                status:
                  type: string
                  enum: [active, inactive]
                  example: "inactive"
      responses:
        '200':
          description: Client fleet assignment updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClientsFleet'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden or subscription expired
        '404':
          description: Client fleet assignment not found
        '422':
          description: Validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationError'

    delete:
      tags:
        - Fleets
      summary: Delete client fleet assignment
      description: Delete an existing client fleet assignment
      operationId: deleteClientsFleet
      security:
        - BearerAuth: []
        - TenantAuth: []
      parameters:
        - name: fleet
          in: path
          required: true
          description: Client fleet assignment ID
          schema:
            type: integer
            example: 7
      responses:
        '200':
          description: Client fleet assignment deleted successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: "Client fleet deleted successfully"
        '401':
          description: Unauthorized
        '403':
          description: Forbidden or subscription expired
        '404':
          description: Client fleet assignment not found

  /v1/vehicles:
    get:
      tags:
        - Vehicles
      summary: List all vehicles
      description: Get all vehicles for the authenticated tenant with pagination and filters
      operationId: getVehicles
      security:
        - BearerAuth: []
        - TenantAuth: []
      parameters:
        - name: client_id
          in: query
          description: Filter by client ID
          schema:
            type: integer
            example: 42
        - name: fleet_id
          in: query
          description: Filter by fleet ID
          schema:
            type: integer
            example: 12345
        - name: brand_id
          in: query
          description: Filter by brand ID
          schema:
            type: integer
            example: 1
        - name: model_id
          in: query
          description: Filter by model ID
          schema:
            type: integer
            example: 5
        - name: status
          in: query
          description: Filter by status
          schema:
            type: string
            enum: [active, inactive, sold, scrapped]
            example: active
        - name: search
          in: query
          description: Search in plate number and VIN
          schema:
            type: string
            example: "AB-12"
      responses:
        '200':
          description: Vehicles retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Vehicle'
                  links:
                    type: object
                  meta:
                    type: object
        '401':
          description: Unauthorized
        '403':
          description: Subscription expired or feature not available

    post:
      tags:
        - Vehicles
      summary: Create new vehicle
      description: Create a new vehicle for the authenticated tenant
      operationId: createVehicle
      security:
        - BearerAuth: []
        - TenantAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - client_id
                - brand_id
                - model_id
                - type
                - plate_number
              properties:
                client_id:
                  type: integer
                  example: 42
                fleet_id:
                  type: integer
                  nullable: true
                  example: 12345
                brand_id:
                  type: integer
                  example: 1
                model_id:
                  type: integer
                  example: 5
                version_id:
                  type: integer
                  nullable: true
                  example: 25
                type:
                  type: string
                  enum: [car, motorcycle, van, truck, bus, other]
                  example: car
                plate_number:
                  type: string
                  maxLength: 20
                  example: "AB-12-CD"
                vin:
                  type: string
                  maxLength: 17
                  nullable: true
                  example: "WBA3A5C58EF123456"
                chassis_number:
                  type: string
                  nullable: true
                  example: "CH123456"
                color:
                  type: string
                  maxLength: 50
                  nullable: true
                  example: "Black"
                year:
                  type: integer
                  nullable: true
                  minimum: 1900
                  example: 2020
                registration_date:
                  type: string
                  format: date
                  nullable: true
                  example: "2020-01-15"
                purchase_date:
                  type: string
                  format: date
                  nullable: true
                  example: "2020-01-10"
                purchase_price:
                  type: number
                  format: decimal
                  nullable: true
                  example: 35000.00
                custom_version:
                  type: string
                  nullable: true
                  example: "Custom Edition"
                motor:
                  type: string
                  nullable: true
                  example: "2.0 TDI"
                description:
                  type: string
                  nullable: true
                  example: "BMW Série 3 320d"
                notes:
                  type: string
                  nullable: true
                status:
                  type: string
                  enum: [active, inactive, sold, scrapped]
                  example: active
      responses:
        '201':
          description: Vehicle created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Vehicle'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden or subscription expired
        '422':
          description: Validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationError'

  /v1/vehicles/{vehicle}:
    get:
      tags:
        - Vehicles
      summary: Get vehicle details
      description: Get details of a specific vehicle including ownership history
      operationId: getVehicle
      security:
        - BearerAuth: []
        - TenantAuth: []
      parameters:
        - name: vehicle
          in: path
          required: true
          description: Vehicle ID
          schema:
            type: integer
            example: 1
      responses:
        '200':
          description: Vehicle retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VehicleWithRelations'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden or subscription expired
        '404':
          description: Vehicle not found

    put:
      tags:
        - Vehicles
      summary: Update vehicle
      description: Update an existing vehicle
      operationId: updateVehicle
      security:
        - BearerAuth: []
        - TenantAuth: []
      parameters:
        - name: vehicle
          in: path
          required: true
          description: Vehicle ID
          schema:
            type: integer
            example: 1
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                client_id:
                  type: integer
                  example: 42
                fleet_id:
                  type: integer
                  nullable: true
                  example: 12345
                brand_id:
                  type: integer
                  example: 1
                model_id:
                  type: integer
                  example: 5
                version_id:
                  type: integer
                  nullable: true
                  example: 25
                type:
                  type: string
                  enum: [car, motorcycle, van, truck, bus, other]
                  example: car
                plate_number:
                  type: string
                  maxLength: 20
                  example: "AB-12-CD"
                vin:
                  type: string
                  maxLength: 17
                  nullable: true
                  example: "WBA3A5C58EF123456"
                color:
                  type: string
                  maxLength: 50
                  nullable: true
                  example: "White"
                year:
                  type: integer
                  nullable: true
                  example: 2021
                status:
                  type: string
                  enum: [active, inactive, sold, scrapped]
                  example: inactive
      responses:
        '200':
          description: Vehicle updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Vehicle'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden or subscription expired
        '404':
          description: Vehicle not found
        '422':
          description: Validation error

    delete:
      tags:
        - Vehicles
      summary: Delete vehicle
      description: Delete an existing vehicle
      operationId: deleteVehicle
      security:
        - BearerAuth: []
        - TenantAuth: []
      parameters:
        - name: vehicle
          in: path
          required: true
          description: Vehicle ID
          schema:
            type: integer
            example: 1
      responses:
        '200':
          description: Vehicle deleted successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: "Vehicle deleted successfully"
        '401':
          description: Unauthorized
        '403':
          description: Forbidden or subscription expired
        '404':
          description: Vehicle not found

  /v1/vehicles/{vehicle}/transfer:
    post:
      tags:
        - Vehicles
      summary: Transfer vehicle to new owner
      description: Transfer a vehicle to a new owner, maintaining complete ownership history
      operationId: transferVehicle
      security:
        - BearerAuth: []
        - TenantAuth: []
      parameters:
        - name: vehicle
          in: path
          required: true
          description: Vehicle ID
          schema:
            type: integer
            example: 1
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - client_id
                - ownership_start_date
              properties:
                client_id:
                  type: integer
                  description: ID of the new owner
                  example: 50
                ownership_start_date:
                  type: string
                  format: date
                  description: Start date of new ownership
                  example: "2025-11-25"
                transfer_reason:
                  type: string
                  maxLength: 255
                  nullable: true
                  description: Reason for transfer
                  example: "Venda"
                transfer_notes:
                  type: string
                  nullable: true
                  description: Additional notes about the transfer
                  example: "Vendido a cliente externo"
      responses:
        '200':
          description: Vehicle transferred successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: "Vehicle transferred successfully"
                  vehicle:
                    $ref: '#/components/schemas/Vehicle'
                  new_owner:
                    $ref: '#/components/schemas/VehicleOwner'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden or subscription expired
        '404':
          description: Vehicle not found
        '422':
          description: Validation error or vehicle already owned by this client

  /v1/change-history/{source}/{source_id}:
    get:
      tags:
        - Change History
      summary: Get change history for an entity
      description: |
        Retrieve the change history (audit trail) for a specific entity.
        Returns all changes (creates and updates) made to the entity, including who made the change and when.
        The tenant is automatically validated from the X-TENANT-ID header.
      operationId: getChangeHistory
      security:
        - BearerAuth: []
        - TenantAuth: []
      parameters:
        - name: source
          in: path
          required: true
          description: Type of entity (e.g., 'client', 'clients_fleet')
          schema:
            type: string
            example: "client"
        - name: source_id
          in: path
          required: true
          description: ID of the entity record
          schema:
            type: integer
            example: 123
      responses:
        '200':
          description: Change history retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/ChangeHistory'
                  meta:
                    type: object
                    properties:
                      tenant_id:
                        type: integer
                        example: 1
                      source:
                        type: string
                        example: "client"
                      source_id:
                        type: integer
                        example: 123
                      total:
                        type: integer
                        example: 2
        '401':
          description: Unauthorized
        '403':
          description: Forbidden - Tenant context not found
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: "TENANT_NOT_FOUND"
                  message:
                    type: string
                    example: "Tenant context not found"
        '404':
          description: No change history found for the specified source and tenant
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: "NOT_FOUND"
                  message:
                    type: string
                    example: "No change history found for the specified source and tenant"

  /v1/vehicle-catalog/brands:
    get:
      tags:
        - Vehicle Catalog
      summary: List all vehicle brands
      description: |
        Get a list of all active vehicle brands.
        This endpoint is public and does not require authentication.
      operationId: getVehicleBrands
      responses:
        '200':
          description: Brands retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/VehicleBrand'
                  meta:
                    type: object
                    properties:
                      total:
                        type: integer
                        example: 10

  /v1/vehicle-catalog/brands/{brand}:
    get:
      tags:
        - Vehicle Catalog
      summary: Get brand details with models
      description: Get details of a specific brand including its models
      operationId: getVehicleBrand
      parameters:
        - name: brand
          in: path
          required: true
          description: Brand ID
          schema:
            type: integer
            example: 1
      responses:
        '200':
          description: Brand retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/VehicleBrandWithModels'
        '404':
          description: Brand not found
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: "BRAND_NOT_FOUND"
                  message:
                    type: string
                    example: "Brand not found or inactive"

  /v1/vehicle-catalog/brands/{brand}/models:
    get:
      tags:
        - Vehicle Catalog
      summary: List models for a brand
      description: Get all active models for a specific brand
      operationId: getBrandModels
      parameters:
        - name: brand
          in: path
          required: true
          description: Brand ID
          schema:
            type: integer
            example: 1
      responses:
        '200':
          description: Models retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/VehicleModel'
                  meta:
                    type: object
                    properties:
                      brand_id:
                        type: integer
                        example: 1
                      brand_name:
                        type: string
                        example: "BMW"
                      total:
                        type: integer
                        example: 5
        '404':
          description: Brand not found

  /v1/vehicle-catalog/models/{model}:
    get:
      tags:
        - Vehicle Catalog
      summary: Get model details with versions
      description: Get details of a specific model including its versions
      operationId: getVehicleModel
      parameters:
        - name: model
          in: path
          required: true
          description: Model ID
          schema:
            type: integer
            example: 5
      responses:
        '200':
          description: Model retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/VehicleModelWithVersions'
        '404':
          description: Model not found

  /v1/vehicle-catalog/models/{model}/versions:
    get:
      tags:
        - Vehicle Catalog
      summary: List versions for a model
      description: Get all active versions for a specific model
      operationId: getModelVersions
      parameters:
        - name: model
          in: path
          required: true
          description: Model ID
          schema:
            type: integer
            example: 5
      responses:
        '200':
          description: Versions retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/VehicleVersion'
                  meta:
                    type: object
                    properties:
                      model_id:
                        type: integer
                        example: 5
                      model_name:
                        type: string
                        example: "Série 3"
                      brand_id:
                        type: integer
                        example: 1
                      brand_name:
                        type: string
                        example: "BMW"
                      total:
                        type: integer
                        example: 8
        '404':
          description: Model not found

  /v1/vehicle-catalog/versions/{version}:
    get:
      tags:
        - Vehicle Catalog
      summary: Get version details
      description: Get full details of a specific vehicle version
      operationId: getVehicleVersion
      parameters:
        - name: version
          in: path
          required: true
          description: Version ID
          schema:
            type: integer
            example: 25
      responses:
        '200':
          description: Version retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/VehicleVersionFull'
        '404':
          description: Version not found

  /v1/vehicle-catalog/search/{query}:
    get:
      tags:
        - Vehicle Catalog
      summary: Search vehicles
      description: Search for brands, models, or versions by name
      operationId: searchVehicles
      parameters:
        - name: query
          in: path
          required: true
          description: Search query
          schema:
            type: string
            example: "320"
      responses:
        '200':
          description: Search results
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      brands:
                        type: array
                        items:
                          $ref: '#/components/schemas/VehicleBrand'
                      models:
                        type: array
                        items:
                          $ref: '#/components/schemas/VehicleModel'
                      versions:
                        type: array
                        items:
                          $ref: '#/components/schemas/VehicleVersion'
                  meta:
                    type: object
                    properties:
                      query:
                        type: string
                        example: "320"
                      total_brands:
                        type: integer
                        example: 0
                      total_models:
                        type: integer
                        example: 0
                      total_versions:
                        type: integer
                        example: 2
                      total_results:
                        type: integer
                        example: 2

components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
    TenantAuth:
      type: apiKey
      in: header
      name: X-TENANT-ID
      description: Tenant ID header for multi-tenancy

  schemas:
    UnauthorizedError:
      type: object
      properties:
        error:
          type: string
          example: "UNAUTHORIZED"
        message:
          type: string
          example: "Unauthorized access"
    ValidationError:
      type: object
      properties:
        message:
          type: string
          example: "The given data was invalid."
        errors:
          type: object
          additionalProperties:
            type: array
            items:
              type: string
    Contract:
      type: object
      properties:
        id:
          type: integer
          example: 1
        tenant_id:
          type: integer
          example: 1
        plan_type:
          type: string
          example: "turbo"
        plan_name:
          type: string
          example: "Turbo Plan"
        status:
          type: string
          enum: [active, inactive, cancelled]
          example: "active"
        is_active:
          type: boolean
          example: true
        is_valid:
          type: boolean
          example: true
        is_trial:
          type: boolean
          example: false
        start_date:
          type: string
          format: date
          example: "2025-01-15"
        end_date:
          type: string
          format: date
          example: "2025-02-15"
        billing_cycle:
          type: string
          enum: [monthly, quarterly, annual]
          example: "monthly"
        price_paid:
          type: number
          format: decimal
          example: 299.00
        next_billing_date:
          type: string
          format: date
          example: "2025-02-15"
        days_remaining:
          type: integer
          example: 15
        features:
          type: array
          items:
            type: string
          example: ["basic_analytics", "project_management"]
        limits:
          type: object
          properties:
            projects:
              type: integer
              example: 50
            users:
              type: integer
              example: 25
            storage:
              type: integer
              example: 1000
        add_ons:
          type: array
          items:
            type: string
          description: Additional features
          example: ["priority_support"]
        notes:
          type: string
          description: Contract notes
          example: "Free trial contract created automatically"
    
    Plan:
      type: object
      properties:
        type:
          type: string
          example: "turbo"
        name:
          type: string
          example: "Turbo Plan"
        description:
          type: string
          example: "Advanced plan for growing businesses"
        pricing:
          type: object
          properties:
            monthly:
              type: number
              format: decimal
              example: 299.00
            quarterly:
              type: number
              format: decimal
              example: 849.00
            annual:
              type: number
              format: decimal
              example: 3228.00
        features:
          type: array
          items:
            type: string
          example: ["basic_analytics", "advanced_analytics", "project_management"]
        limits:
          type: object
          properties:
            projects:
              type: integer
              example: 50
            users:
              type: integer
              example: 25
            storage:
              type: integer
              example: 1000
        trial_duration_days:
          type: integer
          example: 30
    
    User:
      type: object
      properties:
        id:
          type: integer
          example: 1
        name:
          type: string
          example: "João Silva"
        email:
          type: string
          format: email
          example: "joao@empresa.com"
        tenant_id:
          type: integer
          example: 1
        created_at:
          type: string
          format: date-time
          example: "2025-01-15T10:30:00.000000Z"
        updated_at:
          type: string
          format: date-time
          example: "2025-01-15T10:30:00.000000Z"
    
    UserWithRoles:
      type: object
      properties:
        id:
          type: integer
          example: 1
        name:
          type: string
          example: "João Silva"
        email:
          type: string
          format: email
          example: "joao@empresa.com"
        is_owner:
          type: boolean
          description: Whether the user is the tenant owner
          example: false
        is_active:
          type: boolean
          description: Whether the user account is active
          example: true
        last_login_at:
          type: string
          format: date-time
          nullable: true
          description: Last login timestamp
          example: "2025-01-15T10:30:00.000000Z"
        tenant_id:
          type: integer
          example: 1
        created_at:
          type: string
          format: date-time
          example: "2025-01-15T10:30:00.000000Z"
        updated_at:
          type: string
          format: date-time
          example: "2025-01-15T10:30:00.000000Z"
        roles:
          type: array
          items:
            type: object
            properties:
              id:
                type: integer
                example: 1
              name:
                type: string
                example: "administrator"
              display_name:
                type: string
                example: "Administrator"
          description: Array of roles assigned to the user
          example:
            - id: 1
              name: "administrator"
              display_name: "Administrator"
    
    Role:
      type: object
      properties:
        id:
          type: integer
          description: Role ID
          example: 1
        name:
          type: string
          description: Role internal name (slug)
          example: "administrator"
        display_name:
          type: string
          description: Human-readable role name
          example: "Administrator"
        description:
          type: string
          nullable: true
          description: Role description
          example: "Full access to all features and settings"
        is_system_role:
          type: boolean
          description: Whether this is a system role (true) or tenant custom role (false)
          example: true
        permissions:
          type: array
          items:
            type: string
          description: List of permission slugs granted by this role
          example: ["manage_users", "manage_settings", "view_analytics", "view_reports"]
        created_at:
          type: string
          format: date-time
          example: "2025-01-15T10:30:00.000000Z"
        updated_at:
          type: string
          format: date-time
          example: "2025-01-15T10:30:00.000000Z"

    Client:
      type: object
      properties:
        client_id:
          type: integer
          example: 42
        tenant_id:
          type: integer
          example: 1
        name:
          type: string
          example: "Jane"
        lastname:
          type: string
          nullable: true
          example: "Doe"
        email:
          type: string
          format: email
          nullable: true
          example: "jane.doe@example.com"
        phone:
          type: string
          nullable: true
          example: "+351912345678"
        address:
          type: string
          nullable: true
          example: "Rua das Flores 10"
        postal_code:
          type: string
          nullable: true
          example: "1000-001"
        local:
          type: string
          nullable: true
          example: "Lisboa"
        country:
          type: string
          nullable: true
          example: "Portugal"
        fiscal_id:
          type: string
          nullable: true
          example: "123456789"
        type:
          type: string
          enum: [individual, business]
          example: "individual"
        created_at:
          type: string
          format: date-time
          example: "2025-11-07T13:55:00.000000Z"
        updated_at:
          type: string
          format: date-time
          example: "2025-11-07T13:55:00.000000Z"

    ClientsFleet:
      type: object
      properties:
        clients_fleet_id:
          type: integer
          example: 7
        tenant_id:
          type: integer
          example: 1
        client_id:
          type: integer
          example: 42
        fleet_id:
          type: integer
          example: 12345
        name:
          type: string
          example: "Fleet Lisbon"
        status:
          type: string
          enum: [active, inactive]
          example: "active"
        created_at:
          type: string
          format: date-time
          example: "2025-11-09T10:00:00.000000Z"
        updated_at:
          type: string
          format: date-time
          example: "2025-11-09T10:00:00.000000Z"

    ChangeHistory:
      type: object
      properties:
        id:
          type: integer
          example: 1
        source:
          type: string
          description: Type of entity (e.g., 'client', 'clients_fleet')
          example: "client"
        source_id:
          type: integer
          description: ID of the entity record
          example: 123
        tenant_id:
          type: integer
          example: 1
        user_id:
          type: integer
          nullable: true
          description: ID of the user who made the change
          example: 5
        date:
          type: string
          format: date-time
          description: Date and time when the change occurred
          example: "2025-11-23T10:00:00.000000Z"
        data:
          type: object
          nullable: true
          description: |
            Full data of the record at the time of change (if storeData=true).
            Null if storeData=false to save space.
          additionalProperties: true
          example:
            client_id: 123
            name: "João Silva"
            email: "joao@example.com"
            tenant_id: 1

    VehicleBrand:
      type: object
      properties:
        brand_id:
          type: integer
          example: 1
        name:
          type: string
          example: "BMW"
        slug:
          type: string
          example: "bmw"
        logo_url:
          type: string
          nullable: true
          example: "https://example.com/logos/bmw.png"
        sort_order:
          type: integer
          example: 1
        is_active:
          type: boolean
          example: true
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    VehicleBrandWithModels:
      allOf:
        - $ref: '#/components/schemas/VehicleBrand'
        - type: object
          properties:
            models:
              type: array
              items:
                $ref: '#/components/schemas/VehicleModel'

    VehicleModel:
      type: object
      properties:
        model_id:
          type: integer
          example: 5
        brand_id:
          type: integer
          example: 1
        name:
          type: string
          example: "Série 3"
        slug:
          type: string
          example: "serie-3"
        start_year:
          type: integer
          nullable: true
          example: 1975
        end_year:
          type: integer
          nullable: true
          example: null
        sort_order:
          type: integer
          example: 0
        is_active:
          type: boolean
          example: true
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    VehicleModelWithVersions:
      allOf:
        - $ref: '#/components/schemas/VehicleModel'
        - type: object
          properties:
            brand:
              $ref: '#/components/schemas/VehicleBrand'
            versions:
              type: array
              items:
                $ref: '#/components/schemas/VehicleVersion'

    VehicleVersion:
      type: object
      properties:
        version_id:
          type: integer
          example: 25
        model_id:
          type: integer
          example: 5
        name:
          type: string
          example: "320d"
        slug:
          type: string
          example: "320d"
        engine_type:
          type: string
          nullable: true
          enum: [diesel, gasoline, hybrid, electric]
          example: "diesel"
        engine_displacement:
          type: number
          format: decimal
          nullable: true
          example: 2.0
        power_hp:
          type: integer
          nullable: true
          example: 184
        start_year:
          type: integer
          nullable: true
          example: 2012
        end_year:
          type: integer
          nullable: true
          example: null
        sort_order:
          type: integer
          example: 0
        is_active:
          type: boolean
          example: true
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    VehicleVersionFull:
      allOf:
        - $ref: '#/components/schemas/VehicleVersion'
        - type: object
          properties:
            model:
              $ref: '#/components/schemas/VehicleModelWithVersions'
            full_name:
              type: string
              example: "BMW Série 3 320d"

    Vehicle:
      type: object
      properties:
        vehicle_id:
          type: integer
          example: 1
        tenant_id:
          type: integer
          example: 1
        client_id:
          type: integer
          example: 42
        fleet_id:
          type: integer
          nullable: true
          example: 12345
        brand_id:
          type: integer
          example: 1
        model_id:
          type: integer
          example: 5
        version_id:
          type: integer
          nullable: true
          example: 25
        type:
          type: string
          enum: [car, motorcycle, van, truck, bus, other]
          example: car
        plate_number:
          type: string
          maxLength: 20
          example: "AB-12-CD"
        vin:
          type: string
          maxLength: 17
          nullable: true
          example: "WBA3A5C58EF123456"
        chassis_number:
          type: string
          nullable: true
          example: "CH123456"
        color:
          type: string
          maxLength: 50
          nullable: true
          example: "Black"
        year:
          type: integer
          nullable: true
          example: 2020
        registration_date:
          type: string
          format: date
          nullable: true
          example: "2020-01-15"
        purchase_date:
          type: string
          format: date
          nullable: true
          example: "2020-01-10"
        purchase_price:
          type: number
          format: decimal
          nullable: true
          example: 35000.00
        custom_version:
          type: string
          nullable: true
          example: "Custom Edition"
        motor:
          type: string
          nullable: true
          example: "2.0 TDI"
        description:
          type: string
          nullable: true
          example: "BMW Série 3 320d"
        notes:
          type: string
          nullable: true
        status:
          type: string
          enum: [active, inactive, sold, scrapped]
          example: active
        created_at:
          type: string
          format: date-time
          example: "2025-11-25T10:00:00.000000Z"
        updated_at:
          type: string
          format: date-time
          example: "2025-11-25T10:00:00.000000Z"

    VehicleWithRelations:
      allOf:
        - $ref: '#/components/schemas/Vehicle'
        - type: object
          properties:
            brand:
              $ref: '#/components/schemas/VehicleBrand'
            model:
              $ref: '#/components/schemas/VehicleModel'
            version:
              $ref: '#/components/schemas/VehicleVersion'
            client:
              $ref: '#/components/schemas/Client'
            fleet:
              $ref: '#/components/schemas/ClientsFleet'
            owners:
              type: array
              items:
                $ref: '#/components/schemas/VehicleOwner'
            current_owner:
              $ref: '#/components/schemas/VehicleOwner'

    VehicleOwner:
      type: object
      properties:
        vehicle_owner_id:
          type: integer
          example: 1
        vehicle_id:
          type: integer
          example: 1
        tenant_id:
          type: integer
          example: 1
        client_id:
          type: integer
          description: Current owner client ID
          example: 42
        previous_client_id:
          type: integer
          nullable: true
          description: Previous owner client ID
          example: null
        ownership_start_date:
          type: string
          format: date
          example: "2020-01-10"
        ownership_end_date:
          type: string
          format: date
          nullable: true
          description: Null when this is the current owner
          example: null
        status:
          type: string
          enum: [active, inactive]
          example: active
        transfer_reason:
          type: string
          nullable: true
          example: "Venda"
        transfer_notes:
          type: string
          nullable: true
          example: "Vendido a cliente externo"
        created_at:
          type: string
          format: date-time
          example: "2025-11-25T10:00:00.000000Z"
        updated_at:
          type: string
          format: date-time
          example: "2025-11-25T10:00:00.000000Z"

tags:
  - name: Authentication
    description: User authentication and token management
  - name: OAuth2
    description: OAuth2 standard endpoints
  - name: System
    description: API health and status endpoints
  - name: Plans
    description: Subscription plans information and comparison
  - name: Subscription Management
    description: Tenant subscription status and management
  - name: Contract Management
    description: Contract and plan management operations
  - name: User Management
    description: User profile and password management
  - name: Clients
    description: Client management operations
  - name: Fleets
    description: Manage client fleet assignments within a tenant
  - name: Change History
    description: Audit trail and change history tracking
  - name: Vehicle Catalog
    description: Vehicle catalog (brands, models, versions) - public read-only endpoints
  - name: Vehicles
    description: Vehicle management operations with ownership history tracking
