openapi: 3.1.0
info:
  title: Redleg Forms API
  version: "1.0.0"
  description: |
    PDF generation endpoints for Army administrative forms. Each endpoint
    accepts a JSON payload, validates it against a Zod schema, and returns
    a filled-in PDF as a binary download.

    **No authentication required.** All endpoints are public POST routes.

    Handlers live in `src/app/api/forms/<form>/route.ts`. Zod schemas (the
    source of truth for validation) live in `src/lib/forms/schemas.ts`.
servers:
  - url: https://redleg.app
    description: Production
  - url: http://localhost:3000
    description: Local development

paths:
  /api/forms/da-87:
    post:
      summary: Generate DA Form 87 (Certificate of Training)
      operationId: generateDA87
      description: |
        Fills and returns a DA 87 Certificate of Training PDF for a single
        soldier. Response is a binary PDF with a `Content-Disposition`
        attachment header.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DA87Input"
            example:
              soldierName: "Smith, John J."
              trainingDescription: "Basic Leader Course"
              date: "2026-04-08"
              location: "Fort Liberty, NC"
              instructorName: "CPT Johnson, M."
              instructorTitle: "Course Manager"
      responses:
        "200":
          description: PDF generated successfully
          headers:
            Content-Disposition:
              schema:
                type: string
              description: |
                `attachment; filename="DA87_<soldierName>_<date>.pdf"`
                (spaces in soldierName replaced with underscores)
          content:
            application/pdf:
              schema:
                type: string
                format: binary
        "400":
          $ref: "#/components/responses/ValidationError"
        "500":
          $ref: "#/components/responses/ServerError"

  /api/forms/da-4856:
    post:
      summary: Generate DA Form 4856 (Developmental Counseling Form)
      operationId: generateDA4856
      description: |
        Fills and returns a DA 4856 Developmental Counseling Form PDF.
        Response is a binary PDF with a `Content-Disposition` attachment
        header.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DA4856Input"
            example:
              name: "Smith, John J."
              rank: "SPC"
              date: "2026-04-08"
              organization: "HHC, 1-121 IN"
              counselor: "CPT Johnson, M., S-3"
              purpose: "Monthly performance counseling"
              keyPointsOfDiscussion: "Discussed recent AAR feedback; squad comms need work."
              leadersResponsibilities: "Provide weekly feedback; facilitate SLC attendance."
              planOfAction: "Attend SLC by 30 June 2026; practice active listening daily."
              assessment: "Soldier acknowledged feedback and committed to improvement."
      responses:
        "200":
          description: PDF generated successfully
          headers:
            Content-Disposition:
              schema:
                type: string
              description: |
                `attachment; filename="DA4856_<name>_<date>.pdf"`
                (spaces in name replaced with underscores)
          content:
            application/pdf:
              schema:
                type: string
                format: binary
        "400":
          $ref: "#/components/responses/ValidationError"
        "500":
          $ref: "#/components/responses/ServerError"

  /api/forms/da-4856-2023:
    post:
      summary: Generate DA Form 4856 (MAR 2023 revision)
      operationId: generateDA4856_2023
      description: |
        Fills and returns the current MAR 2023 revision of the DA 4856
        Developmental Counseling Form. Adds explicit `approach` and
        `typeOfCounseling` selectors over the JUL 2014 revision.
        Response is a binary PDF with a `Content-Disposition` attachment header.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DA4856_2023Input"
            example:
              name: "Smith, John J."
              rank: "SPC"
              date: "2026-04-08"
              organization: "HHC, 1-121 IN"
              counselor: "CPT Johnson, M., S-3"
              approach: "directive"
              typeOfCounseling: "performance"
              purpose: "Monthly performance counseling"
              keyPointsOfDiscussion: "Discussed recent AAR feedback; squad comms need work."
              planOfAction: "Attend SLC by 30 June 2026; practice active listening daily."
              individualCounseledAgrees: true
              individualCounseledRemarks: "Acknowledged. Plan is realistic."
              leadersResponsibilities: "Provide weekly feedback; facilitate SLC attendance."
              assessment: "Soldier acknowledged feedback and committed to improvement."
      responses:
        "200":
          description: PDF generated successfully
          headers:
            Content-Disposition:
              schema:
                type: string
              description: |
                `attachment; filename="DA4856-2023_<name>_<date>.pdf"`
                (spaces in name replaced with underscores)
          content:
            application/pdf:
              schema:
                type: string
                format: binary
        "400":
          $ref: "#/components/responses/ValidationError"
        "500":
          $ref: "#/components/responses/ServerError"

components:
  schemas:
    Rank:
      type: string
      description: Valid US Army enlisted, warrant, officer, and OCS ranks (case-sensitive).
      enum:
        - OC
        - CDT
        - PV1
        - PV2
        - PFC
        - SPC
        - CPL
        - SGT
        - SSG
        - SFC
        - MSG
        - 1SG
        - SGM
        - WO1
        - WO2
        - WO3
        - WO4
        - WO5
        - 2LT
        - 1LT
        - CPT
        - MAJ
        - LTC
        - COL

    IsoDate:
      type: string
      pattern: '^\d{4}-\d{2}-\d{2}$'
      description: Date in strict `YYYY-MM-DD` format.
      example: "2026-04-08"

    DA87Input:
      type: object
      required:
        - soldierName
        - trainingDescription
        - date
        - location
        - instructorName
      additionalProperties: false
      properties:
        soldierName:
          type: string
          minLength: 1
          maxLength: 100
          description: Soldier's name, typically "Last, First M.".
        trainingDescription:
          type: string
          minLength: 1
          maxLength: 500
          description: Name/description of the training completed.
        date:
          $ref: "#/components/schemas/IsoDate"
        location:
          type: string
          minLength: 1
          maxLength: 100
          description: Training location (post, installation, or site).
        instructorName:
          type: string
          minLength: 1
          maxLength: 100
          description: Instructor's rank and name.
        instructorTitle:
          type: string
          maxLength: 100
          description: Instructor's title or role (optional).

    DA4856Input:
      type: object
      required:
        - name
        - rank
        - date
        - counselor
        - purpose
        - keyPointsOfDiscussion
        - planOfAction
      additionalProperties: false
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 100
          description: Soldier's name, typically "Last, First M.".
        rank:
          $ref: "#/components/schemas/Rank"
        date:
          $ref: "#/components/schemas/IsoDate"
        organization:
          type: string
          description: Soldier's unit/organization (e.g., "HHC, 1-121 IN"). Optional; leave unset to render a blank Organization field on the printed form.
        counselor:
          type: string
          minLength: 1
          description: Counselor's rank, name, and duty position.
        purpose:
          type: string
          minLength: 1
          description: Purpose of the counseling session.
        keyPointsOfDiscussion:
          type: string
          minLength: 1
          description: Summary of discussion points. Free-form, can be multi-paragraph.
        leadersResponsibilities:
          type: string
          description: Leader's plan of action / responsibilities (optional).
        planOfAction:
          type: string
          minLength: 1
          description: Soldier's plan of action with measurable outcomes.
        assessment:
          type: string
          description: Post-counseling assessment (optional — usually completed later).

    CounselingApproach:
      type: string
      description: Counseling approach used (MAR 2023 revision).
      enum:
        - non-directive
        - combined
        - directive

    CounselingType:
      type: string
      description: Type of counseling (MAR 2023 revision).
      enum:
        - general
        - professional-growth
        - performance
        - event-oriented

    DA4856_2023Input:
      type: object
      required:
        - name
        - rank
        - date
        - counselor
        - approach
        - typeOfCounseling
        - purpose
        - keyPointsOfDiscussion
        - planOfAction
      additionalProperties: false
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 100
          description: Soldier's name, typically "Last, First M.".
        rank:
          $ref: "#/components/schemas/Rank"
        date:
          $ref: "#/components/schemas/IsoDate"
        organization:
          type: string
          description: Soldier's unit/organization (e.g., "HHC, 1-121 IN"). Optional.
        counselor:
          type: string
          minLength: 1
          description: Counselor's rank, name, and duty position.
        approach:
          $ref: "#/components/schemas/CounselingApproach"
        typeOfCounseling:
          $ref: "#/components/schemas/CounselingType"
        purpose:
          type: string
          minLength: 1
          description: Purpose of the counseling session.
        keyPointsOfDiscussion:
          type: string
          minLength: 1
          description: Summary of discussion points. Free-form, can be multi-paragraph.
        planOfAction:
          type: string
          minLength: 1
          description: Soldier's plan of action with measurable outcomes.
        individualCounseledAgrees:
          type: boolean
          description: |
            If set, checks the corresponding "I agree" / "I disagree" box in
            Session Closing. Omit to leave both boxes unchecked (Soldier signs
            on paper).
        individualCounseledRemarks:
          type: string
          description: Soldier's remarks acknowledging the counseling (optional).
        leadersResponsibilities:
          type: string
          description: Leader's plan of action / responsibilities (optional).
        assessment:
          type: string
          description: Post-counseling assessment (optional — usually completed later).

    ValidationError:
      type: object
      required: [error, details]
      properties:
        error:
          type: string
          const: "Validation failed"
        details:
          type: array
          description: Raw Zod issues array. Each entry has `path`, `message`, `code`, and type-specific fields.
          items:
            type: object
            required: [path, message, code]
            properties:
              path:
                type: array
                items:
                  oneOf:
                    - type: string
                    - type: integer
              message:
                type: string
              code:
                type: string
                description: Zod issue code (e.g., `too_small`, `invalid_string`, `invalid_enum_value`).

    ServerError:
      type: object
      required: [error]
      properties:
        error:
          type: string
          example: "Failed to generate PDF"

  responses:
    ValidationError:
      description: Request body failed Zod validation.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ValidationError"
          example:
            error: "Validation failed"
            details:
              - path: ["soldierName"]
                message: "Soldier name is required"
                code: "too_small"

    ServerError:
      description: PDF generation failed on the server.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ServerError"
          example:
            error: "Failed to generate PDF"
