openapi: 3.0.3
info:
  title: Goa GEL - Blockchain Document Verification Platform API
  description: |
    ## Overview
    REST API for the Government of Goa's Blockchain-based Document Verification Platform (GEL).
    This platform enables multi-department approval workflows for various licenses and permits,
    with blockchain-backed verification using Hyperledger Besu and ERC-721 Soulbound NFTs.

    ## Authentication
    - **Department APIs**: Use `X-API-Key` and `X-Department-Code` headers
    - **Applicant APIs**: Use Bearer token from DigiLocker authentication (mock for POC)
    - **Admin APIs**: Use Bearer token with admin role

    ## Blockchain Integration
    All critical operations (request creation, approvals, document updates) are recorded on-chain.
    Response includes `transactionHash` for blockchain verification.

    ## Webhooks
    Departments can register webhooks to receive real-time notifications for:
    - `APPROVAL_REQUIRED` - New request pending approval
    - `DOCUMENT_UPDATED` - Applicant updated a document
    - `REQUEST_APPROVED` - Request fully approved
    - `REQUEST_REJECTED` - Request rejected

  version: 1.0.0
  contact:
    name: Goa GEL Platform Support
    email: support@goagel.gov.in
  license:
    name: Government of Goa
    url: https://www.goa.gov.in

servers:
  - url: https://api.goagel.gov.in/api/v1
    description: Production server
  - url: https://staging-api.goagel.gov.in/api/v1
    description: Staging server
  - url: http://localhost:3001/api/v1
    description: Local development

tags:
  - name: Requests
    description: License request operations
  - name: Documents
    description: Document upload and retrieval
  - name: Approvals
    description: Department approval actions
  - name: Departments
    description: Department management
  - name: Workflows
    description: Workflow configuration
  - name: Webhooks
    description: Webhook management
  - name: Admin
    description: Platform administration
  - name: Verification
    description: Public verification endpoints

paths:
  # ==================== REQUESTS ====================
  /requests:
    post:
      tags:
        - Requests
      summary: Create new license request
      description: |
        Creates a new license request and mints a draft NFT on the blockchain.
        The request starts in DRAFT status until submitted.
      operationId: createRequest
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateRequestInput'
            example:
              applicantId: "DL-GOA-123456789"
              requestType: "RESORT_LICENSE"
              metadata:
                resortName: "Paradise Beach Resort"
                location: "Calangute, North Goa"
                plotArea: 5000
                builtUpArea: 3500
                numberOfRooms: 50
      responses:
        '201':
          description: Request created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RequestResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'

    get:
      tags:
        - Requests
      summary: List requests
      description: Get list of requests with optional filters
      operationId: listRequests
      security:
        - BearerAuth: []
        - ApiKeyAuth: []
      parameters:
        - name: status
          in: query
          schema:
            $ref: '#/components/schemas/RequestStatus'
        - name: requestType
          in: query
          schema:
            type: string
            example: "RESORT_LICENSE"
        - name: applicantId
          in: query
          schema:
            type: string
        - name: page
          in: query
          schema:
            type: integer
            default: 1
            minimum: 1
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
            minimum: 1
            maximum: 100
        - name: sortBy
          in: query
          schema:
            type: string
            enum: [createdAt, updatedAt, status]
            default: createdAt
        - name: sortOrder
          in: query
          schema:
            type: string
            enum: [asc, desc]
            default: desc
      responses:
        '200':
          description: List of requests
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RequestListResponse'

  /requests/pending:
    get:
      tags:
        - Requests
      summary: Get requests pending for department
      description: Returns all requests that are pending approval from the specified department
      operationId: getPendingRequests
      security:
        - ApiKeyAuth: []
      parameters:
        - name: department
          in: query
          required: true
          schema:
            type: string
          example: "FIRE_DEPT"
        - name: page
          in: query
          schema:
            type: integer
            default: 1
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
      responses:
        '200':
          description: List of pending requests
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RequestListResponse'

  /requests/{requestId}:
    get:
      tags:
        - Requests
      summary: Get request details
      description: |
        Returns complete request details including documents, approvals,
        current workflow stage, and full timeline of events.
      operationId: getRequest
      security:
        - BearerAuth: []
        - ApiKeyAuth: []
      parameters:
        - $ref: '#/components/parameters/RequestId'
      responses:
        '200':
          description: Request details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RequestDetailResponse'
        '404':
          $ref: '#/components/responses/NotFound'

  /requests/{requestId}/submit:
    post:
      tags:
        - Requests
      summary: Submit request for approval
      description: |
        Submits the request for departmental approval workflow.
        Validates that all required documents are uploaded before submission.
        Records submission on blockchain and notifies relevant departments.
      operationId: submitRequest
      security:
        - BearerAuth: []
      parameters:
        - $ref: '#/components/parameters/RequestId'
      responses:
        '200':
          description: Request submitted successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  requestId:
                    type: string
                    format: uuid
                  status:
                    type: string
                    example: "SUBMITTED"
                  currentStage:
                    $ref: '#/components/schemas/WorkflowStage'
                  pendingDepartments:
                    type: array
                    items:
                      type: string
                    example: ["FIRE_DEPT", "TOURISM_DEPT"]
                  transactionHash:
                    type: string
                    example: "0x1234567890abcdef..."
        '400':
          description: Missing required documents
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                code: "MISSING_DOCUMENTS"
                message: "Required documents not uploaded"
                details:
                  missingDocuments: ["FIRE_SAFETY_CERTIFICATE", "BUILDING_PLAN"]

  /requests/{requestId}/cancel:
    post:
      tags:
        - Requests
      summary: Cancel request
      description: Cancels a request that is in DRAFT or PENDING_RESUBMISSION status
      operationId: cancelRequest
      security:
        - BearerAuth: []
      parameters:
        - $ref: '#/components/parameters/RequestId'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                reason:
                  type: string
                  example: "No longer needed"
      responses:
        '200':
          description: Request cancelled
          content:
            application/json:
              schema:
                type: object
                properties:
                  requestId:
                    type: string
                  status:
                    type: string
                    example: "CANCELLED"
                  transactionHash:
                    type: string

  /requests/{requestId}/timeline:
    get:
      tags:
        - Requests
      summary: Get request timeline
      description: Returns chronological list of all events for this request
      operationId: getRequestTimeline
      security:
        - BearerAuth: []
        - ApiKeyAuth: []
      parameters:
        - $ref: '#/components/parameters/RequestId'
      responses:
        '200':
          description: Request timeline
          content:
            application/json:
              schema:
                type: object
                properties:
                  requestId:
                    type: string
                  events:
                    type: array
                    items:
                      $ref: '#/components/schemas/TimelineEvent'

  # ==================== DOCUMENTS ====================
  /requests/{requestId}/documents:
    post:
      tags:
        - Documents
      summary: Upload document
      description: |
        Uploads a document for the request. The document is:
        1. Stored in MinIO with versioning
        2. Hash generated using SHA-256
        3. Hash recorded on blockchain
        4. Linked to the request NFT
      operationId: uploadDocument
      security:
        - BearerAuth: []
      parameters:
        - $ref: '#/components/parameters/RequestId'
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required:
                - file
                - docType
              properties:
                file:
                  type: string
                  format: binary
                  description: Document file (PDF, JPG, PNG)
                docType:
                  type: string
                  description: Document type code
                  example: "FIRE_SAFETY_CERTIFICATE"
                description:
                  type: string
                  description: Optional description
                  example: "Fire safety certificate from Fire Department"
      responses:
        '201':
          description: Document uploaded successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DocumentResponse'
        '400':
          description: Invalid file or document type
        '413':
          description: File too large (max 10MB)

    get:
      tags:
        - Documents
      summary: List request documents
      description: Returns all documents associated with the request
      operationId: listRequestDocuments
      security:
        - BearerAuth: []
        - ApiKeyAuth: []
      parameters:
        - $ref: '#/components/parameters/RequestId'
      responses:
        '200':
          description: List of documents
          content:
            application/json:
              schema:
                type: object
                properties:
                  requestId:
                    type: string
                  documents:
                    type: array
                    items:
                      $ref: '#/components/schemas/Document'

  /documents/{documentId}:
    get:
      tags:
        - Documents
      summary: Get document details
      description: Returns document metadata and all versions
      operationId: getDocument
      security:
        - BearerAuth: []
        - ApiKeyAuth: []
      parameters:
        - name: documentId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Document details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DocumentDetailResponse'

  /documents/{documentId}/download:
    get:
      tags:
        - Documents
      summary: Download document
      description: Returns a signed URL for downloading the document
      operationId: downloadDocument
      security:
        - BearerAuth: []
        - ApiKeyAuth: []
      parameters:
        - name: documentId
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: version
          in: query
          description: Specific version to download (defaults to latest)
          schema:
            type: integer
      responses:
        '200':
          description: Download URL
          content:
            application/json:
              schema:
                type: object
                properties:
                  downloadUrl:
                    type: string
                    format: uri
                    description: Signed URL (expires in 1 hour)
                  expiresAt:
                    type: string
                    format: date-time

  /requests/{requestId}/documents/{documentId}:
    put:
      tags:
        - Documents
      summary: Update document (new version)
      description: |
        Uploads a new version of an existing document.
        This will:
        1. Create new version in MinIO
        2. Generate new hash
        3. Record new hash on blockchain
        4. Mark affected approvals as "REVIEW_REQUIRED"
        5. Notify affected departments via webhook
      operationId: updateDocument
      security:
        - BearerAuth: []
      parameters:
        - $ref: '#/components/parameters/RequestId'
        - name: documentId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required:
                - file
              properties:
                file:
                  type: string
                  format: binary
                description:
                  type: string
      responses:
        '200':
          description: Document updated
          content:
            application/json:
              schema:
                type: object
                properties:
                  documentId:
                    type: string
                  newVersion:
                    type: integer
                  newHash:
                    type: string
                  invalidatedApprovals:
                    type: array
                    items:
                      type: string
                    description: Department codes that need re-review
                  transactionHash:
                    type: string

  # ==================== APPROVALS ====================
  /requests/{requestId}/approve:
    post:
      tags:
        - Approvals
      summary: Approve request
      description: |
        Records department approval on the blockchain.
        If all required approvals for the current stage are complete,
        automatically advances to the next stage or finalizes the request.
      operationId: approveRequest
      security:
        - ApiKeyAuth: []
      parameters:
        - $ref: '#/components/parameters/RequestId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - remarks
                - reviewedDocuments
              properties:
                remarks:
                  type: string
                  example: "All fire safety requirements met"
                reviewedDocuments:
                  type: array
                  items:
                    type: string
                    format: uuid
                  description: Document IDs that were reviewed
      responses:
        '200':
          description: Approval recorded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApprovalResponse'

  /requests/{requestId}/reject:
    post:
      tags:
        - Approvals
      summary: Reject request
      description: Records department rejection. This permanently rejects the request.
      operationId: rejectRequest
      security:
        - ApiKeyAuth: []
      parameters:
        - $ref: '#/components/parameters/RequestId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - remarks
                - reason
              properties:
                remarks:
                  type: string
                  example: "Fire safety standards not met"
                reason:
                  type: string
                  enum:
                    - SAFETY_VIOLATION
                    - INCOMPLETE_DOCUMENTS
                    - POLICY_VIOLATION
                    - FRAUDULENT_APPLICATION
                    - OTHER
      responses:
        '200':
          description: Rejection recorded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApprovalResponse'

  /requests/{requestId}/request-changes:
    post:
      tags:
        - Approvals
      summary: Request changes
      description: |
        Requests additional information or document updates from the applicant.
        The request status changes to PENDING_RESUBMISSION.
      operationId: requestChanges
      security:
        - ApiKeyAuth: []
      parameters:
        - $ref: '#/components/parameters/RequestId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - remarks
              properties:
                remarks:
                  type: string
                  example: "Please provide updated fire safety certificate with recent inspection"
                requiredDocuments:
                  type: array
                  items:
                    type: string
                  description: Additional document types needed
                  example: ["FIRE_SAFETY_CERTIFICATE", "INSPECTION_REPORT"]
      responses:
        '200':
          description: Changes requested
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: "CHANGES_REQUESTED"
                  transactionHash:
                    type: string

  /requests/{requestId}/approvals:
    get:
      tags:
        - Approvals
      summary: Get all approvals for request
      description: Returns all approval records including historical/invalidated ones
      operationId: getRequestApprovals
      security:
        - BearerAuth: []
        - ApiKeyAuth: []
      parameters:
        - $ref: '#/components/parameters/RequestId'
        - name: includeInvalidated
          in: query
          schema:
            type: boolean
            default: false
      responses:
        '200':
          description: List of approvals
          content:
            application/json:
              schema:
                type: object
                properties:
                  requestId:
                    type: string
                  approvals:
                    type: array
                    items:
                      $ref: '#/components/schemas/Approval'

  # ==================== DEPARTMENTS ====================
  /departments:
    get:
      tags:
        - Departments
      summary: List all departments
      description: Returns all registered departments
      operationId: listDepartments
      security:
        - BearerAuth: []
        - ApiKeyAuth: []
      responses:
        '200':
          description: List of departments
          content:
            application/json:
              schema:
                type: object
                properties:
                  departments:
                    type: array
                    items:
                      $ref: '#/components/schemas/Department'

    post:
      tags:
        - Departments
      summary: Register new department
      description: Registers a new department and creates blockchain wallet
      operationId: createDepartment
      security:
        - AdminAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateDepartmentInput'
      responses:
        '201':
          description: Department created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DepartmentResponse'

  /departments/{departmentCode}:
    get:
      tags:
        - Departments
      summary: Get department details
      operationId: getDepartment
      security:
        - BearerAuth: []
        - ApiKeyAuth: []
      parameters:
        - name: departmentCode
          in: path
          required: true
          schema:
            type: string
          example: "FIRE_DEPT"
      responses:
        '200':
          description: Department details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Department'

    patch:
      tags:
        - Departments
      summary: Update department
      operationId: updateDepartment
      security:
        - AdminAuth: []
      parameters:
        - name: departmentCode
          in: path
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                webhookUrl:
                  type: string
                  format: uri
                isActive:
                  type: boolean
      responses:
        '200':
          description: Department updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Department'

  /departments/{departmentCode}/regenerate-api-key:
    post:
      tags:
        - Departments
      summary: Regenerate API key
      description: Generates a new API key for the department (invalidates the old key)
      operationId: regenerateApiKey
      security:
        - AdminAuth: []
      parameters:
        - name: departmentCode
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: New API key generated
          content:
            application/json:
              schema:
                type: object
                properties:
                  apiKey:
                    type: string
                    description: New API key (shown only once)
                  apiSecret:
                    type: string
                    description: New API secret (shown only once)

  /departments/{departmentCode}/stats:
    get:
      tags:
        - Departments
      summary: Get department statistics
      operationId: getDepartmentStats
      security:
        - ApiKeyAuth: []
        - AdminAuth: []
      parameters:
        - name: departmentCode
          in: path
          required: true
          schema:
            type: string
        - name: startDate
          in: query
          schema:
            type: string
            format: date
        - name: endDate
          in: query
          schema:
            type: string
            format: date
      responses:
        '200':
          description: Department statistics
          content:
            application/json:
              schema:
                type: object
                properties:
                  departmentCode:
                    type: string
                  period:
                    type: object
                    properties:
                      start:
                        type: string
                        format: date
                      end:
                        type: string
                        format: date
                  stats:
                    type: object
                    properties:
                      totalReceived:
                        type: integer
                      approved:
                        type: integer
                      rejected:
                        type: integer
                      pending:
                        type: integer
                      avgProcessingTimeDays:
                        type: number

  # ==================== WORKFLOWS ====================
  /workflows:
    get:
      tags:
        - Workflows
      summary: List workflow definitions
      operationId: listWorkflows
      security:
        - AdminAuth: []
      parameters:
        - name: isActive
          in: query
          schema:
            type: boolean
      responses:
        '200':
          description: List of workflows
          content:
            application/json:
              schema:
                type: object
                properties:
                  workflows:
                    type: array
                    items:
                      $ref: '#/components/schemas/Workflow'

    post:
      tags:
        - Workflows
      summary: Create workflow definition
      operationId: createWorkflow
      security:
        - AdminAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateWorkflowInput'
      responses:
        '201':
          description: Workflow created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Workflow'

  /workflows/{workflowId}:
    get:
      tags:
        - Workflows
      summary: Get workflow details
      operationId: getWorkflow
      security:
        - AdminAuth: []
      parameters:
        - name: workflowId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Workflow details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Workflow'

    put:
      tags:
        - Workflows
      summary: Update workflow
      description: |
        Updates a workflow definition. Creates a new version.
        In-progress requests continue with their original workflow version.
      operationId: updateWorkflow
      security:
        - AdminAuth: []
      parameters:
        - name: workflowId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateWorkflowInput'
      responses:
        '200':
          description: Workflow updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Workflow'

    delete:
      tags:
        - Workflows
      summary: Deactivate workflow
      description: Deactivates the workflow. Cannot be used for new requests.
      operationId: deactivateWorkflow
      security:
        - AdminAuth: []
      parameters:
        - name: workflowId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Workflow deactivated

  /workflows/{workflowId}/validate:
    post:
      tags:
        - Workflows
      summary: Validate workflow definition
      description: Validates workflow for circular dependencies, missing departments, etc.
      operationId: validateWorkflow
      security:
        - AdminAuth: []
      parameters:
        - name: workflowId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Validation result
          content:
            application/json:
              schema:
                type: object
                properties:
                  isValid:
                    type: boolean
                  errors:
                    type: array
                    items:
                      type: object
                      properties:
                        code:
                          type: string
                        message:
                          type: string
                        path:
                          type: string

  # ==================== WEBHOOKS ====================
  /webhooks:
    get:
      tags:
        - Webhooks
      summary: List registered webhooks
      operationId: listWebhooks
      security:
        - ApiKeyAuth: []
        - AdminAuth: []
      responses:
        '200':
          description: List of webhooks
          content:
            application/json:
              schema:
                type: object
                properties:
                  webhooks:
                    type: array
                    items:
                      $ref: '#/components/schemas/Webhook'

    post:
      tags:
        - Webhooks
      summary: Register webhook
      operationId: createWebhook
      security:
        - ApiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateWebhookInput'
      responses:
        '201':
          description: Webhook registered
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Webhook'

  /webhooks/{webhookId}:
    delete:
      tags:
        - Webhooks
      summary: Delete webhook
      operationId: deleteWebhook
      security:
        - ApiKeyAuth: []
      parameters:
        - name: webhookId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '204':
          description: Webhook deleted

  /webhooks/{webhookId}/test:
    post:
      tags:
        - Webhooks
      summary: Test webhook
      description: Sends a test payload to the webhook URL
      operationId: testWebhook
      security:
        - ApiKeyAuth: []
      parameters:
        - name: webhookId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Test result
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  statusCode:
                    type: integer
                  responseTime:
                    type: integer
                    description: Response time in ms

  /webhooks/logs:
    get:
      tags:
        - Webhooks
      summary: Get webhook delivery logs
      operationId: getWebhookLogs
      security:
        - ApiKeyAuth: []
        - AdminAuth: []
      parameters:
        - name: webhookId
          in: query
          schema:
            type: string
            format: uuid
        - name: status
          in: query
          schema:
            type: string
            enum: [success, failed, pending]
        - name: page
          in: query
          schema:
            type: integer
            default: 1
        - name: limit
          in: query
          schema:
            type: integer
            default: 50
      responses:
        '200':
          description: Webhook logs
          content:
            application/json:
              schema:
                type: object
                properties:
                  logs:
                    type: array
                    items:
                      $ref: '#/components/schemas/WebhookLog'

  # ==================== ADMIN ====================
  /admin/stats:
    get:
      tags:
        - Admin
      summary: Get platform statistics
      operationId: getPlatformStats
      security:
        - AdminAuth: []
      parameters:
        - name: startDate
          in: query
          schema:
            type: string
            format: date
        - name: endDate
          in: query
          schema:
            type: string
            format: date
      responses:
        '200':
          description: Platform statistics
          content:
            application/json:
              schema:
                type: object
                properties:
                  period:
                    type: object
                    properties:
                      start:
                        type: string
                        format: date
                      end:
                        type: string
                        format: date
                  requests:
                    type: object
                    properties:
                      total:
                        type: integer
                      byStatus:
                        type: object
                        additionalProperties:
                          type: integer
                      byType:
                        type: object
                        additionalProperties:
                          type: integer
                  blockchain:
                    type: object
                    properties:
                      totalTransactions:
                        type: integer
                      nftsMinted:
                        type: integer
                      avgGasUsed:
                        type: number
                  performance:
                    type: object
                    properties:
                      avgProcessingTimeDays:
                        type: number
                      requestsPerDay:
                        type: number

  /admin/audit-logs:
    get:
      tags:
        - Admin
      summary: Get audit logs
      operationId: getAuditLogs
      security:
        - AdminAuth: []
      parameters:
        - name: entityType
          in: query
          schema:
            type: string
            enum: [REQUEST, APPROVAL, DOCUMENT, DEPARTMENT, WORKFLOW]
        - name: entityId
          in: query
          schema:
            type: string
            format: uuid
        - name: action
          in: query
          schema:
            type: string
        - name: actorId
          in: query
          schema:
            type: string
            format: uuid
        - name: startDate
          in: query
          schema:
            type: string
            format: date-time
        - name: endDate
          in: query
          schema:
            type: string
            format: date-time
        - name: page
          in: query
          schema:
            type: integer
            default: 1
        - name: limit
          in: query
          schema:
            type: integer
            default: 50
      responses:
        '200':
          description: Audit logs
          content:
            application/json:
              schema:
                type: object
                properties:
                  logs:
                    type: array
                    items:
                      $ref: '#/components/schemas/AuditLog'
                  pagination:
                    $ref: '#/components/schemas/Pagination'

  /admin/blockchain/status:
    get:
      tags:
        - Admin
      summary: Get blockchain network status
      operationId: getBlockchainStatus
      security:
        - AdminAuth: []
      responses:
        '200':
          description: Blockchain status
          content:
            application/json:
              schema:
                type: object
                properties:
                  network:
                    type: object
                    properties:
                      chainId:
                        type: integer
                      networkId:
                        type: integer
                      consensus:
                        type: string
                        example: "QBFT"
                  nodes:
                    type: array
                    items:
                      type: object
                      properties:
                        nodeId:
                          type: string
                        isValidator:
                          type: boolean
                        isHealthy:
                          type: boolean
                        peers:
                          type: integer
                        latestBlock:
                          type: integer
                  latestBlock:
                    type: object
                    properties:
                      number:
                        type: integer
                      hash:
                        type: string
                      timestamp:
                        type: string
                        format: date-time

  /admin/blockchain/transactions:
    get:
      tags:
        - Admin
      summary: Get blockchain transactions
      operationId: getBlockchainTransactions
      security:
        - AdminAuth: []
      parameters:
        - name: txType
          in: query
          schema:
            type: string
            enum: [MINT_NFT, APPROVAL, DOC_UPDATE, REJECT, REVOKE]
        - name: status
          in: query
          schema:
            type: string
            enum: [PENDING, CONFIRMED, FAILED]
        - name: page
          in: query
          schema:
            type: integer
            default: 1
        - name: limit
          in: query
          schema:
            type: integer
            default: 50
      responses:
        '200':
          description: Blockchain transactions
          content:
            application/json:
              schema:
                type: object
                properties:
                  transactions:
                    type: array
                    items:
                      $ref: '#/components/schemas/BlockchainTransaction'
                  pagination:
                    $ref: '#/components/schemas/Pagination'

  # ==================== VERIFICATION ====================
  /verify/{tokenId}:
    get:
      tags:
        - Verification
      summary: Verify license by token ID
      description: |
        Public endpoint for verifying a license using its NFT token ID.
        No authentication required.
      operationId: verifyByTokenId
      parameters:
        - name: tokenId
          in: path
          required: true
          schema:
            type: integer
          example: 12345
      responses:
        '200':
          description: Verification result
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VerificationResponse'
        '404':
          description: Token not found

  /verify/qr/{qrCode}:
    get:
      tags:
        - Verification
      summary: Verify license by QR code
      description: Public endpoint for verifying a license using QR code data
      operationId: verifyByQrCode
      parameters:
        - name: qrCode
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Verification result
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VerificationResponse'

  /verify/document/{hash}:
    get:
      tags:
        - Verification
      summary: Verify document by hash
      description: Public endpoint for verifying a document using its hash
      operationId: verifyDocumentByHash
      parameters:
        - name: hash
          in: path
          required: true
          schema:
            type: string
          example: "0x1234567890abcdef..."
      responses:
        '200':
          description: Document verification result
          content:
            application/json:
              schema:
                type: object
                properties:
                  isValid:
                    type: boolean
                  documentId:
                    type: string
                  requestId:
                    type: string
                  docType:
                    type: string
                  version:
                    type: integer
                  uploadedAt:
                    type: string
                    format: date-time
                  blockchainRecord:
                    type: object
                    properties:
                      transactionHash:
                        type: string
                      blockNumber:
                        type: integer
                      timestamp:
                        type: string
                        format: date-time

# ==================== COMPONENTS ====================
components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: JWT token from DigiLocker authentication

    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: |
        Department API key. Must be used with X-Department-Code header.

    AdminAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: Admin JWT token

  parameters:
    RequestId:
      name: requestId
      in: path
      required: true
      schema:
        type: string
        format: uuid
      description: Unique request identifier

  responses:
    BadRequest:
      description: Bad request
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'

    Unauthorized:
      description: Unauthorized
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: "UNAUTHORIZED"
            message: "Invalid or missing authentication"

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

  schemas:
    # ===== Input Schemas =====
    CreateRequestInput:
      type: object
      required:
        - applicantId
        - requestType
      properties:
        applicantId:
          type: string
          description: DigiLocker ID
          example: "DL-GOA-123456789"
        requestType:
          type: string
          description: Type of license/permit
          enum:
            - RESORT_LICENSE
            - TRADE_LICENSE
            - BUILDING_PERMIT
          example: "RESORT_LICENSE"
        metadata:
          type: object
          description: Request-specific data
          additionalProperties: true

    CreateDepartmentInput:
      type: object
      required:
        - code
        - name
      properties:
        code:
          type: string
          pattern: "^[A-Z_]+$"
          example: "FIRE_DEPT"
        name:
          type: string
          example: "Fire & Emergency Services Department"
        webhookUrl:
          type: string
          format: uri

    CreateWorkflowInput:
      type: object
      required:
        - workflowType
        - name
        - stages
      properties:
        workflowType:
          type: string
          example: "RESORT_LICENSE"
        name:
          type: string
          example: "Resort License Approval Workflow"
        description:
          type: string
        stages:
          type: array
          items:
            $ref: '#/components/schemas/WorkflowStageInput'

    WorkflowStageInput:
      type: object
      required:
        - stageId
        - stageName
        - stageOrder
        - executionType
        - requiredApprovals
      properties:
        stageId:
          type: string
        stageName:
          type: string
        stageOrder:
          type: integer
        executionType:
          type: string
          enum: [SEQUENTIAL, PARALLEL]
        requiredApprovals:
          type: array
          items:
            type: object
            properties:
              departmentCode:
                type: string
              requiredDocuments:
                type: array
                items:
                  type: string
              isMandatory:
                type: boolean
        completionCriteria:
          type: string
          enum: [ALL, ANY, THRESHOLD]
          default: ALL
        threshold:
          type: integer
        timeoutDays:
          type: integer
        onTimeout:
          type: string
          enum: [NOTIFY, ESCALATE, AUTO_REJECT]
        onRejection:
          type: string
          enum: [FAIL_REQUEST, RETRY_STAGE, ESCALATE]

    CreateWebhookInput:
      type: object
      required:
        - url
        - events
        - secret
      properties:
        departmentCode:
          type: string
        url:
          type: string
          format: uri
        events:
          type: array
          items:
            type: string
            enum:
              - APPROVAL_REQUIRED
              - DOCUMENT_UPDATED
              - REQUEST_APPROVED
              - REQUEST_REJECTED
              - CHANGES_REQUESTED
        secret:
          type: string
          description: Secret for HMAC signature verification

    # ===== Response Schemas =====
    RequestResponse:
      type: object
      properties:
        requestId:
          type: string
          format: uuid
        requestNumber:
          type: string
          example: "RL-2024-001234"
        status:
          $ref: '#/components/schemas/RequestStatus'
        transactionHash:
          type: string
        createdAt:
          type: string
          format: date-time

    RequestListResponse:
      type: object
      properties:
        requests:
          type: array
          items:
            $ref: '#/components/schemas/RequestSummary'
        pagination:
          $ref: '#/components/schemas/Pagination'

    RequestSummary:
      type: object
      properties:
        requestId:
          type: string
          format: uuid
        requestNumber:
          type: string
        requestType:
          type: string
        status:
          $ref: '#/components/schemas/RequestStatus'
        applicantName:
          type: string
        currentStage:
          type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time

    RequestDetailResponse:
      type: object
      properties:
        requestId:
          type: string
          format: uuid
        requestNumber:
          type: string
        tokenId:
          type: integer
        requestType:
          type: string
        status:
          $ref: '#/components/schemas/RequestStatus'
        applicant:
          type: object
          properties:
            id:
              type: string
            name:
              type: string
            email:
              type: string
        metadata:
          type: object
        documents:
          type: array
          items:
            $ref: '#/components/schemas/Document'
        approvals:
          type: array
          items:
            $ref: '#/components/schemas/Approval'
        currentStage:
          $ref: '#/components/schemas/WorkflowStage'
        timeline:
          type: array
          items:
            $ref: '#/components/schemas/TimelineEvent'
        blockchainData:
          type: object
          properties:
            tokenId:
              type: integer
            contractAddress:
              type: string
            creationTxHash:
              type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        submittedAt:
          type: string
          format: date-time
        approvedAt:
          type: string
          format: date-time

    DocumentResponse:
      type: object
      properties:
        documentId:
          type: string
          format: uuid
        docType:
          type: string
        hash:
          type: string
        version:
          type: integer
        transactionHash:
          type: string
        createdAt:
          type: string
          format: date-time

    DocumentDetailResponse:
      type: object
      properties:
        documentId:
          type: string
          format: uuid
        docType:
          type: string
        originalFilename:
          type: string
        currentVersion:
          type: integer
        currentHash:
          type: string
        versions:
          type: array
          items:
            $ref: '#/components/schemas/DocumentVersion'
        downloadUrl:
          type: string
          format: uri

    ApprovalResponse:
      type: object
      properties:
        approvalId:
          type: string
          format: uuid
        status:
          $ref: '#/components/schemas/ApprovalStatus'
        transactionHash:
          type: string
        workflowStatus:
          type: object
          properties:
            currentStage:
              type: string
            isComplete:
              type: boolean
            nextPendingDepartments:
              type: array
              items:
                type: string

    DepartmentResponse:
      type: object
      properties:
        code:
          type: string
        name:
          type: string
        walletAddress:
          type: string
        apiKey:
          type: string
          description: Shown only on creation
        apiSecret:
          type: string
          description: Shown only on creation
        isActive:
          type: boolean
        createdAt:
          type: string
          format: date-time

    VerificationResponse:
      type: object
      properties:
        isValid:
          type: boolean
        tokenId:
          type: integer
        requestNumber:
          type: string
        requestType:
          type: string
        status:
          $ref: '#/components/schemas/RequestStatus'
        applicantName:
          type: string
        issuedAt:
          type: string
          format: date-time
        expiresAt:
          type: string
          format: date-time
        approvals:
          type: array
          items:
            type: object
            properties:
              departmentName:
                type: string
              approvedAt:
                type: string
                format: date-time
        blockchainProof:
          type: object
          properties:
            contractAddress:
              type: string
            tokenId:
              type: integer
            ownerAddress:
              type: string
            transactionHash:
              type: string

    # ===== Entity Schemas =====
    Document:
      type: object
      properties:
        documentId:
          type: string
          format: uuid
        docType:
          type: string
        originalFilename:
          type: string
        currentVersion:
          type: integer
        currentHash:
          type: string
        uploadedAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time

    DocumentVersion:
      type: object
      properties:
        version:
          type: integer
        hash:
          type: string
        fileSize:
          type: integer
        mimeType:
          type: string
        uploadedBy:
          type: string
        transactionHash:
          type: string
        createdAt:
          type: string
          format: date-time

    Approval:
      type: object
      properties:
        approvalId:
          type: string
          format: uuid
        departmentCode:
          type: string
        departmentName:
          type: string
        status:
          $ref: '#/components/schemas/ApprovalStatus'
        remarks:
          type: string
        reviewedDocuments:
          type: array
          items:
            type: string
        isActive:
          type: boolean
        transactionHash:
          type: string
        createdAt:
          type: string
          format: date-time
        invalidatedAt:
          type: string
          format: date-time
        invalidationReason:
          type: string

    Department:
      type: object
      properties:
        code:
          type: string
        name:
          type: string
        walletAddress:
          type: string
        webhookUrl:
          type: string
        isActive:
          type: boolean
        createdAt:
          type: string
          format: date-time

    Workflow:
      type: object
      properties:
        workflowId:
          type: string
          format: uuid
        workflowType:
          type: string
        name:
          type: string
        description:
          type: string
        version:
          type: integer
        isActive:
          type: boolean
        stages:
          type: array
          items:
            $ref: '#/components/schemas/WorkflowStage'
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time

    WorkflowStage:
      type: object
      properties:
        stageId:
          type: string
        stageName:
          type: string
        stageOrder:
          type: integer
        executionType:
          type: string
          enum: [SEQUENTIAL, PARALLEL]
        requiredApprovals:
          type: array
          items:
            type: object
            properties:
              departmentCode:
                type: string
              departmentName:
                type: string
              requiredDocuments:
                type: array
                items:
                  type: string
              isMandatory:
                type: boolean
        completionCriteria:
          type: string
          enum: [ALL, ANY, THRESHOLD]
        threshold:
          type: integer
        timeoutDays:
          type: integer
        onTimeout:
          type: string
        onRejection:
          type: string

    Webhook:
      type: object
      properties:
        webhookId:
          type: string
          format: uuid
        departmentCode:
          type: string
        url:
          type: string
          format: uri
        events:
          type: array
          items:
            type: string
        isActive:
          type: boolean
        createdAt:
          type: string
          format: date-time

    WebhookLog:
      type: object
      properties:
        logId:
          type: string
          format: uuid
        webhookId:
          type: string
          format: uuid
        eventType:
          type: string
        payload:
          type: object
        responseStatus:
          type: integer
        responseTime:
          type: integer
        retryCount:
          type: integer
        createdAt:
          type: string
          format: date-time

    TimelineEvent:
      type: object
      properties:
        eventId:
          type: string
          format: uuid
        eventType:
          type: string
          enum:
            - REQUEST_CREATED
            - REQUEST_SUBMITTED
            - DOCUMENT_UPLOADED
            - DOCUMENT_UPDATED
            - APPROVAL_RECEIVED
            - REJECTION_RECEIVED
            - CHANGES_REQUESTED
            - REQUEST_APPROVED
            - REQUEST_REJECTED
            - NFT_MINTED
        description:
          type: string
        actor:
          type: object
          properties:
            type:
              type: string
              enum: [APPLICANT, DEPARTMENT, SYSTEM]
            id:
              type: string
            name:
              type: string
        metadata:
          type: object
        transactionHash:
          type: string
        timestamp:
          type: string
          format: date-time

    AuditLog:
      type: object
      properties:
        logId:
          type: string
          format: uuid
        entityType:
          type: string
        entityId:
          type: string
          format: uuid
        action:
          type: string
        actorType:
          type: string
        actorId:
          type: string
          format: uuid
        oldValue:
          type: object
        newValue:
          type: object
        ipAddress:
          type: string
        userAgent:
          type: string
        createdAt:
          type: string
          format: date-time

    BlockchainTransaction:
      type: object
      properties:
        txId:
          type: string
          format: uuid
        txHash:
          type: string
        txType:
          type: string
          enum: [MINT_NFT, APPROVAL, DOC_UPDATE, REJECT, REVOKE]
        relatedEntityType:
          type: string
        relatedEntityId:
          type: string
          format: uuid
        fromAddress:
          type: string
        toAddress:
          type: string
        status:
          type: string
          enum: [PENDING, CONFIRMED, FAILED]
        blockNumber:
          type: integer
        gasUsed:
          type: integer
        errorMessage:
          type: string
        createdAt:
          type: string
          format: date-time
        confirmedAt:
          type: string
          format: date-time

    # ===== Enums =====
    RequestStatus:
      type: string
      enum:
        - DRAFT
        - SUBMITTED
        - IN_REVIEW
        - PENDING_RESUBMISSION
        - APPROVED
        - REJECTED
        - REVOKED
        - CANCELLED

    ApprovalStatus:
      type: string
      enum:
        - PENDING
        - APPROVED
        - REJECTED
        - CHANGES_REQUESTED
        - REVIEW_REQUIRED

    # ===== Common Schemas =====
    Pagination:
      type: object
      properties:
        page:
          type: integer
        limit:
          type: integer
        total:
          type: integer
        totalPages:
          type: integer
        hasNext:
          type: boolean
        hasPrev:
          type: boolean

    Error:
      type: object
      properties:
        code:
          type: string
        message:
          type: string
        details:
          type: object
        timestamp:
          type: string
          format: date-time
        path:
          type: string
