openapi: 3.0.3
info:
  title: IZUBA API (expanded)
  version: 1.0.0
  description: Expanded OpenAPI specification covering members, loans, repayments, disbursements, reports, and exit balance.
servers:
  - url: http://localhost:{port}
    variables:
      port:
        default: "3000"
paths:
  /api/users:
    post:
      summary: Create a new user
      tags: [Users]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateUserRequest'
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
      security: 
        - bearerAuth: []
    get:
      security:
        - bearerAuth: []
      summary: List users
      tags: [Users]
      parameters:
        - in: query
          name: page
          schema:
            type: integer
            default: 1
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/User'

  /api/loans/applications:
    post:
      security:
        - bearerAuth: []
      summary: Submit a loan application
      tags: [Loans]
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                memberId:
                  type: string
                amount:
                  type: number
                interestRate:
                  type: number
                termMonths:
                  type: integer
                purpose:
                  type: string
                guarantor:
                  type: string
                documents:
                  type: array
                  items:
                    type: string
                    format: binary
              required: [memberId, amount, interestRate, termMonths]
      responses:
        '201':
          description: Application created with calculation
          content:
            application/json:
              schema:
                type: object
                properties:
                  applicationId:
                    type: string
                  calculation:
                    $ref: '#/components/schemas/LoanCalcResponse'

  /api/loans/calc:
    post:
      security:
        - bearerAuth: []
      summary: Calculate loan repayment values (preview)
      tags: [Loans]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/LoanCalcRequest'
      responses:
        '200':
          description: Calculation result
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LoanCalcResponse'

  /api/loans/{applicationId}/approve:
    post:
      security:
        - bearerAuth: []
      summary: Approve a loan application (create Loan and schedule)
      tags: [Loans]
      parameters:
        - in: path
          name: applicationId
          required: true
          schema:
            type: string
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/LoanApprovalRequest'
      responses:
        '200':
          description: Loan approved and loan record created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LoanResponse'

  /api/loans/{applicationId}/reject:
    post:
      security:
        - bearerAuth: []
      summary: Reject a loan application
      tags: [Loans]
      parameters:
        - in: path
          name: applicationId
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/LoanRejectRequest'
      responses:
        '200':
          description: Loan application rejected
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LoanApplication'

  /api/repayments:
    post:
      security:
        - bearerAuth: []
      summary: Record a repayment
      tags: [Repayments]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RepaymentRequest'
      responses:
        '201':
          description: Repayment recorded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Repayment'
    get:
      security:
        - bearerAuth: []
      summary: List repayment history with optional filters and pagination
      tags: [Repayments]
      parameters:
        - in: query
          name: loanId
          schema:
            type: string
        - in: query
          name: memberId
          schema:
            type: string
        - in: query
          name: limit
          schema:
            type: integer
        - in: query
          name: offset
          schema:
            type: integer
      responses:
        '200':
          description: Repayment history
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RepaymentList'

  /api/disbursements:
    post:
      security:
        - bearerAuth: []
      summary: Record a social disbursement
      tags: [Disbursements]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DisbursementRequest'
      responses:
        '201':
          description: Disbursement recorded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Disbursement'

  /api/loans:
    get:
      security:
        - bearerAuth: []
      summary: List loans with optional filters and pagination
      tags: [Loans]
      parameters:
        - in: query
          name: memberId
          schema:
            type: string
        - in: query
          name: status
          schema:
            type: string
        - in: query
          name: outstandingOnly
          schema:
            type: string
            enum: ["true","false","1","0"]
        - in: query
          name: limit
          schema:
            type: integer
        - in: query
          name: offset
          schema:
            type: integer
      responses:
        '200':
          description: List of loans
          content:
            application/json:
              schema:
                type: object
                properties:
                  loans:
                    type: array
                    items:
                      $ref: '#/components/schemas/LoanDetail'

  /api/loans/{loanId}:
    get:
      security:
        - bearerAuth: []
      summary: Get loan details by loan id
      tags: [Loans]
      parameters:
        - in: path
          name: loanId
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Loan details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LoanDetail'

  /api/members/{memberId}/exit-balance:
    get:
      security:
        - bearerAuth: []
      summary: Get exit balance for a member
      tags: [Members]
      parameters:
        - in: path
          name: memberId
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Exit balance calculation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExitBalanceResponse'

  /api/reports/summary:
    get:
      security:
        - bearerAuth: []
      summary: Get summary report
      tags: [Reports]
      parameters:
        - in: query
          name: from
          schema:
            type: string
            format: date
        - in: query
          name: to
          schema:
            type: string
            format: date
        - in: query
          name: format
          schema:
            type: string
            enum: [json,csv]
      responses:
        '200':
          description: Report data
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReportSummary'
      /api/reports/repayments:
        get:
          security:
            - bearerAuth: []
          summary: Repayments report (list and filters)
          tags: [Reports]
          parameters:
            - in: query
              name: from
              schema:
                type: string
                format: date
            - in: query
              name: to
              schema:
                type: string
                format: date
            - in: query
              name: memberId
              schema:
                type: string
            - in: query
              name: limit
              schema:
                type: integer
            - in: query
              name: offset
              schema:
                type: integer
            - in: query
              name: format
              schema:
                type: string
                enum: [json,csv]
          responses:
            '200':
              description: Repayments report
              content:
                application/json:
                  schema:
                    $ref: '#/components/schemas/RepaymentList'


    DisbursementRequest:
      type: object
      properties:
        memberId:
          type: string
        openapi: 3.0.3
        info:
          title: IZUBA API (expanded)
          version: 1.0.0
          description: Expanded OpenAPI specification covering members, loans, repayments, disbursements, reports, and exit balance.
        servers:
          - url: http://localhost:{port}
            variables:
              port:
                default: "3000"
        paths:
          /api/users:
            post:
              summary: Create a new user
              tags: [Users]
              requestBody:
                required: true
                content:
                  application/json:
                    schema:
                      $ref: '#/components/schemas/CreateUserRequest'
              responses:
                '201':
                  description: Created
                  content:
                    application/json:
                      schema:
                        $ref: '#/components/schemas/User'
              security: 
                - bearerAuth: []
            get:
              security:
                - bearerAuth: []
              summary: List users
              tags: [Users]
              parameters:
                - in: query
                  name: page
                  schema:
                    type: integer
                    default: 1
              responses:
                '200':
                  description: OK
                  content:
                    application/json:
                      schema:
                        type: array
                        items:
                          $ref: '#/components/schemas/User'

          /api/loans/applications:
            post:
              security:
                - bearerAuth: []
              summary: Submit a loan application
              tags: [Loans]
              requestBody:
                required: true
                content:
                  multipart/form-data:
                    schema:
                      type: object
                      properties:
                        memberId:
                          type: string
                        amount:
                          type: number
                        interestRate:
                          type: number
                        termMonths:
                          type: integer
                        purpose:
                          type: string
                        guarantor:
                          type: string
                        documents:
                          type: array
                          items:
                            type: string
                            format: binary
                      required: [memberId, amount, interestRate, termMonths]
              responses:
                '201':
                  description: Application created with calculation
                  content:
                    application/json:
                      schema:
                        type: object
                        properties:
                          applicationId:
                            type: string
                          calculation:
                            $ref: '#/components/schemas/LoanCalcResponse'

          /api/loans/calc:
            post:
              security:
                - bearerAuth: []
              summary: Calculate loan repayment values (preview)
              tags: [Loans]
              requestBody:
                required: true
                content:
                  application/json:
                    schema:
                      $ref: '#/components/schemas/LoanCalcRequest'
              responses:
                '200':
                  description: Calculation result
                  content:
                    application/json:
                      schema:
                        $ref: '#/components/schemas/LoanCalcResponse'

          /api/loans/{applicationId}/approve:
            post:
              security:
                - bearerAuth: []
              summary: Approve a loan application (create Loan and schedule)
              tags: [Loans]
              parameters:
                - in: path
                  name: applicationId
                  required: true
                  schema:
                    type: string
              requestBody:
                required: false
                content:
                  application/json:
                    schema:
                      $ref: '#/components/schemas/LoanApprovalRequest'
              responses:
                '200':
                  description: Loan approved and loan record created
                  content:
                    application/json:
                      schema:
                        $ref: '#/components/schemas/LoanResponse'

          /api/loans/{applicationId}/reject:
            post:
              security:
                - bearerAuth: []
              summary: Reject a loan application
              tags: [Loans]
              parameters:
                - in: path
                  name: applicationId
                  required: true
                  schema:
                    type: string
              requestBody:
                required: true
                content:
                  application/json:
                    schema:
                      $ref: '#/components/schemas/LoanRejectRequest'
              responses:
                '200':
                  description: Loan application rejected
                  content:
                    application/json:
                      schema:
                        $ref: '#/components/schemas/LoanApplication'

          /api/repayments:
            post:
              security:
                - bearerAuth: []
              summary: Record a repayment
              tags: [Repayments]
              requestBody:
                required: true
                content:
                  application/json:
                    schema:
                      $ref: '#/components/schemas/RepaymentRequest'
              responses:
                '201':
                  description: Repayment recorded
                  content:
                    application/json:
                      schema:
                        $ref: '#/components/schemas/Repayment'
            get:
              security:
                - bearerAuth: []
              summary: List repayment history with optional filters and pagination
              tags: [Repayments]
              parameters:
                - in: query
                  name: loanId
                  schema:
                    type: string
                - in: query
                  name: memberId
                  schema:
                    type: string
                - in: query
                  name: limit
                  schema:
                    type: integer
                - in: query
                  name: offset
                  schema:
                    type: integer
              responses:
                '200':
                  description: Repayment history
                  content:
                    application/json:
                      schema:
                        $ref: '#/components/schemas/RepaymentList'

          /api/disbursements:
            post:
              security:
                - bearerAuth: []
              summary: Record a social disbursement
              tags: [Disbursements]
              requestBody:
                required: true
                content:
                  application/json:
                    schema:
                      $ref: '#/components/schemas/DisbursementRequest'
              responses:
                '201':
                  description: Disbursement recorded
                  content:
                    application/json:
                      schema:
                        $ref: '#/components/schemas/Disbursement'

          /api/loans:
            get:
              security:
                - bearerAuth: []
              summary: List loans with optional filters and pagination
              tags: [Loans]
              parameters:
                - in: query
                  name: memberId
                  schema:
                    type: string
                - in: query
                  name: status
                  schema:
                    type: string
                - in: query
                  name: outstandingOnly
                  schema:
                    type: string
                    enum: ["true","false","1","0"]
                - in: query
                  name: limit
                  schema:
                    type: integer
                - in: query
                  name: offset
                  schema:
                    type: integer
              responses:
                '200':
                  description: List of loans
                  content:
                    application/json:
                      schema:
                        type: object
                        properties:
                          loans:
                            type: array
                            items:
                              $ref: '#/components/schemas/LoanDetail'

          /api/loans/{loanId}:
            get:
              security:
                - bearerAuth: []
              summary: Get loan details by loan id
              tags: [Loans]
              parameters:
                - in: path
                  name: loanId
                  required: true
                  schema:
                    type: string
              responses:
                '200':
                  description: Loan details
                  content:
                    application/json:
                      schema:
                        $ref: '#/components/schemas/LoanDetail'

          /api/members/{memberId}/exit-balance:
            get:
              security:
                - bearerAuth: []
              summary: Get exit balance for a member
              tags: [Members]
              parameters:
                - in: path
                  name: memberId
                  required: true
                  schema:
                    type: string
              responses:
                '200':
                  description: Exit balance calculation
                  content:
                    application/json:
                      schema:
                        $ref: '#/components/schemas/ExitBalanceResponse'

          /api/reports/summary:
            get:
              security:
                - bearerAuth: []
              summary: Get summary report
              tags: [Reports]
              parameters:
                - in: query
                  name: from
                  schema:
                    type: string
                    format: date
                - in: query
                  name: to
                  schema:
                    type: string
                    format: date
                - in: query
                  name: format
                  schema:
                    type: string
                    enum: [json,csv]
              responses:
                '200':
                  description: Report data
                  content:
                    application/json:
                      schema:
                        $ref: '#/components/schemas/ReportSummary'
              /api/reports/repayments:
                get:
                  security:
                    - bearerAuth: []
                  summary: Repayments report (list and filters)
                  tags: [Reports]
                  parameters:
                    - in: query
                      name: from
                      schema:
                        type: string
                        format: date
                    - in: query
                      name: to
                      schema:
                        type: string
                        format: date
                    - in: query
                      name: memberId
                      schema:
                        type: string
                    - in: query
                      name: limit
                      schema:
                        type: integer
                    - in: query
                      name: offset
                      schema:
                        type: integer
                    - in: query
                      name: format
                      schema:
                        type: string
                        enum: [json,csv]
                  responses:
                    '200':
                      description: Repayments report
                      content:
                        application/json:
                          schema:
                            $ref: '#/components/schemas/RepaymentList'

              /api/reports/disbursements:
                get:
                  security:
                    - bearerAuth: []
                  summary: Disbursements report (list, totals and filters)
                  tags: [Reports]
                  parameters:
                    - in: query
                      name: from
                      schema:
                        type: string
                        format: date
                    - in: query
                      name: to
                      schema:
                        type: string
                        format: date
                    - in: query
                      name: memberId
                      schema:
                        type: string
                    - in: query
                      name: limit
                      schema:
                        type: integer
                    - in: query
                      name: offset
                      schema:
                        type: integer
                    - in: query
                      name: format
                      schema:
                        type: string
                        enum: [json,csv]
                  responses:
                    '200':
                      description: Disbursements report
                      content:
                        application/json:
                          schema:
                            $ref: '#/components/schemas/DisbursementList'

              /api/reports/loans:
                get:
                  security:
                    - bearerAuth: []
                  summary: Loans report (list, aggregates and filters)
                  tags: [Reports]
                  parameters:
                    - in: query
                      name: status
                      schema:
                        type: string
                    - in: query
                      name: memberId
                      schema:
                        type: string
                    - in: query
                      name: limit
                      schema:
                        type: integer
                    - in: query
                      name: offset
                      schema:
                        type: integer
                    - in: query
                      name: format
                      schema:
                        type: string
                        enum: [json,csv]
                  responses:
                    '200':
                      description: Loans report
                      content:
                        application/json:
                          schema:
                            $ref: '#/components/schemas/LoansReport'
          /api/auth/login:
            post:
              summary: Login and receive a JWT token
              tags: [Auth]
              requestBody:
                required: true
                content:
                  application/json:
                    schema:
                      $ref: '#/components/schemas/LoginRequest'
              responses:
                '200':
                  description: Successful login
                  content:
                    application/json:
                      schema:
                        $ref: '#/components/schemas/LoginResponse'
                '400':
                  description: Bad request
                '401':
                  description: Unauthorized

          /api/loan-limits:
            post:
              security:
                - bearerAuth: []
              summary: Create a loan limit range (salary -> loan limit)
              tags: [LoanLimits]
              requestBody:
                required: true
                content:
                  application/json:
                    schema:
                      $ref: '#/components/schemas/LoanLimitCreate'
              responses:
                '201':
                  description: Created
                  content:
                    application/json:
                      schema:
                        $ref: '#/components/schemas/LoanLimit'
            get:
              security:
                - bearerAuth: []
              summary: List configured loan limits
              tags: [LoanLimits]
              responses:
                '200':
                  description: OK
                  content:
                    application/json:
                      schema:
                        type: object
                        properties:
                          limits:
                            type: array
                            items:
                              $ref: '#/components/schemas/LoanLimit'
          /api/loan-limits/match:
            get:
              security:
                - bearerAuth: []
              summary: Get matched loan limit for a member or salary
              tags: [LoanLimits]
              parameters:
                - in: query
                  name: memberId
                  schema:
                    type: string
                - in: query
                  name: salary
                  schema:
                    type: number
              responses:
                '200':
                  description: Matched limit
                  content:
                    application/json:
                      schema:
                        type: object
                        properties:
                          limit:
                            $ref: '#/components/schemas/LoanLimit'

          /api/loan-limits/{id}:
            delete:
              security:
                - bearerAuth: []
              summary: Delete a loan limit by id
              tags: [LoanLimits]
              parameters:
                - in: path
                  name: id
                  required: true
                  schema:
                    type: string
              responses:
                '200':
                  description: Deleted
                  content:
                    application/json:
                      schema:
                        type: object
                        properties:
                          id:
                            type: string
                          deleted:
                            type: boolean

          /api/loan-limits:
            put:
              security:
                - bearerAuth: []
              summary: Update a loan limit entry
              tags: [LoanLimits]
              requestBody:
                required: true
                content:
                  application/json:
                    schema:
                      $ref: '#/components/schemas/LoanLimitUpdate'
              responses:
                '200':
                  description: Updated
                  content:
                    application/json:
                      schema:
                        $ref: '#/components/schemas/LoanLimit'

        components:
          schemas:
            CreateUserRequest:
              type: object
              properties:
                fullName:
                  type: string
                email:
                  type: string
                  format: email
                password:
                  type: string
                netsallary:
                  type: number
                savingAmount:
                  type: number
                role:
                  type: string
                  enum: [ADMIN, MEMBER, ACCOUNTANT]
              required: [fullName, email, password]

            User:
              type: object
              properties:
                id:
                  type: string
                fullName:
                  type: string
                email:
                  type: string
                netsallary:
                  type: number
                savingAmount:
                  type: number
                role:
                  type: string
                  enum: [ADMIN, MEMBER, ACCOUNTANT]
                createdAt:
                  type: string
                  format: date-time

            LoanApplicationRequest:
              type: object
              properties:
                memberId:
                  type: string
                amount:
                  type: number
                interestRate:
                  type: number
                termMonths:
                  type: integer
                purpose:
                  type: string
                guarantor:
                  type: object
                  properties:
                    name:
                      type: string
                    contact:
                      type: string
                documents:
                  type: array
                  items:
                    type: string
              required: [memberId, amount, interestRate, termMonths]

            LoanApplication:
              type: object
              properties:
                id:
                  type: string
                memberId:
                  type: string
                amount:
                  type: number
                interestRate:
                  type: number
                termMonths:
                  type: integer
                purpose:
                  type: string
                status:
                  type: string
                createdAt:
                  type: string
                  format: date-time

            LoanCalcRequest:
              type: object
              properties:
                amount:
                  type: number
                interestRate:
                  type: number
                termMonths:
                  type: integer
              required: [amount, interestRate, termMonths]

            LoanCalcResponse:
              type: object
              properties:
                monthlyPayment:
                  type: number
                totalInterest:
                  type: number
                totalRepayment:
                  type: number

            Loan:
              type: object
              properties:
                id:
                  type: string
                principal:
                  type: number
                interestRate:
                  type: number
                termMonths:
                  type: integer
                status:
                  type: string
                outstandingPrincipal:
                  type: number
            LoanDetail:
              allOf:
                - $ref: '#/components/schemas/Loan'
                - type: object
                  properties:
                    repayments:
                      type: array
                      items:
                        $ref: '#/components/schemas/Repayment'
                    application:
                      $ref: '#/components/schemas/LoanApplication'

            RepaymentRequest:
              type: object
              properties:
                loanId:
                  type: string
                amount:
                  type: number
                date:
                  type: string
                  format: date
              required: [loanId, amount]

            Repayment:
              type: object
              properties:
                id:
                  type: string
                loanId:
                  type: string
                amount:
                  type: number
                date:
                  type: string
                  format: date-time

            RepaymentList:
              type: object
              properties:
                repayments:
                  type: array
                  items:
                    $ref: '#/components/schemas/Repayment'
                total:
                  type: integer
                limit:
                  type: integer
                offset:
                  type: integer

            DisbursementRequest:
              type: object
              properties:
                memberId:
                  type: string
                amount:
                  type: number
                date:
                  type: string
                reason:
                  type: string
              required: [memberId, amount]

            Disbursement:
              type: object
              properties:
                id:
                  type: string
                memberId:
                  type: string
                amount:
                  type: number
                date:
                  type: string
                member:
                  $ref: '#/components/schemas/User'

            ExitBalanceResponse:
              type: object
              properties:
                totalSavings:
                  type: number
                outstandingPrincipal:
                  type: number
                outstandingInterest:
                  type: number
                socialContributions:
                  type: number
                exitBalance:
                  type: number

            ReportSummary:
              type: object
              properties:
                totalSavings:
                  type: number
                totalOutstandingPrincipal:
                  type: number
                socialContributions:
                  type: number

            DisbursementList:
              type: object
              properties:
                disbursements:
                  type: array
                  items:
                    $ref: '#/components/schemas/Disbursement'
                total:
                  type: integer
                totalAmount:
                  type: number
                limit:
                  type: integer
                offset:
                  type: integer

            LoansReport:
              type: object
              properties:
                loans:
                  type: array
                  items:
                    $ref: '#/components/schemas/LoanDetail'
                total:
                  type: integer
                totalOutstanding:
                  type: number
                totalPrincipal:
                  type: number
                statusCounts:
                  type: object
                  additionalProperties:
                    type: integer
                limit:
                  type: integer
                offset:
                  type: integer

            LoginRequest:
              type: object
              properties:
                email:
                  type: string
                  format: email
                password:
                  type: string
              required: [email, password]

            LoginResponse:
              type: object
              properties:
                token:
                  type: string
                user:
                  $ref: '#/components/schemas/User'
            LoanApprovalRequest:
              type: object
              properties:
                approvedBy:
                  type: string
                approvedAt:
                  type: string
                  format: date-time

            LoanRejectRequest:
              type: object
              properties:
                reason:
                  type: string
              required: [reason]

            LoanResponse:
              type: object
              properties:
                id:
                  type: string
                applicationId:
                  type: string
                principal:
                  type: number
                interestRate:
                  type: number
                termMonths:
                  type: integer
                status:
                  type: string
                schedule:
                  type: array
                  items:
                    $ref: '#/components/schemas/RepaymentSchedule'

            RepaymentSchedule:
              type: object
              properties:
                installmentNumber:
                  type: integer
                dueDate:
                  type: string
                  format: date
                principal:
                  type: number
                interest:
                  type: number
                total:
                  type: number
            LoanLimit:
              type: object
              properties:
                id:
                  type: string
                minSalary:
                  type: number
                maxSalary:
                  type: number
                loanLimit:
                  type: number
                createdBy:
                  type: string
                  nullable: true
                createdAt:
                  type: string
                  format: date-time

            LoanLimitCreate:
              type: object
              properties:
                minSalary:
                  type: number
                maxSalary:
                  type: number
                loanLimit:
                  type: number
                createdBy:
                  type: string
              required: [minSalary, maxSalary, loanLimit]

            LoanLimitUpdate:
              type: object
              properties:
                id:
                  type: string
                minSalary:
                  type: number
                maxSalary:
                  type: number
                loanLimit:
                  type: number
              required: [id]
          securitySchemes:
            bearerAuth:
              type: http
              scheme: bearer
              bearerFormat: JWT

        security: []
