openapi: 3.1.0
info:
  title: Api
  version: 0.1.0
  description: CDACC Learning Plan AI API specification
servers:
  - url: /api
    description: Base API path
tags:
  - name: health
    description: Health operations
  - name: institutions
    description: Institution management
  - name: departments
    description: Department management
  - name: documents
    description: Knowledge base document library
  - name: templates
    description: Plan templates
  - name: plans
    description: Learning and session plans
  - name: approvals
    description: Approval workflow
  - name: dashboard
    description: Dashboard analytics
  - name: user-profile
    description: User profile

paths:
  /healthz:
    get:
      operationId: healthCheck
      tags: [health]
      summary: Health check
      responses:
        "200":
          description: Healthy
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HealthStatus"

  # User Profile
  /profile:
    get:
      operationId: getProfile
      tags: [user-profile]
      summary: Get current user profile
      responses:
        "200":
          description: User profile
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UserProfile"
        "404":
          description: Not found
    patch:
      operationId: updateProfile
      tags: [user-profile]
      summary: Update current user profile
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UserProfileUpdate"
      responses:
        "200":
          description: Updated profile
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UserProfile"

  # Institutions
  /institutions:
    get:
      operationId: listInstitutions
      tags: [institutions]
      summary: List institutions
      responses:
        "200":
          description: List of institutions
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Institution"
    post:
      operationId: createInstitution
      tags: [institutions]
      summary: Create institution
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/InstitutionInput"
      responses:
        "201":
          description: Created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Institution"

  /institutions/{id}:
    get:
      operationId: getInstitution
      tags: [institutions]
      summary: Get institution
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        "200":
          description: Institution
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Institution"
        "404":
          description: Not found
    patch:
      operationId: updateInstitution
      tags: [institutions]
      summary: Update institution
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/InstitutionUpdate"
      responses:
        "200":
          description: Updated
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Institution"

  # Departments
  /departments:
    get:
      operationId: listDepartments
      tags: [departments]
      summary: List departments
      parameters:
        - name: institutionId
          in: query
          schema:
            type: integer
      responses:
        "200":
          description: List of departments
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Department"
    post:
      operationId: createDepartment
      tags: [departments]
      summary: Create department
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DepartmentInput"
      responses:
        "201":
          description: Created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Department"

  /departments/{id}:
    patch:
      operationId: updateDepartment
      tags: [departments]
      summary: Update department
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DepartmentUpdate"
      responses:
        "200":
          description: Updated
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Department"
    delete:
      operationId: deleteDepartment
      tags: [departments]
      summary: Delete department
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        "204":
          description: Deleted

  # Documents
  /documents:
    get:
      operationId: listDocuments
      tags: [documents]
      summary: List documents in knowledge base
      parameters:
        - name: institutionId
          in: query
          schema:
            type: integer
        - name: tag
          in: query
          schema:
            type: string
      responses:
        "200":
          description: List of documents
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Document"

  /documents/{id}:
    get:
      operationId: getDocument
      tags: [documents]
      summary: Get document
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        "200":
          description: Document
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Document"
        "404":
          description: Not found
    delete:
      operationId: deleteDocument
      tags: [documents]
      summary: Delete document
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        "204":
          description: Deleted

  # Templates
  /templates:
    get:
      operationId: listTemplates
      tags: [templates]
      summary: List templates
      parameters:
        - name: institutionId
          in: query
          schema:
            type: integer
        - name: type
          in: query
          schema:
            type: string
      responses:
        "200":
          description: List of templates
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Template"
    post:
      operationId: createTemplate
      tags: [templates]
      summary: Create template
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TemplateInput"
      responses:
        "201":
          description: Created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Template"

  /templates/{id}:
    get:
      operationId: getTemplate
      tags: [templates]
      summary: Get template
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        "200":
          description: Template
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Template"
    patch:
      operationId: updateTemplate
      tags: [templates]
      summary: Update template
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TemplateUpdate"
      responses:
        "200":
          description: Updated
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Template"
    delete:
      operationId: deleteTemplate
      tags: [templates]
      summary: Delete template
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        "204":
          description: Deleted

  # Plans
  /plans:
    get:
      operationId: listPlans
      tags: [plans]
      summary: List plans
      parameters:
        - name: status
          in: query
          schema:
            type: string
        - name: institutionId
          in: query
          schema:
            type: integer
        - name: createdById
          in: query
          schema:
            type: string
      responses:
        "200":
          description: List of plans
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Plan"
    post:
      operationId: createPlan
      tags: [plans]
      summary: Create a new plan
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PlanInput"
      responses:
        "201":
          description: Created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Plan"

  /plans/{id}:
    get:
      operationId: getPlan
      tags: [plans]
      summary: Get plan with all details
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        "200":
          description: Plan detail
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlanDetail"
        "404":
          description: Not found
    patch:
      operationId: updatePlan
      tags: [plans]
      summary: Update plan
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PlanUpdate"
      responses:
        "200":
          description: Updated
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Plan"
    delete:
      operationId: deletePlan
      tags: [plans]
      summary: Delete plan
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        "204":
          description: Deleted

  /plans/{id}/generate:
    post:
      operationId: generatePlan
      tags: [plans]
      summary: Generate AI plan content
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/GeneratePlanRequest"
      responses:
        "200":
          description: Generation result
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GeneratePlanResult"

  /plans/{id}/duplicate:
    post:
      operationId: duplicatePlan
      tags: [plans]
      summary: Duplicate a plan
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        "201":
          description: Duplicated plan
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Plan"

  /plans/{id}/export:
    post:
      operationId: exportPlan
      tags: [plans]
      summary: Export plan to PDF or DOCX
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ExportRequest"
      responses:
        "200":
          description: Export result
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ExportResult"

  # Session Rows
  /plans/{id}/sessions:
    get:
      operationId: listSessionRows
      tags: [plans]
      summary: List session rows for a plan
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        "200":
          description: Session rows
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/SessionRow"
    post:
      operationId: createSessionRow
      tags: [plans]
      summary: Create a session row
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SessionRowInput"
      responses:
        "201":
          description: Created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SessionRow"

  /plans/{id}/sessions/{sessionId}:
    patch:
      operationId: updateSessionRow
      tags: [plans]
      summary: Update a session row
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
        - name: sessionId
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SessionRowUpdate"
      responses:
        "200":
          description: Updated
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SessionRow"
    delete:
      operationId: deleteSessionRow
      tags: [plans]
      summary: Delete a session row
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
        - name: sessionId
          in: path
          required: true
          schema:
            type: integer
      responses:
        "204":
          description: Deleted

  /plans/{id}/sessions/{sessionId}/regenerate:
    post:
      operationId: regenerateSession
      tags: [plans]
      summary: Regenerate a single session using AI
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
        - name: sessionId
          in: path
          required: true
          schema:
            type: integer
      responses:
        "200":
          description: Regenerated session row
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SessionRow"

  # Timetable
  /plans/{id}/timetable:
    get:
      operationId: getTimetable
      tags: [plans]
      summary: Get timetable for a plan
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        "200":
          description: Timetable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Timetable"
        "404":
          description: Not found
    put:
      operationId: upsertTimetable
      tags: [plans]
      summary: Create or update timetable for a plan
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TimetableInput"
      responses:
        "200":
          description: Timetable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Timetable"

  /plans/{id}/timetable/schedule:
    get:
      operationId: getTimetableSchedule
      tags: [plans]
      summary: Get auto-calculated session schedule for a plan
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        "200":
          description: Computed schedule
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TimetableSchedule"

  # Session Plans (detailed per-session AI plans)
  /plans/{id}/sessions/{sessionId}/session-plan:
    get:
      operationId: getSessionPlan
      tags: [plans]
      summary: Get detailed session plan for a session row
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
        - name: sessionId
          in: path
          required: true
          schema:
            type: integer
      responses:
        "200":
          description: Session plan
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SessionPlan"
        "404":
          description: Not found
    post:
      operationId: generateSessionPlan
      tags: [plans]
      summary: AI-generate a detailed session plan for a session row
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
        - name: sessionId
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/GenerateSessionPlanRequest"
      responses:
        "201":
          description: Generated session plan
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SessionPlan"

  /session-plans/{id}:
    get:
      operationId: getSessionPlanById
      tags: [plans]
      summary: Get session plan by ID
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        "200":
          description: Session plan
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SessionPlan"
    patch:
      operationId: updateSessionPlan
      tags: [plans]
      summary: Update session plan metadata or content
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateSessionPlanRequest"
      responses:
        "200":
          description: Updated session plan
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SessionPlan"

  /session-plans/{id}/regenerate-section:
    post:
      operationId: regenerateSessionPlanSection
      tags: [plans]
      summary: Regenerate a single section of a session plan using AI
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/RegenerateSectionRequest"
      responses:
        "200":
          description: Updated session plan with regenerated section
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SessionPlan"

  /plans/{id}/generate-all-session-plans:
    post:
      operationId: generateAllSessionPlans
      tags: [plans]
      summary: Batch generate detailed session plans for all session rows
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/GenerateSessionPlanRequest"
      responses:
        "200":
          description: Generation result
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BatchGenerateResult"

  # Approvals
  /plans/{id}/approvals:
    get:
      operationId: listApprovals
      tags: [approvals]
      summary: List approvals for a plan
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        "200":
          description: List of approvals
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Approval"
    post:
      operationId: createApproval
      tags: [approvals]
      summary: Submit an approval action
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ApprovalInput"
      responses:
        "201":
          description: Created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Approval"

  # Comments
  /plans/{id}/comments:
    get:
      operationId: listComments
      tags: [plans]
      summary: List comments for a plan
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        "200":
          description: Comments
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Comment"
    post:
      operationId: createComment
      tags: [plans]
      summary: Add a comment to a plan
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CommentInput"
      responses:
        "201":
          description: Created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Comment"

  # Dashboard
  /dashboard/stats:
    get:
      operationId: getDashboardStats
      tags: [dashboard]
      summary: Get dashboard statistics
      responses:
        "200":
          description: Dashboard stats
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DashboardStats"

  /dashboard/recent-plans:
    get:
      operationId: getRecentPlans
      tags: [dashboard]
      summary: Get recent plans
      responses:
        "200":
          description: Recent plans
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Plan"

  /dashboard/plans-by-status:
    get:
      operationId: getPlansByStatus
      tags: [dashboard]
      summary: Get plans grouped by status
      responses:
        "200":
          description: Plans by status
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/StatusCount"

components:
  schemas:
    HealthStatus:
      type: object
      required: [status]
      properties:
        status:
          type: string

    # User Profile
    UserProfile:
      type: object
      required: [id, clerkUserId, role]
      properties:
        id:
          type: integer
        clerkUserId:
          type: string
        email:
          type: ["string", "null"]
        firstName:
          type: ["string", "null"]
        lastName:
          type: ["string", "null"]
        role:
          type: string
          enum: [admin, trainer, reviewer, manager]
        institutionId:
          type: ["integer", "null"]
        departmentId:
          type: ["integer", "null"]
        createdAt:
          type: string

    UserProfileUpdate:
      type: object
      properties:
        firstName:
          type: string
        lastName:
          type: string
        role:
          type: string
          enum: [admin, trainer, reviewer, manager]
        institutionId:
          type: integer
        departmentId:
          type: integer

    # Institution
    Institution:
      type: object
      required: [id, name]
      properties:
        id:
          type: integer
        name:
          type: string
        address:
          type: ["string", "null"]
        logoUrl:
          type: ["string", "null"]
        defaultHeaderText:
          type: ["string", "null"]
        defaultFooterText:
          type: ["string", "null"]
        signatureLines:
          type: ["string", "null"]
        createdAt:
          type: string

    InstitutionInput:
      type: object
      required: [name]
      properties:
        name:
          type: string
        address:
          type: string
        logoUrl:
          type: string
        defaultHeaderText:
          type: string
        defaultFooterText:
          type: string
        signatureLines:
          type: string

    InstitutionUpdate:
      type: object
      properties:
        name:
          type: string
        address:
          type: string
        logoUrl:
          type: string
        defaultHeaderText:
          type: string
        defaultFooterText:
          type: string
        signatureLines:
          type: string

    # Department
    Department:
      type: object
      required: [id, name, institutionId]
      properties:
        id:
          type: integer
        name:
          type: string
        institutionId:
          type: integer
        description:
          type: ["string", "null"]
        createdAt:
          type: string

    DepartmentInput:
      type: object
      required: [name, institutionId]
      properties:
        name:
          type: string
        institutionId:
          type: integer
        description:
          type: string

    DepartmentUpdate:
      type: object
      properties:
        name:
          type: string
        description:
          type: string

    # Document
    Document:
      type: object
      required: [id, title, fileType, uploadedAt]
      properties:
        id:
          type: integer
        title:
          type: string
        fileType:
          type: string
          enum: [pdf, docx, txt]
        institutionId:
          type: ["integer", "null"]
        courseName:
          type: ["string", "null"]
        level:
          type: ["string", "null"]
        unitCode:
          type: ["string", "null"]
        tag:
          type: ["string", "null"]
          enum: [occupational_standard, curriculum_design, assessment_guideline, approval_template, session_plan_sample, learning_plan_sample, policy_or_procedure, null]
        filePath:
          type: string
        extractedText:
          type: ["string", "null"]
        uploadedAt:
          type: string
        uploadedById:
          type: ["string", "null"]

    # Template
    Template:
      type: object
      required: [id, name, type]
      properties:
        id:
          type: integer
        name:
          type: string
        type:
          type: string
          enum: [learning_plan, session_plan]
        sector:
          type: ["string", "null"]
        institutionId:
          type: ["integer", "null"]
        columns:
          type: ["string", "null"]
        isDefault:
          type: boolean
        createdAt:
          type: string

    TemplateInput:
      type: object
      required: [name, type]
      properties:
        name:
          type: string
        type:
          type: string
          enum: [learning_plan, session_plan]
        sector:
          type: string
        institutionId:
          type: integer
        columns:
          type: string
        isDefault:
          type: boolean

    TemplateUpdate:
      type: object
      properties:
        name:
          type: string
        type:
          type: string
        sector:
          type: string
        columns:
          type: string
        isDefault:
          type: boolean

    # Plan
    Plan:
      type: object
      required: [id, unitTitle, status, createdAt]
      properties:
        id:
          type: integer
        unitTitle:
          type: string
        unitCode:
          type: ["string", "null"]
        level:
          type: ["string", "null"]
        trainerName:
          type: ["string", "null"]
        className:
          type: ["string", "null"]
        numberOfTrainees:
          type: ["integer", "null"]
        totalDuration:
          type: ["string", "null"]
        deliveryMode:
          type: ["string", "null"]
        numberOfSessions:
          type: ["integer", "null"]
        sessionDuration:
          type: ["string", "null"]
        institutionId:
          type: ["integer", "null"]
        departmentId:
          type: ["integer", "null"]
        createdById:
          type: ["string", "null"]
        templateId:
          type: ["integer", "null"]
        status:
          type: string
          enum: [draft, trainer_review, hod_review, iqa_review, approved, rejected]
        versionNumber:
          type: integer
        complianceFlags:
          type: ["string", "null"]
        improvementNotes:
          type: ["string", "null"]
        dateOfPreparation:
          type: ["string", "null"]
        dateOfRevision:
          type: ["string", "null"]
        createdAt:
          type: string
        updatedAt:
          type: string

    PlanInput:
      type: object
      required: [unitTitle]
      properties:
        unitTitle:
          type: string
        unitCode:
          type: string
        level:
          type: string
        trainerName:
          type: string
        className:
          type: string
        numberOfTrainees:
          type: integer
        totalDuration:
          type: string
        deliveryMode:
          type: string
        numberOfSessions:
          type: integer
        sessionDuration:
          type: string
        institutionId:
          type: integer
        departmentId:
          type: integer
        templateId:
          type: integer
        dateOfPreparation:
          type: string
        dateOfRevision:
          type: string

    PlanUpdate:
      type: object
      properties:
        unitTitle:
          type: string
        unitCode:
          type: string
        level:
          type: string
        trainerName:
          type: string
        className:
          type: string
        numberOfTrainees:
          type: integer
        totalDuration:
          type: string
        deliveryMode:
          type: string
        status:
          type: string
          enum: [draft, trainer_review, hod_review, iqa_review, approved, rejected]
        complianceFlags:
          type: string
        improvementNotes:
          type: string
        dateOfPreparation:
          type: string
        dateOfRevision:
          type: string

    PlanDetail:
      type: object
      required: [id, unitTitle, status, createdAt, sessions]
      properties:
        id:
          type: integer
        unitTitle:
          type: string
        unitCode:
          type: ["string", "null"]
        level:
          type: ["string", "null"]
        trainerName:
          type: ["string", "null"]
        className:
          type: ["string", "null"]
        numberOfTrainees:
          type: ["integer", "null"]
        totalDuration:
          type: ["string", "null"]
        deliveryMode:
          type: ["string", "null"]
        numberOfSessions:
          type: ["integer", "null"]
        sessionDuration:
          type: ["string", "null"]
        institutionId:
          type: ["integer", "null"]
        departmentId:
          type: ["integer", "null"]
        createdById:
          type: ["string", "null"]
        templateId:
          type: ["integer", "null"]
        status:
          type: string
          enum: [draft, trainer_review, hod_review, iqa_review, approved, rejected]
        versionNumber:
          type: integer
        complianceFlags:
          type: ["string", "null"]
        improvementNotes:
          type: ["string", "null"]
        dateOfPreparation:
          type: ["string", "null"]
        dateOfRevision:
          type: ["string", "null"]
        sessions:
          type: array
          items:
            $ref: "#/components/schemas/SessionRow"
        approvals:
          type: array
          items:
            $ref: "#/components/schemas/Approval"
        comments:
          type: array
          items:
            $ref: "#/components/schemas/Comment"
        createdAt:
          type: string
        updatedAt:
          type: string

    GeneratePlanRequest:
      type: object
      required: [documentType]
      properties:
        documentType:
          type: string
          enum: [learning_plan, session_plan, both]
        weeklyStructure:
          type: string
        sessionsPerWeek:
          type: integer
        specificOutcomes:
          type: string
        practicalEmphasis:
          type: string
        assessmentStyle:
          type: string
        availableResources:
          type: string
        documentIds:
          type: array
          items:
            type: integer

    GeneratePlanResult:
      type: object
      required: [success]
      properties:
        success:
          type: boolean
        sessions:
          type: array
          items:
            $ref: "#/components/schemas/SessionRow"
        complianceFlags:
          type: array
          items:
            type: string
        improvementNotes:
          type: array
          items:
            type: string
        sourcedDocuments:
          type: array
          items:
            type: string

    ExportRequest:
      type: object
      required: [format]
      properties:
        format:
          type: string
          enum: [pdf, docx]

    ExportResult:
      type: object
      required: [success, downloadUrl]
      properties:
        success:
          type: boolean
        downloadUrl:
          type: string
        format:
          type: string

    # Timetable
    TeachingSlot:
      type: object
      required: [dayOfWeek, startTime, endTime]
      properties:
        dayOfWeek:
          type: integer
          description: "0=Sun, 1=Mon, 2=Tue, 3=Wed, 4=Thu, 5=Fri, 6=Sat"
        startTime:
          type: string
          description: "HH:MM"
        endTime:
          type: string
          description: "HH:MM"
        venue:
          type: ["string", "null"]

    Timetable:
      type: object
      required: [id, planId]
      properties:
        id:
          type: integer
        planId:
          type: integer
        termStartDate:
          type: ["string", "null"]
        termEndDate:
          type: ["string", "null"]
        teachingSlots:
          type: array
          items:
            $ref: "#/components/schemas/TeachingSlot"
        holidays:
          type: array
          items:
            type: string
        excludedDates:
          type: array
          items:
            type: string
        notes:
          type: ["string", "null"]
        createdAt:
          type: string
        updatedAt:
          type: string

    TimetableInput:
      type: object
      properties:
        termStartDate:
          type: string
        termEndDate:
          type: string
        teachingSlots:
          type: array
          items:
            $ref: "#/components/schemas/TeachingSlot"
        holidays:
          type: array
          items:
            type: string
        excludedDates:
          type: array
          items:
            type: string
        notes:
          type: string

    ScheduledSession:
      type: object
      required: [sessionIndex, date, dayOfWeek, startTime, endTime]
      properties:
        sessionIndex:
          type: integer
        date:
          type: string
        dayOfWeek:
          type: integer
        startTime:
          type: string
        endTime:
          type: string
        venue:
          type: ["string", "null"]
        sessionRowId:
          type: ["integer", "null"]
        topic:
          type: ["string", "null"]

    TimetableSchedule:
      type: object
      required: [sessions, totalSessions]
      properties:
        totalSessions:
          type: integer
        sessions:
          type: array
          items:
            $ref: "#/components/schemas/ScheduledSession"

    # Session Plan
    ParticipationStage:
      type: object
      required: [title, duration]
      properties:
        title:
          type: string
        duration:
          type: string
        trainerActivity:
          type: string
        traineeActivity:
          type: string
        teachingMethod:
          type: string
        learningCheck:
          type: string
        notes:
          type: ["string", "null"]

    SessionPlanContent:
      type: object
      properties:
        bridge_in:
          type: object
          properties:
            attentionGrabber:
              type: string
            scenario:
              type: string
            priorKnowledgeActivity:
              type: string
        learning_outcomes:
          type: array
          items:
            type: string
        resources:
          type: array
          items:
            type: string
        safety_requirements:
          type: array
          items:
            type: string
        pre_assessment:
          type: array
          items:
            type: string
        participatory_stages:
          type: array
          items:
            $ref: "#/components/schemas/ParticipationStage"
        post_assessment:
          type: array
          items:
            type: string
        summary:
          type: object
          properties:
            recap:
              type: string
            keyTakeaways:
              type: array
              items:
                type: string
            assignment:
              type: string
            nextLessonPrep:
              type: string
        reflection_prompts:
          type: array
          items:
            type: string

    SessionPlan:
      type: object
      required: [id, sessionRowId, planId, status, createdAt]
      properties:
        id:
          type: integer
        sessionRowId:
          type: integer
        planId:
          type: integer
        scheduledDate:
          type: ["string", "null"]
        scheduledStartTime:
          type: ["string", "null"]
        scheduledEndTime:
          type: ["string", "null"]
        duration:
          type: ["string", "null"]
        venue:
          type: ["string", "null"]
        status:
          type: string
          enum: [draft, approved]
        content:
          $ref: "#/components/schemas/SessionPlanContent"
        createdAt:
          type: string
        updatedAt:
          type: string

    GenerateSessionPlanRequest:
      type: object
      properties:
        duration:
          type: string
          description: "e.g. '2 hours', '4 hours'"
        venue:
          type: string
        scheduledDate:
          type: string
        scheduledStartTime:
          type: string
        scheduledEndTime:
          type: string
        deliveryContext:
          type: string
          description: "classroom, workshop, lab, fieldwork"
        documentIds:
          type: array
          items:
            type: integer

    UpdateSessionPlanRequest:
      type: object
      properties:
        scheduledDate:
          type: string
        scheduledStartTime:
          type: string
        scheduledEndTime:
          type: string
        duration:
          type: string
        venue:
          type: string
        status:
          type: string
          enum: [draft, approved]
        content:
          $ref: "#/components/schemas/SessionPlanContent"

    RegenerateSectionRequest:
      type: object
      required: [section]
      properties:
        section:
          type: string
          enum: [bridge_in, pre_assessment, participatory_stages, post_assessment, summary, reflection_prompts]
        extraInstructions:
          type: string

    BatchGenerateResult:
      type: object
      required: [success, generated, failed]
      properties:
        success:
          type: boolean
        generated:
          type: integer
        failed:
          type: integer
        sessionPlanIds:
          type: array
          items:
            type: integer

    # Session Row
    SessionRow:
      type: object
      required: [id, planId, weekNumber, sessionNumber]
      properties:
        id:
          type: integer
        planId:
          type: integer
        weekNumber:
          type: integer
        sessionNumber:
          type: integer
        topic:
          type: ["string", "null"]
        subtopic:
          type: ["string", "null"]
        learningOutcome:
          type: ["string", "null"]
        trainerActivity:
          type: ["string", "null"]
        traineeActivity:
          type: ["string", "null"]
        resources:
          type: ["string", "null"]
        assessmentMethod:
          type: ["string", "null"]
        duration:
          type: ["string", "null"]
        performanceCriteria:
          type: ["string", "null"]
        evidenceRequired:
          type: ["string", "null"]
        deliveryMode:
          type: ["string", "null"]
        practicalExercise:
          type: ["string", "null"]
        reflection:
          type: ["string", "null"]
        notes:
          type: ["string", "null"]
        isLocked:
          type: boolean
        createdAt:
          type: string

    SessionRowInput:
      type: object
      required: [weekNumber, sessionNumber]
      properties:
        weekNumber:
          type: integer
        sessionNumber:
          type: integer
        topic:
          type: string
        subtopic:
          type: string
        learningOutcome:
          type: string
        trainerActivity:
          type: string
        traineeActivity:
          type: string
        resources:
          type: string
        assessmentMethod:
          type: string
        duration:
          type: string
        performanceCriteria:
          type: string
        evidenceRequired:
          type: string
        deliveryMode:
          type: string
        practicalExercise:
          type: string
        reflection:
          type: string
        notes:
          type: string

    SessionRowUpdate:
      type: object
      properties:
        topic:
          type: string
        subtopic:
          type: string
        learningOutcome:
          type: string
        trainerActivity:
          type: string
        traineeActivity:
          type: string
        resources:
          type: string
        assessmentMethod:
          type: string
        duration:
          type: string
        performanceCriteria:
          type: string
        evidenceRequired:
          type: string
        deliveryMode:
          type: string
        practicalExercise:
          type: string
        reflection:
          type: string
        notes:
          type: string
        isLocked:
          type: boolean

    # Approval
    Approval:
      type: object
      required: [id, planId, stage, status, createdAt]
      properties:
        id:
          type: integer
        planId:
          type: integer
        stage:
          type: string
          enum: [trainer_review, hod_review, iqa_review, final_approval]
        status:
          type: string
          enum: [pending, approved, rejected, revision_requested]
        approverUserId:
          type: ["string", "null"]
        approverName:
          type: ["string", "null"]
        comments:
          type: ["string", "null"]
        signatureText:
          type: ["string", "null"]
        createdAt:
          type: string

    ApprovalInput:
      type: object
      required: [stage, status]
      properties:
        stage:
          type: string
          enum: [trainer_review, hod_review, iqa_review, final_approval]
        status:
          type: string
          enum: [pending, approved, rejected, revision_requested]
        approverName:
          type: string
        comments:
          type: string
        signatureText:
          type: string

    # Comment
    Comment:
      type: object
      required: [id, planId, content, createdAt]
      properties:
        id:
          type: integer
        planId:
          type: integer
        userId:
          type: ["string", "null"]
        userName:
          type: ["string", "null"]
        content:
          type: string
        sessionRowId:
          type: ["integer", "null"]
        createdAt:
          type: string

    CommentInput:
      type: object
      required: [content]
      properties:
        content:
          type: string
        sessionRowId:
          type: integer
        userName:
          type: string

    # Dashboard
    DashboardStats:
      type: object
      required: [totalPlans, draftPlans, awaitingReview, approvedPlans, rejectedPlans, totalDocuments, totalTrainers]
      properties:
        totalPlans:
          type: integer
        draftPlans:
          type: integer
        awaitingReview:
          type: integer
        approvedPlans:
          type: integer
        rejectedPlans:
          type: integer
        totalDocuments:
          type: integer
        totalTrainers:
          type: integer

    StatusCount:
      type: object
      required: [status, count]
      properties:
        status:
          type: string
        count:
          type: integer
