openapi: 3.1.0
info:
  title: TEK-SA / Kalyon PV — MES-Entegrasyon Servisi Arayüzü
  version: 0.2.0
  description: >
    Blueprint referansı: TEK-SA | Kalyon PV MES ve Otomasyon Entegrasyon
    Blueprint rev 0.2, §4/§5/§6. Bu spesifikasyon Entegrasyon Servisi'nin
    MES ve PLC tarafına sunduğu sözleşmeyi tanımlar. Sürüm 0.2.0 —
    dondurulmadan önce Kalyon MES sağlayıcısıyla mutabakat gerekir
    (Blueprint §12 adım 3).
  contact:
    name: TEK-SA Proje ve Teknoloji

servers:
  - url: http://localhost:4001
    description: Yerel FAT dry-run ortamı
  - url: http://161.97.168.139:8090
    description: Canlı FAT dry-run kanıt ortamı (demo)

tags:
  - name: job-orders
    description: MES'ten Entegrasyon Servisi'ne üretim emri akışı (Blueprint §4.1)
  - name: job-results
    description: PLC'den Entegrasyon Servisi üzerinden MES'e sonuç akışı (Blueprint §4.2)
  - name: gözlemlenebilirlik
    description: Durum, kuyruk ve denetim izi okuma uçları

paths:
  /api/job-orders:
    post:
      tags: [job-orders]
      summary: Üretim emri yayımla (Blueprint §5 adım 1-2)
      description: >
        MES bu uca benzersiz bir txn_id ile üretim emri gönderir. Aynı
        txn_id ikinci kez gelirse (retry/replay) yeni bir işlem AÇILMAZ;
        `duplicate: true` ile 200 döner — idempotent üreticidir.
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/JobOrder' }
      responses:
        '200':
          description: Emir kabul edildi (ilk kez ya da mükerrer olarak tanındı)
          content:
            application/json:
              schema: { $ref: '#/components/schemas/JobOrderAccepted' }
        '400':
          description: Şema doğrulaması başarısız — emir reddedildi, denetim izine yazıldı
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ValidationError' }

  /api/job-results:
    post:
      tags: [job-results]
      summary: PLC üretim sonucu bildirir (Blueprint §5 adım 6-7)
      description: >
        PLC/hat kontrolü çevrim tamamlandığında sonucu bu uca gönderir.
        Entegrasyon Servisi sonucu MES'e göndermeden önce kalıcı kuyruğa
        (outbox) yazar — bu yazma ile durum güncellemesi TEK bir veritabanı
        işleminde gerçekleşir (Blueprint §6.1: "sonuç, gönderimden önce
        kalıcı yerel kuyruğa yazılır").
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/JobResult' }
      responses:
        '200':
          description: Sonuç kabul edildi ve kalıcı kuyruğa alındı
          content:
            application/json:
              schema: { $ref: '#/components/schemas/JobResultAccepted' }
        '404':
          description: Bilinmeyen txn_id — bu ID için önceden bir JobOrder alınmamış
        '400':
          description: Şema doğrulaması başarısız

  /api/transactions/{txnId}:
    get:
      tags: [gözlemlenebilirlik]
      summary: İşlem durumunu oku
      parameters:
        - name: txnId
          in: path
          required: true
          schema: { type: string }
      responses:
        '200':
          description: İşlem bulundu
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Transaction' }
        '404':
          description: İşlem bulunamadı

  /api/audit:
    get:
      tags: [gözlemlenebilirlik]
      summary: Hash-zincirli denetim izini ve zincir bütünlüğünü döndür
      responses:
        '200':
          description: Denetim kaydı ve zincir doğrulama sonucu
          content:
            application/json:
              schema: { $ref: '#/components/schemas/AuditResponse' }

components:
  schemas:
    JobOrder:
      type: object
      required: [txn_id, work_order_id, product_code, serial_no, route, issued_at]
      properties:
        txn_id:
          type: string
          description: Uçtan uca değişmeyen işlem kimliği. Retry'larda AYNI kalır.
          example: "TX-97711cfa-4b91-4b72-8bb2-1c1e9fce9a21"
        work_order_id: { type: string, example: "WO-2026-0917-042" }
        product_code: { type: string, example: "PV-MODULE-TOPCON-108" }
        serial_no:
          type: string
          description: IEC 61215-1 gereği modülde benzersiz olmak zorunda olan seri numarası.
          example: "KLY-26-0917-0184"
        route: { type: string, example: "PACK-LINE-1" }
        issued_at: { type: string, format: date-time }

    JobOrderAccepted:
      type: object
      required: [accepted, txn_id, duplicate]
      properties:
        accepted: { type: boolean, const: true }
        txn_id: { type: string }
        duplicate:
          type: boolean
          description: true ise bu txn_id daha önce işlenmişti, yeni kayıt açılmadı.

    JobResult:
      type: object
      required: [txn_id, work_order_id, serial_no, result, cycle_time_ms, station, produced_at]
      properties:
        txn_id: { type: string }
        work_order_id: { type: string }
        serial_no: { type: string }
        result: { type: string, enum: [OK, NOK] }
        cycle_time_ms: { type: integer, minimum: 0 }
        alarm_code: { type: [string, "null"] }
        station: { type: string, example: "PACK-01" }
        produced_at: { type: string, format: date-time }

    JobResultAccepted:
      type: object
      required: [accepted, txn_id, duplicate]
      properties:
        accepted: { type: boolean, const: true }
        txn_id: { type: string }
        duplicate: { type: boolean }

    Transaction:
      type: object
      properties:
        txn_id: { type: string }
        work_order_id: { type: string }
        serial_no: { type: string }
        status:
          type: string
          enum: [RECEIVED, SENT_TO_PLC, RESULT_QUEUED, SENDING_TO_MES, RESULT_BUFFERED, CLOSED]
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }

    AckResponse:
      type: object
      required: [ack, txn_id, duplicate, mes_record_id]
      description: MES'in Entegrasyon Servisi'ne verdiği alındı onayı (Blueprint §5 adım 8).
      properties:
        ack: { type: boolean, const: true }
        txn_id: { type: string }
        duplicate:
          type: boolean
          description: >
            true ise MES bu txn_id'yi daha önce işlemişti; REJECTED değil,
            mevcut mes_record_id ile ACK döner (Blueprint §6.2).
        mes_record_id: { type: string }

    AuditResponse:
      type: object
      properties:
        chain:
          type: object
          properties:
            valid: { type: boolean }
            brokenAtSeq: { type: [integer, "null"] }
        entries:
          type: array
          items:
            type: object
            properties:
              seq: { type: integer }
              ts: { type: string, format: date-time }
              service: { type: string }
              event_type: { type: string }
              txn_id: { type: [string, "null"] }
              prev_hash: { type: string }
              hash: { type: string }

    ValidationError:
      type: object
      properties:
        error: { type: string }
        details: { type: object }
