# 横断的関心事: RFC 9457 Problem Details（application/problem+json）
#
# 複数 audience が参照するエラー型を、audience ドキュメントから独立したファイルに置く。
# 「shared」のような寄せ集めフォルダは作らず、関心事の名前（problem）でファイルを分ける。
# audience ドキュメントは $ref でここを参照する（例: ../problem.yaml#/components/schemas/ProblemDetail）。
#
# このファイルは単体で完結する OpenAPI ドキュメントであり、これ自体を入力に
# 独立したコード生成単位（problem パッケージ）を1度だけ生成する。paths は持たず components のみ。
# 各 audience はこのスキーマを schemaMappings で import し、再生成しない（型を1つに収束させる）。
openapi: 3.0.4
info:
  title: Problem Details
  version: 0.0.1
  description: RFC 9457 Problem Details。複数 audience が $ref で参照する横断的関心事。
paths: {}
# --- example の書き方 ---
# 共通レスポンス(responses)には examples(複数例)を必ず付ける。値は実装の
# ProblemTypes(type) と messages.properties(title/detail) に一致させること。
#   type   : ProblemTypes.java の定数値(/problems/xxx)
#   title  : messages.properties の problem.title.* の値
#   detail : messages.properties の error.handler.* の値、または発生箇所固有の説明
# 実際のレスポンスには上記に加えてトレース用の拡張メンバ traceId が付与されるが、
# スキーマ未定義の項目のため example には含めない(ProblemDetail に定義され次第追加する)。
components:
  responses:
    BadRequest:
      description: リクエストボディまたはパスパラメータのパース失敗
      content:
        application/problem+json:
          schema:
            $ref: "#/components/schemas/FieldError"
          examples:
            unreadableBody:
              summary: リクエストボディのパース失敗（不正なJSON・型不一致など）
              value:
                field: requestBody
                message: request body could not be parsed
            invalidParameter:
              summary: パス・クエリパラメータの形式不正
              value:
                field: flightPlanId
                message: "invalid value for parameter 'flightPlanId'"
    NotFound:
      description: 該当リソースが存在しない
      content:
        application/problem+json:
          schema:
            $ref: "#/components/schemas/ProblemDetail"
          examples:
            notFound:
              summary: 指定されたIDのリソースが存在しない
              value:
                type: /problems/not-found
                title: Not Found
                status: 404
                detail: "flight plan not found: id=550e8400-e29b-41d4-a716-446655440000"
                instance: /api/v1/fp/flight-plans/550e8400-e29b-41d4-a716-446655440000
    ValidationError:
      description: バリデーションエラー、または Idempotency-Key を異なるリクエスト内容で再利用した
      content:
        application/problem+json:
          schema:
            anyOf:
              - $ref: "#/components/schemas/ValidationProblemDetail"
              - $ref: "#/components/schemas/ProblemDetail"
          examples:
            validationFailed:
              summary: フィールド単位のバリデーションエラー（`errors`付き = `ValidationProblemDetail`）
              value:
                type: /problems/invalid-input
                title: Unprocessable Entity
                status: 422
                detail: validation failed
                errors:
                  - field: name
                    message: must not be blank
                  - field: flightPeriod.plannedFlightTime
                    message: must be a multiple of 5
            idempotencyKeyConflict:
              summary: 同一の Idempotency-Key を異なるリクエスト内容で再利用した（`errors`なし = `ProblemDetail`）
              value:
                type: /problems/idempotency-key-conflict
                title: Unprocessable Entity
                status: 422
                detail: "Idempotency-Key has already been used with a different request (conflicting identifier: 0f8fad5b-d9cb-469f-a165-70867728950e)"
    LockConflict:
      description: 状態不正またはロックによるリソースアクセス不可による失敗。
      content:
        application/problem+json:
          schema:
            $ref: "#/components/schemas/ProblemDetail"
          examples:
            invalidTransition:
              summary: 現在のステータスからは実行できない操作（状態遷移違反）
              value:
                type: /problems/invalid-transition
                title: Conflict
                status: 409
                detail: "flight plan cannot be activated from status: ENDED"
            # TODO: ロック競合専用の type は ProblemTypes.java に未定義。
            # 専用定数を追加したら、この example の type もそれに合わせて更新すること。
            lockConflict:
              summary: 他の処理が対象リソースをロック中でアクセスできない
              value:
                type: /problems/business-rule-violation
                title: Conflict
                status: 409
                detail: "flight plan is locked by another operation: id=550e8400-e29b-41d4-a716-446655440000"

  schemas:
    # RFC 9457 Problem Details (application/problem+json)
    ProblemDetail:
      type: object
      required: [type, title, status, detail]
      properties:
        type:
          type: string
          format: uri-reference
          description: |
            問題の種別を識別する URI。
            NOTE: 現在は相対パス (/problems/xxx) を使用。本番環境では絶対 URL に変更すること。
          example: /problems/not-found
        title:
          type: string
          description: 問題種別の短い説明（人間向け）
          example: Not Found
        status:
          type: integer
          description: HTTP ステータスコード
          example: 404
        detail:
          type: string
          description: この発生固有の詳細説明（人間向け）
          example: "todo not found: id=99"
        instance:
          type: string
          format: uri-reference
          description: 問題の発生箇所を示す URI（省略可）
          example: /todos/99

    # 422 Validation Error — ProblemDetail + errors 拡張フィールド
    ValidationProblemDetail:
      allOf:
        - $ref: "#/components/schemas/ProblemDetail"
        - type: object
          required: [errors]
          properties:
            errors:
              type: array
              description: フィールドごとのバリデーションエラー一覧
              items:
                $ref: "#/components/schemas/FieldError"

    FieldError:
      type: object
      required: [field, message]
      properties:
        field:
          type: string
          description: バリデーション失敗したフィールド名
          example: title
        message:
          type: string
          description: バリデーションエラーメッセージ
          example: must not be blank
