openapi: 3.0.3
info:
  title: EVA Converter API
  version: 1.0.0
  description: API untuk konversi data geospasial ke output engineering DXF, BOQ, HPDB, ASTRI, dan KMZ.
servers:
  - url: /
paths:
  /convert:
    post:
      summary: Upload file dan mulai konversi
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                files:
                  type: array
                  items:
                    type: string
                    format: binary
                file:
                  type: string
                  format: binary
                output_mode:
                  type: string
                  enum: [dxf, boq, astri, hpdb, kmz, dxf_boq, dxf_astri, boq_astri, dxf_boq_astri, dxf_hpdb, boq_hpdb, dxf_boq_hpdb, dxf_kmz, boq_kmz, dxf_boq_kmz, astri_hpdb, dxf_astri_hpdb, boq_astri_hpdb, dxf_boq_astri_hpdb, astri_kmz, dxf_astri_kmz, boq_astri_kmz, dxf_boq_astri_kmz, hpdb_kmz, dxf_hpdb_kmz, boq_hpdb_kmz, dxf_boq_hpdb_kmz, astri_hpdb_kmz, dxf_astri_hpdb_kmz, boq_astri_hpdb_kmz, dxf_boq_astri_hpdb_kmz]
                network_type:
                  type: string
                  enum: [AE, UG]
                kml_folders:
                  type: array
                  items:
                    type: string
                road_clip_boundary:
                  type: boolean
      responses:
        "200":
          description: Job created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/JobCreated"
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "413":
          description: File too large
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
  /upload:
    post:
      summary: Backward-compatible alias untuk /convert
      responses:
        "200":
          description: Job created
  /validate-folders:
    post:
      summary: Validasi folder standar dari file KML/KMZ
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                files:
                  type: array
                  items:
                    type: string
                    format: binary
      responses:
        "200":
          description: Folder validation summary
          content:
            application/json:
              schema:
                type: object
                properties:
                  files:
                    type: array
                    items:
                      type: object
                      properties:
                        filename:
                          type: string
                        folders:
                          type: array
                          items:
                            type: object
                            properties:
                              name:
                                type: string
                              items:
                                type: integer
                        item_count:
                          type: integer
                        warning_count:
                          type: integer
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
  /status/{job_id}:
    get:
      summary: Get job status
      parameters:
        - name: job_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Job status
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/JobStatus"
        "404":
          description: Job not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
  /download/{job_id}:
    get:
      summary: Download conversion result
      parameters:
        - name: job_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: File download
          content:
            application/octet-stream:
              schema:
                type: string
                format: binary
        "409":
          description: Output not ready
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "410":
          description: Output expired or missing
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
  /preview/{job_id}:
    get:
      summary: Get GeoJSON preview
      parameters:
        - name: job_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: GeoJSON preview
  /health:
    get:
      summary: Health check
      responses:
        "200":
          description: Service healthy
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Health"
        "503":
          description: Service degraded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Health"
  /metrics:
    get:
      summary: Application metrics
      responses:
        "200":
          description: Metrics data
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Metrics"
  /docs:
    get:
      summary: Swagger UI
      responses:
        "200":
          description: HTML API documentation
components:
  schemas:
    JobCreated:
      type: object
      properties:
        job_id:
          type: string
        file_count:
          type: integer
    JobStatus:
      type: object
      properties:
        job_id:
          type: string
        status:
          type: string
          enum: [queued, processing, done, error]
        progress:
          type: integer
          minimum: 0
          maximum: 100
        message:
          type: string
        output_mode:
          type: string
        network_type:
          type: string
        logs:
          type: array
          items:
            type: object
        log_counts:
          type: object
        download_url:
          type: string
          nullable: true
        error:
          type: string
          nullable: true
    Health:
      type: object
      properties:
        status:
          type: string
          enum: [ok, degraded]
        timestamp:
          type: number
        version:
          type: string
        redis_connected:
          type: boolean
        upload_dir_writable:
          type: boolean
        output_dir_writable:
          type: boolean
    Metrics:
      type: object
      properties:
        uptime_seconds:
          type: number
        jobs_created:
          type: integer
        jobs_completed:
          type: integer
        jobs_failed:
          type: integer
        jobs_active:
          type: integer
        avg_duration_seconds:
          type: object
          additionalProperties:
            type: number
        total_bytes_uploaded:
          type: integer
    Error:
      type: object
      properties:
        error:
          type: string
