{
  "openapi": "3.1.0",
  "info": {
    "title": "Parky API (Owner Portal)",
    "version": "0.1.0",
    "description": "Parky API — オーナーポータル (dev-owner.parky.co.jp) が叩くエンドポイント。オーナー認証で保護。"
  },
  "servers": [
    {
      "url": "https://api.parky.co.jp",
      "description": "Production"
    },
    {
      "url": "https://stg-api.parky.co.jp",
      "description": "Staging"
    },
    {
      "url": "https://dev-api.parky.co.jp",
      "description": "Development"
    },
    {
      "url": "http://localhost:8787",
      "description": "Local"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "Supabase Auth が発行した JWT（HS256 / SUPABASE_JWT_SECRET 署名）"
      }
    },
    "schemas": {
      "AppleAppSiteAssociation": {
        "type": "object",
        "properties": {
          "applinks": {
            "type": "object",
            "properties": {
              "details": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "appIDs": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "components": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "/": {
                            "type": "string"
                          },
                          "comment": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "/"
                        ]
                      }
                    }
                  },
                  "required": [
                    "appIDs",
                    "components"
                  ]
                }
              }
            },
            "required": [
              "details"
            ]
          },
          "webcredentials": {
            "type": "object",
            "properties": {
              "apps": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            },
            "required": [
              "apps"
            ]
          }
        },
        "required": [
          "applinks",
          "webcredentials"
        ]
      },
      "AssetLinksEntry": {
        "type": "object",
        "properties": {
          "relation": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "target": {
            "type": "object",
            "properties": {
              "namespace": {
                "type": "string"
              },
              "package_name": {
                "type": "string"
              },
              "sha256_cert_fingerprints": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            },
            "required": [
              "namespace",
              "package_name",
              "sha256_cert_fingerprints"
            ]
          }
        },
        "required": [
          "relation",
          "target"
        ]
      },
      "AssetLinksResponse": {
        "type": "array",
        "items": {
          "$ref": "#/components/schemas/AssetLinksEntry"
        }
      },
      "OwnerFeatureFlags": {
        "type": "object",
        "properties": {
          "owner_monetization_enabled": {
            "type": "boolean"
          }
        },
        "required": [
          "owner_monetization_enabled"
        ]
      },
      "OwnerMe": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "owner_type": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "phone": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string"
          },
          "company_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "representative_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "string"
          },
          "updated_at": {
            "type": "string"
          },
          "feature_flags": {
            "$ref": "#/components/schemas/OwnerFeatureFlags"
          }
        },
        "required": [
          "id",
          "owner_type",
          "name",
          "email",
          "phone",
          "status",
          "company_name",
          "representative_name",
          "created_at",
          "updated_at",
          "feature_flags"
        ]
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string",
                "examples": [
                  "not_found"
                ]
              },
              "message": {
                "type": "string",
                "examples": [
                  "Not Found"
                ]
              },
              "message_key": {
                "type": "string",
                "examples": [
                  "common.error.not_found"
                ]
              },
              "request_id": {
                "type": "string",
                "examples": [
                  "7d4e5…-…"
                ]
              },
              "param": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "リクエスト上のエラー対象フィールド名（zod path[0] 等）。root レベルエラーは null。",
                "examples": [
                  "email"
                ]
              },
              "doc_url": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "エラーコードに対応するドキュメント URL。未整備時は null。",
                "examples": [
                  null
                ]
              }
            },
            "required": [
              "code",
              "message",
              "request_id"
            ]
          }
        },
        "required": [
          "error"
        ]
      },
      "OwnerParkingLot": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "address": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": [
              "string",
              "null"
            ]
          },
          "total_spaces": {
            "type": [
              "integer",
              "null"
            ]
          },
          "structure": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "name",
          "address",
          "status",
          "total_spaces",
          "structure",
          "created_at"
        ]
      },
      "OwnerParkingLotRow": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "address": {
            "type": [
              "string",
              "null"
            ]
          },
          "lat": {
            "type": [
              "number",
              "null"
            ]
          },
          "lng": {
            "type": [
              "number",
              "null"
            ]
          },
          "status": {
            "type": [
              "string",
              "null"
            ]
          },
          "total_spaces": {
            "type": [
              "integer",
              "null"
            ]
          },
          "structure": {
            "type": [
              "string",
              "null"
            ]
          },
          "entry_method": {
            "type": [
              "string",
              "null"
            ]
          },
          "source": {
            "type": [
              "string",
              "null"
            ]
          },
          "max_height_m": {
            "type": [
              "number",
              "null"
            ]
          },
          "max_width_m": {
            "type": [
              "number",
              "null"
            ]
          },
          "max_length_m": {
            "type": [
              "number",
              "null"
            ]
          },
          "max_weight_t": {
            "type": [
              "number",
              "null"
            ]
          },
          "min_clearance_cm": {
            "type": [
              "integer",
              "null"
            ]
          },
          "operator_code": {
            "type": [
              "string",
              "null"
            ]
          },
          "entry_difficulty": {
            "type": [
              "string",
              "null"
            ]
          },
          "shape_type": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "name",
          "address",
          "lat",
          "lng",
          "status",
          "total_spaces",
          "structure",
          "created_at"
        ]
      },
      "OwnerSearchParkingLot": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "address": {
            "type": [
              "string",
              "null"
            ]
          },
          "lat": {
            "type": [
              "number",
              "null"
            ]
          },
          "lng": {
            "type": [
              "number",
              "null"
            ]
          },
          "has_owner": {
            "type": "boolean"
          }
        },
        "required": [
          "id",
          "name",
          "address",
          "lat",
          "lng",
          "has_owner"
        ]
      },
      "GeometryPoint": {
        "type": "object",
        "properties": {
          "lat": {
            "type": "number",
            "minimum": -90,
            "maximum": 90,
            "description": "緯度（WGS84, 10進）。",
            "examples": [
              35.669277
            ]
          },
          "lng": {
            "type": "number",
            "minimum": -180,
            "maximum": 180,
            "description": "経度（WGS84, 10進）。",
            "examples": [
              139.758991
            ]
          }
        },
        "required": [
          "lat",
          "lng"
        ],
        "additionalProperties": false
      },
      "GeoJSONLineString": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "LineString"
            ]
          },
          "coordinates": {
            "type": "array",
            "items": {
              "type": "array",
              "prefixItems": [
                {
                  "type": "number",
                  "minimum": -180,
                  "maximum": 180
                },
                {
                  "type": "number",
                  "minimum": -90,
                  "maximum": 90
                }
              ],
              "description": "[lng, lat] のペア（GeoJSON 仕様、経度が先）",
              "examples": [
                [
                  139.758991,
                  35.669277
                ]
              ]
            },
            "minItems": 2,
            "description": "2 点以上の座標列。",
            "examples": [
              [
                [
                  139.758,
                  35.669
                ],
                [
                  139.759,
                  35.67
                ]
              ]
            ]
          }
        },
        "required": [
          "type",
          "coordinates"
        ],
        "additionalProperties": false
      },
      "GeoJSONPolygon": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "Polygon"
            ]
          },
          "coordinates": {
            "type": "array",
            "items": {
              "type": "array",
              "items": {
                "type": "array",
                "prefixItems": [
                  {
                    "type": "number",
                    "minimum": -180,
                    "maximum": 180
                  },
                  {
                    "type": "number",
                    "minimum": -90,
                    "maximum": 90
                  }
                ],
                "description": "[lng, lat] のペア（GeoJSON 仕様、経度が先）",
                "examples": [
                  [
                    139.758991,
                    35.669277
                  ]
                ]
              },
              "minItems": 4
            },
            "minItems": 1,
            "description": "外周 + 内周（穴）の配列。各リングは最低 4 点、最後の点は最初の点と一致すること（閉じたリング）。",
            "examples": [
              [
                [
                  [
                    139.758,
                    35.669
                  ],
                  [
                    139.759,
                    35.669
                  ],
                  [
                    139.759,
                    35.67
                  ],
                  [
                    139.758,
                    35.67
                  ],
                  [
                    139.758,
                    35.669
                  ]
                ]
              ]
            ]
          }
        },
        "required": [
          "type",
          "coordinates"
        ],
        "additionalProperties": false
      },
      "ParkingLotGeometry": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "shape_type": {
                "type": "string",
                "enum": [
                  "point"
                ]
              },
              "point": {
                "$ref": "#/components/schemas/GeometryPoint"
              }
            },
            "required": [
              "shape_type",
              "point"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "shape_type": {
                "type": "string",
                "enum": [
                  "line"
                ]
              },
              "line": {
                "$ref": "#/components/schemas/GeoJSONLineString"
              }
            },
            "required": [
              "shape_type",
              "line"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "shape_type": {
                "type": "string",
                "enum": [
                  "area"
                ]
              },
              "area": {
                "$ref": "#/components/schemas/GeoJSONPolygon"
              }
            },
            "required": [
              "shape_type",
              "area"
            ],
            "additionalProperties": false
          },
          {
            "type": "null"
          }
        ],
        "description": "駐車場の座標 / 形状（shape_type + 座標）。座標未設定の場合は `null`。flat の lat/lng/shape_type/area は返さない（すべてこの nested object に集約）。"
      },
      "ParkingLotResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "作成 or 更新された駐車場 UUID",
            "examples": [
              "00000000-0000-0000-0000-000000000000"
            ]
          },
          "name": {
            "type": "string",
            "description": "駐車場の表示名"
          },
          "address": {
            "type": [
              "string",
              "null"
            ],
            "description": "住所全文。未設定なら null。"
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "pending",
              "active",
              "on_hold",
              "withdrawn",
              "rejected"
            ],
            "description": "公開状態。owner POST 経由は常に `pending`、admin は body 指定値。",
            "examples": [
              "active"
            ]
          },
          "source": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "manual",
              "s-park",
              "times",
              "repark",
              "navipark",
              "p-colle"
            ],
            "description": "データ起源（manual / s-park / times / ...）。codes.category_id=`lot_source`。",
            "examples": [
              "manual"
            ]
          },
          "parent_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "親駐車場 UUID（ブランド系列の名寄せ用）。通常 null。",
            "examples": [
              "00000000-0000-0000-0000-000000000000"
            ]
          },
          "variant_label": {
            "type": [
              "string",
              "null"
            ],
            "description": "同一系列内の区別ラベル（「第1」「第2」「裏口」等）。"
          },
          "place_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Google Place ID（archive/032）。Pコレ取り込みの冪等キー。"
          },
          "total_spaces": {
            "type": [
              "integer",
              "null"
            ],
            "description": "駐車可能台数。非負整数 or null。"
          },
          "structure": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "flat",
              "self_multi",
              "mechanical"
            ],
            "description": "駐車場構造（codes.category_id=`lot_structure`）。",
            "examples": [
              "mechanical"
            ]
          },
          "entry_method": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "self",
              "mechanical"
            ],
            "description": "入庫方式（codes.category_id=`lot_entry`）。",
            "examples": [
              "mechanical"
            ]
          },
          "entry_difficulty": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "easy",
              "normal",
              "hard"
            ],
            "description": "入庫難易度（codes.category_id=`entry_difficulty`）。",
            "examples": [
              "easy"
            ]
          },
          "max_height_m": {
            "type": [
              "number",
              "null"
            ],
            "description": "車高制限(m)。"
          },
          "max_width_m": {
            "type": [
              "number",
              "null"
            ],
            "description": "車幅制限(m)。"
          },
          "max_length_m": {
            "type": [
              "number",
              "null"
            ],
            "description": "全長制限(m)。"
          },
          "max_weight_t": {
            "type": [
              "number",
              "null"
            ],
            "description": "重量制限(t)。"
          },
          "min_clearance_cm": {
            "type": [
              "integer",
              "null"
            ],
            "description": "最低地上高(cm)。"
          },
          "max_tire_width_mm": {
            "type": [
              "integer",
              "null"
            ],
            "description": "タイヤ幅制限(mm)。null = 制限なし。archive/041。"
          },
          "max_parking_duration_min": {
            "type": [
              "integer",
              "null"
            ],
            "description": "最大駐車時間(分)。archive/015。"
          },
          "receipt_available": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "領収書発行可否。DEFAULT `false`。"
          },
          "operator_code": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "paraca",
              "times",
              "repark",
              "navipark",
              "mitsui",
              "npc24h",
              "ecoloparc",
              "coinpark",
              "other"
            ],
            "description": "運営会社コード（codes.category_id=`operator`）。",
            "examples": [
              "repark"
            ]
          },
          "raw_text": {
            "type": [
              "string",
              "null"
            ],
            "description": "取り込み元の生テキスト（CSV / スクレイピング原文）。通常 null。"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "作成日時（UTC, ISO 8601）。",
            "examples": [
              "2026-04-17T12:00:00Z"
            ]
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "最終更新日時（UTC, ISO 8601）。20260421150000 trigger で自動更新。",
            "examples": [
              "2026-04-17T12:00:00Z"
            ]
          },
          "geometry": {
            "$ref": "#/components/schemas/ParkingLotGeometry"
          }
        },
        "required": [
          "id",
          "name",
          "address",
          "status",
          "source",
          "parent_id",
          "variant_label",
          "place_id",
          "total_spaces",
          "structure",
          "entry_method",
          "entry_difficulty",
          "max_height_m",
          "max_width_m",
          "max_length_m",
          "max_weight_t",
          "min_clearance_cm",
          "max_tire_width_mm",
          "max_parking_duration_min",
          "receipt_available",
          "operator_code",
          "raw_text",
          "created_at",
          "updated_at",
          "geometry"
        ],
        "additionalProperties": false,
        "description": "fetchLot() が返す parking_lots 行の全列（座標/形状は `geometry` nest に集約）。passthrough は使わず全カラムを明示する。"
      },
      "ParkingLotBundleResponse": {
        "type": "object",
        "properties": {
          "parking_lot": {
            "$ref": "#/components/schemas/ParkingLotResponse"
          },
          "hours_count": {
            "type": "integer",
            "description": "parking_lot_hours に INSERT した行数。bundle body に hours を含めない場合は 0。",
            "examples": [
              1
            ]
          },
          "pricing_rules_count": {
            "type": "integer",
            "description": "parking_lot_pricing_rules に INSERT した行数。",
            "examples": [
              2
            ]
          },
          "images_count": {
            "type": "integer",
            "description": "parking_lot_images に INSERT（create 時）/ 差分適用（update 時）した件数。",
            "examples": [
              2
            ]
          },
          "tags_count": {
            "type": "integer",
            "description": "parking_lot_tags に UPSERT した件数（state=null の DELETE も含む）。",
            "examples": [
              3
            ]
          },
          "owners_count": {
            "type": "integer",
            "description": "parking_lot_owners に INSERT した件数。admin 版は body.owner_ids の長さ、owner セルフ登録版は常に 1（自動紐付け）。",
            "examples": [
              1
            ]
          }
        },
        "required": [
          "parking_lot",
          "hours_count",
          "pricing_rules_count",
          "images_count",
          "tags_count",
          "owners_count"
        ]
      },
      "EntryExitPin": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "entry",
              "exit",
              "both"
            ],
            "description": "ピン種別。`entry`=入口 / `exit`=出口 / `both`=入出口兼用。",
            "examples": [
              "both"
            ]
          },
          "lat": {
            "type": "number",
            "description": "緯度。",
            "examples": [
              35.6587
            ]
          },
          "lng": {
            "type": "number",
            "description": "経度。",
            "examples": [
              139.7454
            ]
          },
          "label": {
            "type": "string",
            "maxLength": 50,
            "description": "ピンのラベル（「北側ゲート」等）。省略可。",
            "examples": [
              "北側ゲート"
            ]
          }
        },
        "required": [
          "kind",
          "lat",
          "lng"
        ],
        "additionalProperties": false
      },
      "EntryExitLocations": {
        "type": [
          "object",
          "null"
        ],
        "properties": {
          "mode": {
            "type": "string",
            "enum": [
              "shared",
              "separate",
              "multiple"
            ],
            "description": "出入口モード。\n- `shared`   : 入出口が同一（1 か所兼用）\n- `separate` : 入口と出口が別（各 1 か所）\n- `multiple` : 複数出入口あり（pins に個別記録）",
            "examples": [
              "shared"
            ]
          },
          "pins": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EntryExitPin"
            },
            "maxItems": 20,
            "description": "出入口ピン一覧。`mode` に応じた件数を格納する。最大 20 件。"
          }
        },
        "required": [
          "mode",
          "pins"
        ],
        "additionalProperties": false,
        "description": "出入口位置情報（jsonb）。parking_field_values.field_name='entry_exit_locations' に保存。"
      },
      "OwnerParkingLotCoreCreate": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "駐車場の表示名（必須）。系列名＋地名の形式が多い。",
            "examples": [
              "晴海西口第一駐車場"
            ]
          },
          "address": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 500,
            "description": "住所全文。都道府県 + 市区 + 町丁目 + 番地。公開検索の ILIKE 対象。",
            "examples": [
              "東京都中央区晴海20-39"
            ]
          },
          "lot_type": {
            "type": "string",
            "enum": [
              "regular",
              "meter",
              "ticket",
              "monthly_only",
              "hourly_with_monthly",
              "prepaid_coin"
            ],
            "description": "駐車場種別 (default `regular`)。`meter` / `ticket` を選んだ場合は wizard が物理制限・spots step をスキップする (§17)。",
            "examples": [
              "regular"
            ]
          },
          "vehicle_type_max": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 50,
            "description": "lot レベル default の最大車種 (codes.category_id=`vehicle_type`)。spot レベルで上書き可能。NULL = 未設定。",
            "examples": [
              "minivan"
            ]
          },
          "parent_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "親駐車場 UUID（ブランド系列の名寄せ用）。通常 null。",
            "examples": [
              "00000000-0000-0000-0000-000000000000"
            ]
          },
          "variant_label": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 200,
            "description": "同一系列内の区別ラベル（「第1」「第2」「裏口」等）。",
            "examples": [
              "第1"
            ]
          },
          "total_spaces": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "駐車可能台数。非負整数。",
            "examples": [
              12
            ]
          },
          "structure": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "flat",
              "self_multi",
              "mechanical"
            ],
            "description": "駐車場構造（codes.category_id=`lot_structure`）。\n- `flat`       : 平置き（屋根なし / 青空）\n- `self_multi` : 自走式立体（自走で各階へ）\n- `mechanical` : 機械式立体（パレット入れ替え）",
            "examples": [
              "mechanical"
            ]
          },
          "entry_method": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "self",
              "mechanical"
            ],
            "description": "入庫方式（codes.category_id=`lot_entry`）。\n- `self`       : 自走式（自分で停める）\n- `mechanical` : 機械式（パレットに車を載せる）\n`structure=mechanical` なら通常 `entry_method=mechanical`、\n`structure=flat`/`self_multi` なら `entry_method=self` が一般的。",
            "examples": [
              "mechanical"
            ]
          },
          "entry_difficulty": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "easy",
              "normal",
              "hard"
            ],
            "description": "入庫難易度（codes.category_id=`entry_difficulty`）。\n- `easy`   : 簡単\n- `normal` : 普通\n- `hard`   : 難しい",
            "examples": [
              "easy"
            ]
          },
          "max_height_m": {
            "type": [
              "number",
              "null"
            ],
            "description": "車高制限(m)。機械式は 1.55/2.10、自走式は 2.10/2.50 が典型。",
            "examples": [
              1.55
            ]
          },
          "max_width_m": {
            "type": [
              "number",
              "null"
            ],
            "description": "車幅制限(m)。1.85 / 1.95 が典型。",
            "examples": [
              1.95
            ]
          },
          "max_length_m": {
            "type": [
              "number",
              "null"
            ],
            "description": "全長制限(m)。5.00 / 5.30 が典型。",
            "examples": [
              5.3
            ]
          },
          "max_weight_t": {
            "type": [
              "number",
              "null"
            ],
            "description": "重量制限(t)。2.0 / 2.5 が典型。",
            "examples": [
              2.5
            ]
          },
          "min_clearance_cm": {
            "type": [
              "integer",
              "null"
            ],
            "description": "最低地上高(cm)。機械式で特に重要。",
            "examples": [
              10
            ]
          },
          "max_tire_width_mm": {
            "type": [
              "integer",
              "null"
            ],
            "description": "タイヤ幅制限(mm)。機械式で設定されることが多い。null = 制限なし（検索では合致扱い）。archive/041 で追加。",
            "examples": [
              205
            ]
          },
          "max_parking_duration_min": {
            "type": [
              "integer",
              "null"
            ],
            "description": "最大駐車時間(分)。短時間のみ等の制限がある場合のみ設定。archive/015 で追加。例: `180` = 3 時間。",
            "examples": [
              180
            ]
          },
          "receipt_available": {
            "type": "boolean",
            "description": "領収書発行可否。DEFAULT `false`。",
            "examples": [
              true
            ]
          },
          "operator_code": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "paraca",
              "times",
              "repark",
              "navipark",
              "mitsui",
              "npc24h",
              "ecoloparc",
              "coinpark",
              "other"
            ],
            "description": "運営会社コード（codes.category_id=`operator`）。\n- `paraca`    : パラカ\n- `times`     : タイムズ24\n- `repark`    : リパーク（三井のリパーク系列）\n- `navipark`  : ナビパーク\n- `mitsui`    : 三井のリパーク（本体）\n- `npc24h`    : NPC24H\n- `ecoloparc` : エコロパーク\n- `coinpark`  : コインパーク\n- `other`     : その他（分類不能 / 個人オーナー等）\n\nowner 自営の駐車場で運営会社が無い場合は `null` で OK。\n新規運営会社は codes マスター追加と schema enum 追記の 2 step で拡張する。",
            "examples": [
              "repark"
            ]
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 2000,
            "description": "駐車場の説明文（オーナーが自由記述）。UI の詳細ページに表示される。",
            "examples": [
              "駅から徒歩3分の好立地。夜間入庫可能。"
            ]
          },
          "pricing_notes": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 1000,
            "description": "料金に関する補足・備考（フリーテキスト）。特典・キャンペーン等の記述に使用。",
            "examples": [
              "月極契約は別途お問い合わせください。"
            ]
          },
          "contact_phone": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 50,
            "description": "問い合わせ電話番号。parking_field_values.field_name='contact_phone' に保存。",
            "examples": [
              "03-1234-5678"
            ]
          },
          "contact_email": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 200,
            "format": "email",
            "description": "問い合わせメールアドレス。parking_field_values.field_name='contact_email' に保存。",
            "examples": [
              "parking@example.com"
            ]
          },
          "contact_url": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 500,
            "format": "uri",
            "description": "問い合わせ / 予約ページ URL。parking_field_values.field_name='contact_url' に保存。",
            "examples": [
              "https://example.com/parking"
            ]
          },
          "capacity_kei": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "軽自動車スペース台数。parking_field_values.field_name='capacity_kei' に保存。",
            "examples": [
              4
            ]
          },
          "capacity_regular": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "普通車スペース台数。parking_field_values.field_name='capacity_regular' に保存。",
            "examples": [
              20
            ]
          },
          "capacity_oversized": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "大型車スペース台数。parking_field_values.field_name='capacity_oversized' に保存。",
            "examples": [
              3
            ]
          },
          "capacity_motorcycle": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "二輪車スペース台数。parking_field_values.field_name='capacity_motorcycle' に保存。",
            "examples": [
              5
            ]
          },
          "capacity_ev": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "EV充電スペース台数。parking_field_values.field_name='capacity_ev' に保存。",
            "examples": [
              2
            ]
          },
          "capacity_disabled": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "障害者スペース台数。parking_field_values.field_name='capacity_disabled' に保存。",
            "examples": [
              2
            ]
          },
          "entry_exit_locations": {
            "$ref": "#/components/schemas/EntryExitLocations"
          },
          "geometry": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ParkingLotGeometry"
              },
              {
                "description": "駐車場の座標 / 形状（shape_type と座標をペアで持つ nested object）。Create では省略時 `null`（座標未設定）。Patch では省略=触らない、`null`=座標クリア、object 指定で置換。"
              }
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "pending"
            ],
            "description": "Owner Bundle が受領する status (Phase A / 2026-04-29)。\n- `draft`   : 下書き保存 (admin 通知なし、検索除外)\n- `pending` : 申請 (admin 審査キューに投入、従来挙動)\n省略時は server 側で `pending` を default として投入。\n`active` / `on_hold` / `withdrawn` / `rejected` は admin 系 API で遷移。",
            "examples": [
              "draft"
            ]
          }
        },
        "required": [
          "name"
        ],
        "additionalProperties": false
      },
      "ParkingLotHourInput": {
        "type": "object",
        "properties": {
          "window_type": {
            "type": "string",
            "enum": [
              "business",
              "entry",
              "exit",
              "after_hours_exit"
            ],
            "description": "時間窓の種別。省略時は `business`（DB DEFAULT と同じ）。2026-04-24 追加カラム。",
            "examples": [
              "business"
            ]
          },
          "day_type": {
            "type": "string",
            "enum": [
              "all",
              "weekday",
              "saturday",
              "sunday",
              "holiday",
              "holiday_eve"
            ],
            "description": "曜日タイプ（parking_lot_hours / parking_lot_pricing_rules 共通）。\ncodes(day_type) 参照。2026-04-24 で 6 コードに整理された。\n- `all`         : 全曜日共通（DEFAULT）\n- `weekday`     : 平日（月〜金）\n- `saturday`    : 土曜\n- `sunday`      : 日曜\n- `holiday`     : 祝日（jp_holidays 参照）\n- `holiday_eve` : 祝前日\n`day_of_week` (0=日〜6=土) と併用して曜日単位の細かい設定も可能。",
            "examples": [
              "all"
            ]
          },
          "day_of_week": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "maximum": 6,
            "description": "曜日インデックス（0=日曜 / 1=月 / 2=火 / 3=水 / 4=木 / 5=金 / 6=土）。\nnull = 毎日（`day_type='all'` と同義）。\n`day_type='weekday'` + `day_of_week=1` のように併用して「月曜だけの特別時間」を表現も可。",
            "examples": [
              1
            ]
          },
          "is_24h": {
            "type": "boolean",
            "description": "24時間営業フラグ。true の場合 open_time/close_time は無視される。",
            "examples": [
              true
            ]
          },
          "is_closed": {
            "type": "boolean",
            "description": "定休フラグ。true の場合 終日 closed として扱う（open_time/close_time/is_24h より優先）。",
            "examples": [
              false
            ]
          },
          "open_time": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^([01]\\d|2[0-4]):[0-5]\\d$",
            "description": "開場時刻 `HH:MM`（24時間制）。`is_24h=true` / `is_closed=true` の場合は null。",
            "examples": [
              "07:00"
            ]
          },
          "close_time": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^([01]\\d|2[0-4]):[0-5]\\d$",
            "description": "閉場時刻 `HH:MM`。`24:00` 表記を許容（RPC が 24:00:00 = 翌日 0 時として解釈）。深夜跨ぎは `22:00` → `06:00` のような逆転値で表現（`open_time > close_time` を許容）。",
            "examples": [
              "23:00"
            ]
          },
          "effective_from": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
            "description": "適用開始日（ISO 8601 date `YYYY-MM-DD`）。null = 常時。季節料金 / 期間限定営業時間に使用。",
            "examples": [
              "2026-04-01"
            ]
          },
          "effective_to": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
            "description": "適用終了日（ISO 8601 date）。null = 常時。",
            "examples": [
              "2026-09-30"
            ]
          }
        },
        "additionalProperties": false
      },
      "ParkingLotPricingRuleInput": {
        "type": "object",
        "properties": {
          "rule_order": {
            "type": "integer",
            "minimum": 0,
            "description": "表示順・評価順（昇順）。省略時はリクエスト配列のインデックス（0 はじまり）が採用される。同一 lot 内で重複しないこと。",
            "examples": [
              1
            ]
          },
          "category": {
            "type": "string",
            "enum": [
              "unit",
              "cap",
              "hourly"
            ],
            "description": "料金ルール種別。\n- `unit`   : 従量（時間単位で課金。`per_minutes` + `price_minor` で表現。例: 30分 200円）\n- `cap`    : 最大料金 / 打止め（`cap_type` + `cap_duration_hours` + `cap_price_minor` で表現。例: 24時間最大 1800円）\n- `hourly` : 集計用の代表時間単価（内部 MV 用途。UI 編集での利用は稀）",
            "examples": [
              "unit"
            ]
          },
          "day_type": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "all",
              "weekday",
              "saturday",
              "sunday",
              "holiday",
              "holiday_eve"
            ],
            "description": "曜日タイプ（parking_lot_hours / parking_lot_pricing_rules 共通）。\ncodes(day_type) 参照。2026-04-24 で 6 コードに整理された。\n- `all`         : 全曜日共通（DEFAULT）\n- `weekday`     : 平日（月〜金）\n- `saturday`    : 土曜\n- `sunday`      : 日曜\n- `holiday`     : 祝日（jp_holidays 参照）\n- `holiday_eve` : 祝前日\n`day_of_week` (0=日〜6=土) と併用して曜日単位の細かい設定も可能。",
            "examples": [
              "all"
            ]
          },
          "time_start": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^([01]\\d|2[0-4]):[0-5]\\d$",
            "description": "適用開始時刻 `HH:MM`（`category=unit` で使用）。深夜跨ぎ可（例: `22:00` → `08:00` の逆転値）。",
            "examples": [
              "08:00"
            ]
          },
          "time_end": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^([01]\\d|2[0-4]):[0-5]\\d$",
            "description": "適用終了時刻 `HH:MM`。",
            "examples": [
              "22:00"
            ]
          },
          "per_minutes": {
            "type": [
              "integer",
              "null"
            ],
            "exclusiveMinimum": 0,
            "description": "課金単位（分）。`category=unit` で使用。典型値: 15 / 20 / 30 / 60。`per_minutes=30` + `price_minor=200` で「30分ごとに 200 円」。",
            "examples": [
              30
            ]
          },
          "price_minor": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "課金単価（JPY 最小単位 = 1 円）。`category=unit` で使用。例: `200` = 200 円。`_minor` 命名は 20260421110000_money_columns_minor_rename.sql で統一済み（bigint, 非負整数）。",
            "examples": [
              200
            ]
          },
          "cap_type": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "daily_max",
              "hour_window_max",
              "duration",
              "daily"
            ],
            "description": "最大料金の適用種別（`category=cap` の時のみ使用）。\n- `daily_max`       : 当日中の最大料金 (新規データはこれを推奨)\n- `hour_window_max` : 指定時間窓内の最大料金。`cap_duration_hours` と組み合わせる\n- `duration`        : (legacy) 指定時間内定額。新規は `hour_window_max` を使用\n- `daily`           : (legacy) 当日中定額。新規は `daily_max` を使用",
            "examples": [
              "daily_max"
            ]
          },
          "cap_duration_hours": {
            "type": [
              "integer",
              "null"
            ],
            "exclusiveMinimum": 0,
            "description": "最大料金の時間窓（`category=cap` + `cap_type=duration` で使用）。典型値: 24（= 24時間以内定額）。",
            "examples": [
              24
            ]
          },
          "cap_price_minor": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "最大料金の金額（JPY 最小単位 = 1 円）。例: `1800` = 1800 円。",
            "examples": [
              1800
            ]
          },
          "cap_repeat": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "最大料金を繰り返し適用するか（24時間毎に打止め再計算する等）。DEFAULT `true`。`false` なら初回 24時間で打止めた後は unit 料金のみ。",
            "examples": [
              true
            ]
          },
          "cap_scope": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 50,
            "description": "最大料金の適用範囲ラベル（任意のスコープ識別子）。複数 cap ルールを区別する用途（例: `day` / `night` / `weekend`）。通常 null で OK。",
            "examples": [
              null
            ]
          }
        },
        "additionalProperties": false
      },
      "ParkingLotImageInput": {
        "type": "object",
        "properties": {
          "asset_id": {
            "type": "string",
            "format": "uuid",
            "description": "`assets` テーブルに事前登録済みの画像 UUID。`POST /v1/storage/upload-url` で発行 → PUT で実体 upload → その asset_id をここで紐付ける 2 段階フロー。",
            "examples": [
              "00000000-0000-0000-0000-000000000000"
            ]
          },
          "is_main": {
            "type": "boolean",
            "description": "メイン画像フラグ（一覧カード / サムネイル用）。同 lot で複数 true を付けた場合の整合性はこの API では保証しない（UI 側で 1 枚に絞ってから送ること）。DEFAULT `false`。",
            "examples": [
              true
            ]
          },
          "sort_order": {
            "type": [
              "integer",
              "null"
            ],
            "description": "ギャラリー表示順（昇順）。null は最後尾扱い。",
            "examples": [
              1
            ]
          }
        },
        "required": [
          "asset_id"
        ],
        "additionalProperties": false
      },
      "ParkingLotTagInput": {
        "type": "object",
        "properties": {
          "tag_code": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64,
            "pattern": "^[a-z][a-z0-9_]*$",
            "description": "タグを一意に識別するコード値。`tags.slug` を参照する snake_case 文字列。\n現時点でサポートしている値は OAS 例 / `GET /v1/tags` のレスポンスを参照。\n未知の code を送ると 400 `unknown_tag_code` で拒否される。",
            "examples": [
              "ev_charging"
            ]
          },
          "state": {
            "type": "boolean",
            "description": "タグ状態。`true` = 該当 / `false` = 明示的に非該当 / 省略 = `true` 扱い。「不明」に戻したい時は PATCH で `state=null` を送る（DELETE 扱い）。",
            "examples": [
              true
            ]
          }
        },
        "required": [
          "tag_code"
        ],
        "additionalProperties": false
      },
      "OwnerParkingLotBundleCreateBody": {
        "type": "object",
        "properties": {
          "parking_lot": {
            "$ref": "#/components/schemas/OwnerParkingLotCoreCreate"
          },
          "hours": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ParkingLotHourInput"
            },
            "maxItems": 50
          },
          "pricing_rules": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ParkingLotPricingRuleInput"
            },
            "maxItems": 100
          },
          "images": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ParkingLotImageInput"
            },
            "maxItems": 50
          },
          "tags": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ParkingLotTagInput"
            },
            "maxItems": 100
          }
        },
        "required": [
          "parking_lot"
        ],
        "additionalProperties": false
      },
      "OwnerParkingLotCorePatch": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "駐車場の表示名（必須）。系列名＋地名の形式が多い。",
            "examples": [
              "晴海西口第一駐車場"
            ]
          },
          "address": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 500,
            "description": "住所全文。都道府県 + 市区 + 町丁目 + 番地。公開検索の ILIKE 対象。",
            "examples": [
              "東京都中央区晴海20-39"
            ]
          },
          "lot_type": {
            "type": "string",
            "enum": [
              "regular",
              "meter",
              "ticket",
              "monthly_only",
              "hourly_with_monthly",
              "prepaid_coin"
            ],
            "description": "駐車場種別 (default `regular`)。`meter` / `ticket` を選んだ場合は wizard が物理制限・spots step をスキップする (§17)。",
            "examples": [
              "regular"
            ]
          },
          "vehicle_type_max": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 50,
            "description": "lot レベル default の最大車種 (codes.category_id=`vehicle_type`)。spot レベルで上書き可能。NULL = 未設定。",
            "examples": [
              "minivan"
            ]
          },
          "parent_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "親駐車場 UUID（ブランド系列の名寄せ用）。通常 null。",
            "examples": [
              "00000000-0000-0000-0000-000000000000"
            ]
          },
          "variant_label": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 200,
            "description": "同一系列内の区別ラベル（「第1」「第2」「裏口」等）。",
            "examples": [
              "第1"
            ]
          },
          "total_spaces": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "駐車可能台数。非負整数。",
            "examples": [
              12
            ]
          },
          "structure": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "flat",
              "self_multi",
              "mechanical"
            ],
            "description": "駐車場構造（codes.category_id=`lot_structure`）。\n- `flat`       : 平置き（屋根なし / 青空）\n- `self_multi` : 自走式立体（自走で各階へ）\n- `mechanical` : 機械式立体（パレット入れ替え）",
            "examples": [
              "mechanical"
            ]
          },
          "entry_method": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "self",
              "mechanical"
            ],
            "description": "入庫方式（codes.category_id=`lot_entry`）。\n- `self`       : 自走式（自分で停める）\n- `mechanical` : 機械式（パレットに車を載せる）\n`structure=mechanical` なら通常 `entry_method=mechanical`、\n`structure=flat`/`self_multi` なら `entry_method=self` が一般的。",
            "examples": [
              "mechanical"
            ]
          },
          "entry_difficulty": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "easy",
              "normal",
              "hard"
            ],
            "description": "入庫難易度（codes.category_id=`entry_difficulty`）。\n- `easy`   : 簡単\n- `normal` : 普通\n- `hard`   : 難しい",
            "examples": [
              "easy"
            ]
          },
          "max_height_m": {
            "type": [
              "number",
              "null"
            ],
            "description": "車高制限(m)。機械式は 1.55/2.10、自走式は 2.10/2.50 が典型。",
            "examples": [
              1.55
            ]
          },
          "max_width_m": {
            "type": [
              "number",
              "null"
            ],
            "description": "車幅制限(m)。1.85 / 1.95 が典型。",
            "examples": [
              1.95
            ]
          },
          "max_length_m": {
            "type": [
              "number",
              "null"
            ],
            "description": "全長制限(m)。5.00 / 5.30 が典型。",
            "examples": [
              5.3
            ]
          },
          "max_weight_t": {
            "type": [
              "number",
              "null"
            ],
            "description": "重量制限(t)。2.0 / 2.5 が典型。",
            "examples": [
              2.5
            ]
          },
          "min_clearance_cm": {
            "type": [
              "integer",
              "null"
            ],
            "description": "最低地上高(cm)。機械式で特に重要。",
            "examples": [
              10
            ]
          },
          "max_tire_width_mm": {
            "type": [
              "integer",
              "null"
            ],
            "description": "タイヤ幅制限(mm)。機械式で設定されることが多い。null = 制限なし（検索では合致扱い）。archive/041 で追加。",
            "examples": [
              205
            ]
          },
          "max_parking_duration_min": {
            "type": [
              "integer",
              "null"
            ],
            "description": "最大駐車時間(分)。短時間のみ等の制限がある場合のみ設定。archive/015 で追加。例: `180` = 3 時間。",
            "examples": [
              180
            ]
          },
          "receipt_available": {
            "type": "boolean",
            "description": "領収書発行可否。DEFAULT `false`。",
            "examples": [
              true
            ]
          },
          "operator_code": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "paraca",
              "times",
              "repark",
              "navipark",
              "mitsui",
              "npc24h",
              "ecoloparc",
              "coinpark",
              "other"
            ],
            "description": "運営会社コード（codes.category_id=`operator`）。\n- `paraca`    : パラカ\n- `times`     : タイムズ24\n- `repark`    : リパーク（三井のリパーク系列）\n- `navipark`  : ナビパーク\n- `mitsui`    : 三井のリパーク（本体）\n- `npc24h`    : NPC24H\n- `ecoloparc` : エコロパーク\n- `coinpark`  : コインパーク\n- `other`     : その他（分類不能 / 個人オーナー等）\n\nowner 自営の駐車場で運営会社が無い場合は `null` で OK。\n新規運営会社は codes マスター追加と schema enum 追記の 2 step で拡張する。",
            "examples": [
              "repark"
            ]
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 2000,
            "description": "駐車場の説明文（オーナーが自由記述）。UI の詳細ページに表示される。",
            "examples": [
              "駅から徒歩3分の好立地。夜間入庫可能。"
            ]
          },
          "pricing_notes": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 1000,
            "description": "料金に関する補足・備考（フリーテキスト）。特典・キャンペーン等の記述に使用。",
            "examples": [
              "月極契約は別途お問い合わせください。"
            ]
          },
          "contact_phone": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 50,
            "description": "問い合わせ電話番号。parking_field_values.field_name='contact_phone' に保存。",
            "examples": [
              "03-1234-5678"
            ]
          },
          "contact_email": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 200,
            "format": "email",
            "description": "問い合わせメールアドレス。parking_field_values.field_name='contact_email' に保存。",
            "examples": [
              "parking@example.com"
            ]
          },
          "contact_url": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 500,
            "format": "uri",
            "description": "問い合わせ / 予約ページ URL。parking_field_values.field_name='contact_url' に保存。",
            "examples": [
              "https://example.com/parking"
            ]
          },
          "capacity_kei": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "軽自動車スペース台数。parking_field_values.field_name='capacity_kei' に保存。",
            "examples": [
              4
            ]
          },
          "capacity_regular": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "普通車スペース台数。parking_field_values.field_name='capacity_regular' に保存。",
            "examples": [
              20
            ]
          },
          "capacity_oversized": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "大型車スペース台数。parking_field_values.field_name='capacity_oversized' に保存。",
            "examples": [
              3
            ]
          },
          "capacity_motorcycle": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "二輪車スペース台数。parking_field_values.field_name='capacity_motorcycle' に保存。",
            "examples": [
              5
            ]
          },
          "capacity_ev": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "EV充電スペース台数。parking_field_values.field_name='capacity_ev' に保存。",
            "examples": [
              2
            ]
          },
          "capacity_disabled": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "障害者スペース台数。parking_field_values.field_name='capacity_disabled' に保存。",
            "examples": [
              2
            ]
          },
          "entry_exit_locations": {
            "$ref": "#/components/schemas/EntryExitLocations"
          },
          "geometry": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ParkingLotGeometry"
              },
              {
                "description": "駐車場の座標 / 形状（shape_type と座標をペアで持つ nested object）。Create では省略時 `null`（座標未設定）。Patch では省略=触らない、`null`=座標クリア、object 指定で置換。"
              }
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "pending"
            ],
            "description": "Owner Bundle が受領する status (Phase A / 2026-04-29)。\n- `draft`   : 下書き保存 (admin 通知なし、検索除外)\n- `pending` : 申請 (admin 審査キューに投入、従来挙動)\n省略時は server 側で `pending` を default として投入。\n`active` / `on_hold` / `withdrawn` / `rejected` は admin 系 API で遷移。",
            "examples": [
              "draft"
            ]
          }
        },
        "additionalProperties": false
      },
      "ParkingLotTagPatchInput": {
        "type": "object",
        "properties": {
          "tag_code": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64,
            "pattern": "^[a-z][a-z0-9_]*$",
            "description": "タグを一意に識別するコード値。`tags.slug` を参照する snake_case 文字列。\n現時点でサポートしている値は OAS 例 / `GET /v1/tags` のレスポンスを参照。\n未知の code を送ると 400 `unknown_tag_code` で拒否される。",
            "examples": [
              "ev_charging"
            ]
          },
          "state": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "タグ状態。`true` / `false` / `null` の 3 値。`null` を送るとそのタグを `parking_lot_tags` から削除（= 不明に戻す）。",
            "examples": [
              true
            ]
          }
        },
        "required": [
          "tag_code",
          "state"
        ],
        "additionalProperties": false
      },
      "OwnerParkingLotBundleUpdateBody": {
        "type": "object",
        "properties": {
          "parking_lot": {
            "$ref": "#/components/schemas/OwnerParkingLotCorePatch"
          },
          "hours": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ParkingLotHourInput"
            },
            "maxItems": 50
          },
          "pricing_rules": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ParkingLotPricingRuleInput"
            },
            "maxItems": 100
          },
          "images": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ParkingLotImageInput"
            },
            "maxItems": 50
          },
          "tags": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ParkingLotTagPatchInput"
            },
            "maxItems": 100,
            "description": "タグ紐付け（parking_lot_tags）。`tag_code` は `tags.slug` を指すコード値。\n`state=null` を送るとそのタグを削除（= 不明に戻す）。\nbody に含まれていない tag は変更されない（差分適用）。"
          }
        },
        "additionalProperties": false
      },
      "OwnerParkingLotAreaPatchResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          }
        },
        "required": [
          "id"
        ]
      },
      "GeoJsonPolygon": {
        "type": [
          "object",
          "null"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "Polygon"
            ]
          },
          "coordinates": {
            "type": "array",
            "items": {
              "type": "array",
              "items": {
                "type": "array",
                "prefixItems": [
                  {
                    "type": "number"
                  },
                  {
                    "type": "number"
                  }
                ]
              }
            }
          }
        },
        "required": [
          "type",
          "coordinates"
        ]
      },
      "OwnerParkingLotAreaPatchBody": {
        "type": "object",
        "properties": {
          "area": {
            "$ref": "#/components/schemas/GeoJsonPolygon"
          }
        },
        "required": [
          "area"
        ]
      },
      "DateOverrideHoursBlock": {
        "type": "object",
        "properties": {
          "is_closed": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "is_24h": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "open_time": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^([01]\\d|2[0-4]):[0-5]\\d$"
          },
          "close_time": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^([01]\\d|2[0-4]):[0-5]\\d$"
          },
          "allowed": {
            "type": [
              "boolean",
              "null"
            ]
          }
        },
        "additionalProperties": false
      },
      "DateOverrideHoursMap": {
        "type": [
          "object",
          "null"
        ],
        "properties": {
          "business": {
            "$ref": "#/components/schemas/DateOverrideHoursBlock"
          },
          "entry": {
            "$ref": "#/components/schemas/DateOverrideHoursBlock"
          },
          "exit": {
            "$ref": "#/components/schemas/DateOverrideHoursBlock"
          },
          "after_hours_exit": {
            "$ref": "#/components/schemas/DateOverrideHoursBlock"
          }
        },
        "additionalProperties": false,
        "description": "営業時間オーバーライド。window_type 毎に block を指定。省略キーは通常ルールへフォールバック。"
      },
      "ParkingLotDateOverride": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "examples": [
              "00000000-0000-0000-0000-000000000000"
            ]
          },
          "parking_lot_id": {
            "type": "string",
            "format": "uuid",
            "examples": [
              "00000000-0000-0000-0000-000000000000"
            ]
          },
          "override_date": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
            "description": "対象日 (JST)",
            "examples": [
              "2026-07-25"
            ]
          },
          "label": {
            "type": "string",
            "description": "例外の名称",
            "examples": [
              "隅田川花火大会"
            ]
          },
          "hours": {
            "$ref": "#/components/schemas/DateOverrideHoursMap"
          },
          "note": {
            "type": [
              "string",
              "null"
            ],
            "description": "社内メモ（任意）"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "examples": [
              "2026-04-17T12:00:00Z"
            ]
          }
        },
        "required": [
          "id",
          "parking_lot_id",
          "override_date",
          "label",
          "hours",
          "note",
          "updated_at"
        ]
      },
      "DateOverrideUpsertBody": {
        "type": "object",
        "properties": {
          "override_date": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "label": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "hours": {
            "$ref": "#/components/schemas/DateOverrideHoursMap"
          },
          "note": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 2000
          }
        },
        "required": [
          "override_date",
          "label"
        ],
        "additionalProperties": false
      },
      "DateOverridePatchBody": {
        "type": "object",
        "properties": {
          "label": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "hours": {
            "$ref": "#/components/schemas/DateOverrideHoursMap"
          },
          "note": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 2000
          }
        },
        "additionalProperties": false
      },
      "OwnerParkingLotDiscount": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "examples": [
              "00000000-0000-0000-0000-000000000000"
            ]
          },
          "parking_lot_id": {
            "type": "string",
            "format": "uuid",
            "examples": [
              "00000000-0000-0000-0000-000000000000"
            ]
          },
          "code": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "kind": {
            "type": "string",
            "enum": [
              "free_minutes",
              "flat_off",
              "percent_off",
              "cap_override"
            ]
          },
          "value_minor": {
            "type": [
              "integer",
              "null"
            ]
          },
          "value_minutes": {
            "type": [
              "integer",
              "null"
            ]
          },
          "value_percent": {
            "type": [
              "number",
              "null"
            ]
          },
          "max_discount_minor": {
            "type": [
              "integer",
              "null"
            ]
          },
          "requires": {
            "type": "string",
            "enum": [
              "none",
              "partner_receipt",
              "member_card",
              "park_and_ride_ticket",
              "qr_code",
              "app_coupon",
              "staff_verification"
            ]
          },
          "partner_facility_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "partner_facility_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "min_purchase_minor": {
            "type": [
              "integer",
              "null"
            ]
          },
          "effective_from": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "effective_to": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "day_type": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "weekday",
              "saturday",
              "sunday",
              "holiday",
              "holiday_eve",
              "all"
            ]
          },
          "time_start": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^[0-2]\\d:[0-5]\\d$"
          },
          "time_end": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^[0-2]\\d:[0-5]\\d$"
          },
          "combinable": {
            "type": "boolean"
          },
          "stack_priority": {
            "type": "integer"
          },
          "exclude_codes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "max_apply_per_day": {
            "type": [
              "integer",
              "null"
            ]
          },
          "is_active": {
            "type": "boolean"
          },
          "created_at": {
            "type": "string"
          },
          "updated_at": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "parking_lot_id",
          "code",
          "name",
          "description",
          "kind",
          "value_minor",
          "value_minutes",
          "value_percent",
          "max_discount_minor",
          "requires",
          "partner_facility_name",
          "partner_facility_url",
          "min_purchase_minor",
          "effective_from",
          "effective_to",
          "day_type",
          "time_start",
          "time_end",
          "combinable",
          "stack_priority",
          "exclude_codes",
          "max_apply_per_day",
          "is_active",
          "created_at",
          "updated_at"
        ]
      },
      "OwnerParkingLotDiscountListResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OwnerParkingLotDiscount"
            }
          }
        },
        "required": [
          "items"
        ]
      },
      "OwnerParkingLotDiscountCreateBody": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 2000
          },
          "kind": {
            "type": "string",
            "enum": [
              "free_minutes",
              "flat_off",
              "percent_off",
              "cap_override"
            ]
          },
          "value_minor": {
            "type": [
              "integer",
              "null"
            ]
          },
          "value_minutes": {
            "type": [
              "integer",
              "null"
            ],
            "exclusiveMinimum": 0
          },
          "value_percent": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "maximum": 100
          },
          "max_discount_minor": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "requires": {
            "type": "string",
            "enum": [
              "none",
              "partner_receipt",
              "member_card",
              "park_and_ride_ticket",
              "qr_code",
              "app_coupon",
              "staff_verification"
            ]
          },
          "partner_facility_name": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 200
          },
          "partner_facility_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "min_purchase_minor": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "effective_from": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "effective_to": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "day_type": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "weekday",
              "saturday",
              "sunday",
              "holiday",
              "holiday_eve",
              "all"
            ]
          },
          "time_start": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^[0-2]\\d:[0-5]\\d$"
          },
          "time_end": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^[0-2]\\d:[0-5]\\d$"
          },
          "combinable": {
            "type": "boolean"
          },
          "stack_priority": {
            "type": "integer",
            "minimum": 0
          },
          "exclude_codes": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            }
          },
          "max_apply_per_day": {
            "type": [
              "integer",
              "null"
            ],
            "exclusiveMinimum": 0
          },
          "is_active": {
            "type": "boolean"
          }
        },
        "required": [
          "code",
          "name",
          "kind"
        ]
      },
      "OwnerParkingLotDiscountPatchBody": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 2000
          },
          "kind": {
            "type": "string",
            "enum": [
              "free_minutes",
              "flat_off",
              "percent_off",
              "cap_override"
            ]
          },
          "value_minor": {
            "type": [
              "integer",
              "null"
            ]
          },
          "value_minutes": {
            "type": [
              "integer",
              "null"
            ],
            "exclusiveMinimum": 0
          },
          "value_percent": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "maximum": 100
          },
          "max_discount_minor": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "requires": {
            "type": "string",
            "enum": [
              "none",
              "partner_receipt",
              "member_card",
              "park_and_ride_ticket",
              "qr_code",
              "app_coupon",
              "staff_verification"
            ]
          },
          "partner_facility_name": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 200
          },
          "partner_facility_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "min_purchase_minor": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "effective_from": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "effective_to": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "day_type": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "weekday",
              "saturday",
              "sunday",
              "holiday",
              "holiday_eve",
              "all"
            ]
          },
          "time_start": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^[0-2]\\d:[0-5]\\d$"
          },
          "time_end": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^[0-2]\\d:[0-5]\\d$"
          },
          "combinable": {
            "type": "boolean"
          },
          "stack_priority": {
            "type": "integer",
            "minimum": 0
          },
          "exclude_codes": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            }
          },
          "max_apply_per_day": {
            "type": [
              "integer",
              "null"
            ],
            "exclusiveMinimum": 0
          },
          "is_active": {
            "type": "boolean"
          }
        }
      },
      "ParkingLotHour": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "examples": [
              "00000000-0000-0000-0000-000000000000"
            ]
          },
          "parking_lot_id": {
            "type": "string",
            "format": "uuid",
            "examples": [
              "00000000-0000-0000-0000-000000000000"
            ]
          },
          "window_type": {
            "type": "string",
            "enum": [
              "business",
              "entry",
              "exit",
              "after_hours_exit"
            ],
            "description": "時間窓の種別（codes.category_id=`parking_hours_window_type`）。\n- `business`         : 通常営業時間（既存行はすべてこれ扱い。DEFAULT）\n- `entry`            : 入庫可能時間（夜間入庫不可施設など）\n- `exit`             : 出庫可能時間\n- `after_hours_exit` : 営業時間外の出庫可否フラグ（曜日単位）",
            "examples": [
              "business"
            ]
          },
          "day_type": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "all",
              "weekday",
              "saturday",
              "sunday",
              "holiday",
              "holiday_eve"
            ]
          },
          "day_of_week": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "maximum": 6
          },
          "is_24h": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "is_closed": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "open_time": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^([01]\\d|2[0-4]):[0-5]\\d$"
          },
          "close_time": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^([01]\\d|2[0-4]):[0-5]\\d$"
          },
          "effective_from": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "effective_to": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "examples": [
              "2026-04-17T12:00:00Z"
            ]
          }
        },
        "required": [
          "id",
          "parking_lot_id",
          "window_type",
          "day_type",
          "day_of_week",
          "is_24h",
          "is_closed",
          "open_time",
          "close_time",
          "effective_from",
          "effective_to",
          "updated_at"
        ]
      },
      "ParkingLotHoursReplaceBody": {
        "type": "object",
        "properties": {
          "window_type": {
            "type": "string",
            "enum": [
              "business",
              "entry",
              "exit",
              "after_hours_exit"
            ],
            "description": "置換対象の window_type。省略時は全 window_type を一括置換する（= `parking_lot_hours` の該当 lot 行を完全リセット）。",
            "examples": [
              "business"
            ]
          },
          "hours": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ParkingLotHourInput"
            },
            "maxItems": 50,
            "description": "置換後の hours 配列。window_type 指定時は全要素がその window_type である必要がある（body の `window_type` と異なる要素は 400）。"
          }
        },
        "required": [
          "hours"
        ],
        "additionalProperties": false
      },
      "OwnerParkingLotImage": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "parking_lot_id": {
            "type": "string",
            "format": "uuid"
          },
          "asset_id": {
            "type": "string",
            "format": "uuid"
          },
          "is_main": {
            "type": "boolean"
          },
          "sort_order": {
            "type": "integer"
          },
          "created_at": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "parking_lot_id",
          "asset_id",
          "is_main",
          "sort_order",
          "created_at"
        ]
      },
      "OwnerParkingLotImageCreateBody": {
        "type": "object",
        "properties": {
          "asset_id": {
            "type": "string",
            "format": "uuid",
            "examples": [
              "00000000-0000-0000-0000-000000000000"
            ]
          },
          "is_main": {
            "type": "boolean"
          },
          "sort_order": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "asset_id"
        ]
      },
      "OwnerParkingLotImageUpdateBody": {
        "type": "object",
        "properties": {
          "sort_order": {
            "type": "integer",
            "minimum": 0
          },
          "is_main": {
            "type": "boolean"
          }
        }
      },
      "OwnerPendingFieldItem": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "field_name": {
            "type": "string",
            "enum": [
              "name",
              "address",
              "total_spaces",
              "structure",
              "entry_method",
              "receipt_available",
              "pricing_notes",
              "vehicle_type_max",
              "contact_phone",
              "contact_email",
              "contact_url",
              "capacity_disabled",
              "capacity_kei",
              "capacity_regular",
              "capacity_oversized",
              "capacity_motorcycle",
              "capacity_ev",
              "entry_difficulty"
            ]
          },
          "value": {},
          "captured_at": {
            "type": "string"
          },
          "contributor_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          }
        },
        "required": [
          "id",
          "field_name",
          "captured_at",
          "contributor_id"
        ]
      },
      "OwnerPendingFieldsResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OwnerPendingFieldItem"
            }
          },
          "total": {
            "type": "integer"
          }
        },
        "required": [
          "items",
          "total"
        ]
      },
      "PricingGroup": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "parking_lot_id": {
            "type": "string",
            "format": "uuid"
          },
          "code": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "is_default": {
            "type": "boolean"
          },
          "display_order": {
            "type": "integer"
          },
          "created_at": {
            "type": "string"
          },
          "updated_at": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "parking_lot_id",
          "code",
          "name",
          "is_default",
          "display_order",
          "created_at",
          "updated_at"
        ]
      },
      "PricingGroupCreateBody": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "minLength": 1,
            "maxLength": 32,
            "pattern": "^[A-Za-z0-9][A-Za-z0-9_-]*$"
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "is_default": {
            "type": "boolean"
          },
          "display_order": {
            "type": "integer"
          }
        },
        "required": [
          "code",
          "name"
        ]
      },
      "PricingGroupUpdateBody": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "minLength": 1,
            "maxLength": 32,
            "pattern": "^[A-Za-z0-9][A-Za-z0-9_-]*$"
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "is_default": {
            "type": "boolean"
          },
          "display_order": {
            "type": "integer"
          }
        }
      },
      "PricingCap": {
        "type": [
          "object",
          "null"
        ],
        "properties": {
          "type": {
            "type": "string",
            "minLength": 1,
            "maxLength": 32
          },
          "duration_hours": {
            "type": [
              "integer",
              "null"
            ],
            "exclusiveMinimum": 0
          },
          "price_minor": {
            "type": "integer",
            "minimum": 0
          },
          "repeat": {
            "type": "boolean"
          },
          "scope": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "type",
          "price_minor",
          "repeat"
        ]
      },
      "PricingRule": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "parking_lot_id": {
            "type": "string",
            "format": "uuid"
          },
          "pricing_group_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "rule_order": {
            "type": "integer"
          },
          "category": {
            "type": "string"
          },
          "day_type": {
            "type": [
              "string",
              "null"
            ]
          },
          "time_start": {
            "type": [
              "string",
              "null"
            ]
          },
          "time_end": {
            "type": [
              "string",
              "null"
            ]
          },
          "per_minutes": {
            "type": [
              "integer",
              "null"
            ]
          },
          "price_minor": {
            "type": [
              "integer",
              "null"
            ]
          },
          "cap": {
            "$ref": "#/components/schemas/PricingCap"
          },
          "created_at": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "parking_lot_id",
          "pricing_group_id",
          "rule_order",
          "category",
          "day_type",
          "time_start",
          "time_end",
          "per_minutes",
          "price_minor",
          "cap",
          "created_at"
        ]
      },
      "PricingRuleCreateBody": {
        "type": "object",
        "properties": {
          "rule_order": {
            "type": "integer"
          },
          "category": {
            "type": "string",
            "minLength": 1,
            "maxLength": 32
          },
          "day_type": {
            "type": [
              "string",
              "null"
            ]
          },
          "time_start": {
            "type": [
              "string",
              "null"
            ]
          },
          "time_end": {
            "type": [
              "string",
              "null"
            ]
          },
          "per_minutes": {
            "type": [
              "integer",
              "null"
            ]
          },
          "price_minor": {
            "type": [
              "integer",
              "null"
            ]
          },
          "cap": {
            "$ref": "#/components/schemas/PricingCap"
          }
        },
        "required": [
          "category"
        ]
      },
      "PricingRuleUpdateBody": {
        "type": "object",
        "properties": {
          "rule_order": {
            "type": "integer"
          },
          "category": {
            "type": "string",
            "minLength": 1,
            "maxLength": 32
          },
          "day_type": {
            "type": [
              "string",
              "null"
            ]
          },
          "time_start": {
            "type": [
              "string",
              "null"
            ]
          },
          "time_end": {
            "type": [
              "string",
              "null"
            ]
          },
          "per_minutes": {
            "type": [
              "integer",
              "null"
            ]
          },
          "price_minor": {
            "type": [
              "integer",
              "null"
            ]
          },
          "cap": {
            "$ref": "#/components/schemas/PricingCap"
          }
        }
      },
      "PricingRuleReplaceBody": {
        "type": "object",
        "properties": {
          "rules": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PricingRuleCreateBody"
            }
          }
        },
        "required": [
          "rules"
        ]
      },
      "OwnerLotTag": {
        "type": "object",
        "properties": {
          "tag_id": {
            "type": "string",
            "format": "uuid"
          },
          "slug": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "color": {
            "type": [
              "string",
              "null"
            ]
          },
          "icon_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "category": {
            "type": [
              "string",
              "null"
            ]
          },
          "is_owner_editable": {
            "type": "boolean"
          },
          "state": {
            "type": "boolean"
          }
        },
        "required": [
          "tag_id",
          "slug",
          "name",
          "color",
          "icon_name",
          "category",
          "is_owner_editable",
          "state"
        ]
      },
      "ParkingSpot": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "parking_lot_id": {
            "type": "string",
            "format": "uuid"
          },
          "pricing_group_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "code": {
            "type": "string"
          },
          "count": {
            "type": "integer",
            "exclusiveMinimum": 0
          },
          "vehicle_type_max": {
            "type": [
              "string",
              "null"
            ]
          },
          "is_ev_charger": {
            "type": "boolean"
          },
          "ev_connector_type": {
            "type": [
              "string",
              "null"
            ]
          },
          "ev_charge_power_kw": {
            "type": [
              "number",
              "null"
            ]
          },
          "ev_charge_type": {
            "type": [
              "string",
              "null"
            ]
          },
          "ev_charge_operator": {
            "type": [
              "string",
              "null"
            ]
          },
          "ev_charge_billing": {
            "type": [
              "string",
              "null"
            ]
          },
          "ev_charge_network_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "accessibility": {
            "type": [
              "string",
              "null"
            ]
          },
          "width_mm": {
            "type": [
              "integer",
              "null"
            ]
          },
          "length_mm": {
            "type": [
              "integer",
              "null"
            ]
          },
          "height_mm": {
            "type": [
              "integer",
              "null"
            ]
          },
          "max_weight_kg": {
            "type": [
              "integer",
              "null"
            ]
          },
          "min_clearance_mm": {
            "type": [
              "integer",
              "null"
            ]
          },
          "max_tire_width_mm": {
            "type": [
              "integer",
              "null"
            ]
          },
          "is_reservable": {
            "type": "boolean"
          },
          "is_active": {
            "type": "boolean"
          },
          "meta": {
            "type": "object",
            "additionalProperties": {}
          },
          "created_at": {
            "type": "string"
          },
          "updated_at": {
            "type": "string"
          },
          "deleted_at": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "parking_lot_id",
          "pricing_group_id",
          "code",
          "count",
          "vehicle_type_max",
          "is_ev_charger",
          "ev_connector_type",
          "ev_charge_power_kw",
          "ev_charge_type",
          "ev_charge_operator",
          "ev_charge_billing",
          "ev_charge_network_id",
          "accessibility",
          "width_mm",
          "length_mm",
          "height_mm",
          "max_weight_kg",
          "min_clearance_mm",
          "max_tire_width_mm",
          "is_reservable",
          "is_active",
          "meta",
          "created_at",
          "updated_at",
          "deleted_at"
        ]
      },
      "ParkingSpotCreateBody": {
        "type": "object",
        "properties": {
          "parking_lot_id": {
            "type": "string",
            "format": "uuid",
            "examples": [
              "00000000-0000-0000-0000-000000000000"
            ]
          },
          "pricing_group_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "examples": [
              "00000000-0000-0000-0000-000000000000"
            ]
          },
          "code": {
            "type": "string",
            "minLength": 1,
            "maxLength": 32,
            "pattern": "^[A-Za-z0-9][A-Za-z0-9_-]*$"
          },
          "count": {
            "type": "integer",
            "exclusiveMinimum": 0
          },
          "vehicle_type_max": {
            "type": [
              "string",
              "null"
            ]
          },
          "is_ev_charger": {
            "type": "boolean"
          },
          "ev_connector_type": {
            "type": [
              "string",
              "null"
            ]
          },
          "ev_charge_power_kw": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0
          },
          "ev_charge_type": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "ac",
              "dc",
              "ac_three_phase"
            ]
          },
          "ev_charge_operator": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 64
          },
          "ev_charge_billing": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "separate",
              "included",
              "free"
            ]
          },
          "ev_charge_network_id": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 128
          },
          "accessibility": {
            "type": [
              "string",
              "null"
            ]
          },
          "width_mm": {
            "type": [
              "integer",
              "null"
            ],
            "exclusiveMinimum": 0
          },
          "length_mm": {
            "type": [
              "integer",
              "null"
            ],
            "exclusiveMinimum": 0
          },
          "height_mm": {
            "type": [
              "integer",
              "null"
            ],
            "exclusiveMinimum": 0
          },
          "max_weight_kg": {
            "type": [
              "integer",
              "null"
            ],
            "exclusiveMinimum": 0
          },
          "min_clearance_mm": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "max_tire_width_mm": {
            "type": [
              "integer",
              "null"
            ],
            "exclusiveMinimum": 0
          },
          "is_reservable": {
            "type": "boolean"
          },
          "is_active": {
            "type": "boolean"
          },
          "meta": {
            "type": "object",
            "additionalProperties": {}
          }
        },
        "required": [
          "parking_lot_id",
          "code"
        ]
      },
      "ParkingSpotUpdateBody": {
        "type": "object",
        "properties": {
          "pricing_group_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "examples": [
              "00000000-0000-0000-0000-000000000000"
            ]
          },
          "code": {
            "type": "string",
            "minLength": 1,
            "maxLength": 32,
            "pattern": "^[A-Za-z0-9][A-Za-z0-9_-]*$"
          },
          "count": {
            "type": "integer",
            "exclusiveMinimum": 0
          },
          "vehicle_type_max": {
            "type": [
              "string",
              "null"
            ]
          },
          "is_ev_charger": {
            "type": "boolean"
          },
          "ev_connector_type": {
            "type": [
              "string",
              "null"
            ]
          },
          "ev_charge_power_kw": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0
          },
          "ev_charge_type": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "ac",
              "dc",
              "ac_three_phase"
            ]
          },
          "ev_charge_operator": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 64
          },
          "ev_charge_billing": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "separate",
              "included",
              "free"
            ]
          },
          "ev_charge_network_id": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 128
          },
          "accessibility": {
            "type": [
              "string",
              "null"
            ]
          },
          "width_mm": {
            "type": [
              "integer",
              "null"
            ],
            "exclusiveMinimum": 0
          },
          "length_mm": {
            "type": [
              "integer",
              "null"
            ],
            "exclusiveMinimum": 0
          },
          "height_mm": {
            "type": [
              "integer",
              "null"
            ],
            "exclusiveMinimum": 0
          },
          "max_weight_kg": {
            "type": [
              "integer",
              "null"
            ],
            "exclusiveMinimum": 0
          },
          "min_clearance_mm": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "max_tire_width_mm": {
            "type": [
              "integer",
              "null"
            ],
            "exclusiveMinimum": 0
          },
          "is_reservable": {
            "type": "boolean"
          },
          "is_active": {
            "type": "boolean"
          },
          "meta": {
            "type": "object",
            "additionalProperties": {}
          }
        }
      },
      "OwnerApplication": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "owner_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "owner_name": {
            "type": "string"
          },
          "owner_email": {
            "type": "string"
          },
          "company_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "parking_lot_id": {
            "type": "string",
            "format": "uuid"
          },
          "proof_asset_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "additional_notes": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string"
          },
          "reviewed_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "reject_reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "owner_id",
          "owner_name",
          "owner_email",
          "company_name",
          "parking_lot_id",
          "proof_asset_id",
          "additional_notes",
          "status",
          "reviewed_at",
          "reject_reason",
          "created_at"
        ]
      },
      "ReviewStatus": {
        "type": "string",
        "enum": [
          "pending",
          "approved",
          "rejected",
          "hidden"
        ]
      },
      "OwnerReview": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "parking_lot_id": {
            "type": "string",
            "format": "uuid"
          },
          "rating": {
            "type": "integer",
            "minimum": 1,
            "maximum": 5
          },
          "comment": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "$ref": "#/components/schemas/ReviewStatus"
          },
          "created_at": {
            "type": "string"
          },
          "user_name": {
            "type": "string"
          },
          "owner_reply": {
            "type": [
              "string",
              "null"
            ]
          },
          "owner_replied_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "owner_replied_by": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "updated_at": {
            "type": "string"
          },
          "parking_lot": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "name": {
                "type": "string"
              }
            },
            "required": [
              "id",
              "name"
            ]
          }
        },
        "required": [
          "id",
          "parking_lot_id",
          "rating",
          "comment",
          "status",
          "created_at",
          "user_name",
          "owner_reply",
          "owner_replied_at",
          "owner_replied_by",
          "updated_at",
          "parking_lot"
        ]
      },
      "OwnerBoostStatsEmbed": {
        "type": "object",
        "properties": {
          "impressions": {
            "type": "integer"
          },
          "clicks": {
            "type": "integer"
          },
          "sessions": {
            "type": "integer"
          },
          "credit_consumed": {
            "type": "integer"
          }
        },
        "required": [
          "impressions",
          "clicks",
          "sessions",
          "credit_consumed"
        ]
      },
      "OwnerBoost": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "owner_id": {
            "type": "string",
            "format": "uuid"
          },
          "parking_lot_id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "credit_per_impression": {
            "type": [
              "integer",
              "null"
            ]
          },
          "daily_budget": {
            "type": [
              "integer",
              "null"
            ]
          },
          "total_budget": {
            "type": [
              "integer",
              "null"
            ]
          },
          "started_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "ended_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "impressions": {
            "type": [
              "integer",
              "null"
            ]
          },
          "clicks": {
            "type": [
              "integer",
              "null"
            ]
          },
          "sessions": {
            "type": [
              "integer",
              "null"
            ]
          },
          "status": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "owner_id",
          "parking_lot_id",
          "name",
          "credit_per_impression",
          "daily_budget",
          "total_budget",
          "started_at",
          "ended_at",
          "impressions",
          "clicks",
          "sessions",
          "status",
          "created_at"
        ]
      },
      "OwnerBoostWithStats": {
        "allOf": [
          {
            "$ref": "#/components/schemas/OwnerBoost"
          },
          {
            "type": "object",
            "properties": {
              "stats": {
                "$ref": "#/components/schemas/OwnerBoostStatsEmbed"
              }
            }
          }
        ]
      },
      "OwnerBoostCreateBody": {
        "type": "object",
        "properties": {
          "parking_lot_id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "credit_per_impression": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "daily_budget": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "total_budget": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "started_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "ended_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "status": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 50
          }
        },
        "required": [
          "parking_lot_id",
          "name"
        ],
        "additionalProperties": false
      },
      "OwnerBoostUpdateBody": {
        "type": "object",
        "properties": {
          "parking_lot_id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "credit_per_impression": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "daily_budget": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "total_budget": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "started_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "ended_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "status": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 50
          }
        },
        "additionalProperties": false
      },
      "OwnerCreditTxn": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "owner_id": {
            "type": "string",
            "format": "uuid"
          },
          "type": {
            "type": "string"
          },
          "amount": {
            "type": "integer"
          },
          "balance_after": {
            "type": "integer"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "boost_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "created_at": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "owner_id",
          "type",
          "amount",
          "balance_after",
          "description",
          "boost_id",
          "created_at"
        ]
      },
      "OwnerCreditCheckoutSession": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "format": "uri"
          },
          "session_id": {
            "type": "string"
          }
        },
        "required": [
          "url",
          "session_id"
        ]
      }
    },
    "parameters": {}
  },
  "paths": {
    "/.well-known/apple-app-site-association": {
      "get": {
        "tags": [
          "well-known"
        ],
        "summary": "iOS Universal Links 設定 / iOS Universal Links Config",
        "description": "Apple が Universal Links 検証時に取得する JSON。\n\n- 認証不要・公開エンドポイント。\n- Content-Type は application/json 固定。\n- Cache-Control: public, max-age=86400（24 時間）。\n- `appIDs` は環境変数 `IOS_APP_ID`（形式: TEAMID.co.jp.parky.app）から取得。\n  または `IOS_APP_TEAM_ID` + `IOS_APP_BUNDLE_ID` を個別に指定（優先）。\n  すべて未設定時は `details` と `webcredentials.apps` を空配列にして返す。\n- 対応パス: /parking-lots/*, /parking-sessions/*, /share/parking/*, /articles/*, /auth/*",
        "responses": {
          "200": {
            "description": "Apple App Site Association",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppleAppSiteAssociation"
                }
              }
            }
          }
        },
        "operationId": "webWellKnownAppleAppSiteAssociationList"
      }
    },
    "/.well-known/assetlinks.json": {
      "get": {
        "tags": [
          "well-known"
        ],
        "summary": "Android App Links 設定 / Android App Links Config",
        "description": "Android が App Links 検証時に取得する JSON。\n\n- 認証不要・公開エンドポイント。\n- Content-Type は application/json 固定。\n- Cache-Control: public, max-age=86400（24 時間）。\n- `package_name` は環境変数 `ANDROID_PACKAGE_NAME` から取得。\n- `sha256_cert_fingerprints` は環境変数 `ANDROID_APP_CERT_FINGERPRINTS`（カンマ区切り）から取得。\n  未設定時は空配列 `[]`（Android 側は App Links 検出しないだけで 200）。",
        "responses": {
          "200": {
            "description": "Digital Asset Links",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AssetLinksResponse"
                }
              }
            }
          }
        },
        "operationId": "webWellKnownAssetlinksList"
      }
    },
    "/v1/owner/me": {
      "get": {
        "tags": [
          "owner-me"
        ],
        "summary": "ログイン中オーナーのプロフィールを返す（ロール検証用）",
        "description": "### 用途\nオーナーポータルのフロントエンドが「sign-in 直後 / セッション復元時」に呼び出して\nロール検証する軽量 endpoint。`requireOwner` middleware を通過した時点で\n`owners.user_id = JWT.sub` かつ `status='active'` が保証される。\n\n### 期待する挙動\n- 認可成功: 200 + 自身の owner プロフィール\n- 非オーナー（admins.user_id しか持たない / 一般ユーザー）: 403 (`owner_not_found`)\n- suspended/disabled: 403 (`owner_status_inactive`)\n\n### Owner Portal 側の使い方\nAuthContext.signIn() が成功した直後にこの endpoint を呼び、403 なら\nsupabase.auth.signOut() + LoginPage に「オーナー権限がありません」表示。",
        "responses": {
          "200": {
            "description": "オーナープロフィール",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OwnerMe"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerRootMe"
      }
    },
    "/v1/owner/parking-lots/mine": {
      "get": {
        "tags": [
          "駐車場 / Parking Lots"
        ],
        "summary": "オーナー管理駐車場一覧 / My Parking Lots",
        "description": "### 用途\nログイン中オーナーが `parking_lot_owners` リンクを通じて所有している駐車場の一覧を返す。\nオーナーポータルのトップ画面・サイドバーの駐車場切替ドロップダウンで利用される基幹 API。\n\n### オーナーポータルでの使用タイミング\n- ダッシュボード初回表示でオーナーが管理する物件サマリを描画するとき\n- 「自分の駐車場」一覧画面のテーブル表示・ページング操作時\n- レビュー / ブースト画面の駐車場フィルタードロップダウンを構築するとき\n\n### 認証・認可\n`requireOwner` ミドルウェアで Bearer JWT を検証し、`owners` テーブルから `status='active'` の owner 行を引き当てる。\n未設定 (`user_id IS NULL`) や `reviewing`/`suspended` の owner は 403。\n返却対象は `parking_lot_owners.owner_id = current_owner_id()` に厳密に絞られる（RLS）。\n\n### 挙動・制約\n- `withOwnerContext` が `SET LOCAL ROLE authenticated` + `jwt.claims` を発行し、RLS で物理ガードする\n- parking_lot_owners の RLS が current_owner_id() に絞るため、アプリ層 WHERE owner_id は不要（CLAUDE.md §1.6）\n- 並び順は `parking_lots.created_at DESC NULLS LAST` 固定\n- ページングは `PageQuerySchema`（page / limit）\n\n### 関連\n- `GET /v1/owner/parking-lots/mine/{lotId}` — 1 件詳細\n- `PATCH /v1/owner/parking-lots/mine/{lotId}` — 編集\n- `POST /v1/owner/parking-lots/mine` — 新規申請（`status='pending'` で admin 審査待ち）\n- `GET /v1/owner/parking-lots/search` — オーナー申請対象探索",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^\\d+$",
              "description": "1 はじまりのページ番号",
              "examples": [
                "1"
              ]
            },
            "required": false,
            "name": "page",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^\\d+$",
              "description": "1 ページあたりの件数（最大 2000）",
              "examples": [
                "20"
              ]
            },
            "required": false,
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "description": "cursor ページング利用時の不透明トークン。offset ページング（page/limit）とは排他。"
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "description": "公開状態でフィルタ。カンマ区切りで複数指定可。\n値は `draft` / `pending` / `active` / `on_hold` / `withdrawn` / `rejected` のいずれか。\n例: `status=draft` / `status=draft,pending`。未指定なら全件。",
              "examples": [
                "draft,pending"
              ]
            },
            "required": false,
            "name": "status",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "一覧",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/OwnerParkingLot"
                      }
                    },
                    "page": {
                      "type": "integer",
                      "minimum": 1
                    },
                    "limit": {
                      "type": "integer",
                      "minimum": 1
                    },
                    "total": {
                      "type": "integer",
                      "minimum": 0
                    },
                    "total_is_estimate": {
                      "type": "boolean",
                      "description": "true のとき total は pg_class.reltuples 由来の概算値（数千行ズレ得る）。exact COUNT のときは field 自体が省略される。"
                    }
                  },
                  "required": [
                    "items",
                    "page",
                    "limit",
                    "total"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingLotsMine"
      },
      "post": {
        "tags": [
          "駐車場 / Parking Lots"
        ],
        "summary": "駐車場を登録 / Register Parking Lot",
        "description": "### 用途\nオーナーが自分の新規駐車場を 1 リクエストで登録する。parking_lot 本体に加え、\n営業時間・料金ルール・画像・タグまで同一トランザクションで atomic 投入できる。\n\n### オーナーポータルでの使用タイミング\n- 「駐車場を追加」ウィザード最終ステップの送信時\n- 申請後すぐにダッシュボードへ戻り「審査中」バッジを表示するため\n\n### 認証・認可\n`requireOwner` 必須。`ownerContext()` middleware により `SET LOCAL ROLE authenticated`\n+ `jwt.claims` を発行した tx で実行され、子テーブルの write は\n`is_lot_owner(parking_lot_id)` RLS 述語で自動的にスコープされる。\n\n### admin 版との違い\n- `parking_lot.status` は body から除外（server が 'pending' を強制）\n- `owner_ids` は受け付けない（自動で呼出元 owner を `parking_lot_owners` に紐付け）\n- それ以外の shape・セマンティクスは admin 版と完全同一\n\n### 挙動・制約\n- 子配列（`hours` / `pricing_rules` / `images` / `tags`）は全て optional。\n- 省略時は対応する子テーブルに INSERT しない。\n- `asset_id` は事前存在必須（assets は storage upload API 経由で作成）。\n- `tag_code` は `tags.slug` を参照するコード値。未知 code は 400 `unknown_tag_code`。\n- どちらかの INSERT が失敗すれば tx 全体 ROLLBACK（部分作成を残さない）。\n- `parking_lot_owners` は `(parking_lot_id, owner_id)` UNIQUE 競合時 DO NOTHING（冪等）。\n- admin が却下した場合は `parking_lots.status` を 'withdrawn' へ遷移 or 削除する運用。\n\n### 関連\n- `GET /v1/owner/parking-lots/mine` — 自分の登録駐車場一覧（`status='pending'` を含む）\n- `PATCH /v1/owner/parking-lots/mine/{lotId}` — 同 shape で編集（全量 or 部分）\n- `POST /v1/admin/parking-lots` — admin 版（owner_ids 指定可 / status 自由）",
        "requestBody": {
          "description": "駐車場本体 + 子テーブル（hours / pricing_rules / images / tags）の全量。`status` は server が `pending` を強制する（body から除外）。`owner_ids` は受け付けない（呼出元 owner を自動紐付け）。",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OwnerParkingLotBundleCreateBody"
              },
              "example": {
                "parking_lot": {
                  "name": "自社ビル前駐車場",
                  "address": "東京都品川区大崎1-11-1",
                  "total_spaces": 8,
                  "operating_hours": "06:00〜24:00",
                  "structure": "flat",
                  "entry_method": "self",
                  "entry_difficulty": "easy",
                  "max_height_m": 2.1,
                  "max_width_m": 1.95,
                  "max_length_m": 5,
                  "max_weight_t": 2,
                  "receipt_available": true,
                  "geometry": {
                    "shape_type": "point",
                    "point": {
                      "lat": 35.619778,
                      "lng": 139.728539
                    }
                  }
                },
                "hours": [
                  {
                    "day_type": "all",
                    "open_time": "06:00",
                    "close_time": "24:00",
                    "is_24h": false,
                    "is_closed": false
                  }
                ],
                "pricing_rules": [
                  {
                    "rule_order": 1,
                    "category": "unit",
                    "day_type": "all",
                    "time_start": "08:00",
                    "time_end": "22:00",
                    "per_minutes": 30,
                    "price_minor": 300
                  },
                  {
                    "rule_order": 2,
                    "category": "cap",
                    "day_type": "weekday",
                    "cap_type": "duration",
                    "cap_duration_hours": 24,
                    "cap_price_minor": 2000,
                    "cap_repeat": true
                  }
                ],
                "images": [
                  {
                    "asset_id": "11111111-2222-3333-4444-555555555555",
                    "is_main": true,
                    "sort_order": 1
                  },
                  {
                    "asset_id": "22222222-3333-4444-5555-666666666666",
                    "is_main": false,
                    "sort_order": 2
                  }
                ],
                "tags": [
                  {
                    "tag_code": "covered",
                    "state": false
                  },
                  {
                    "tag_code": "open_24h",
                    "state": false
                  },
                  {
                    "tag_code": "entry_24h",
                    "state": true
                  },
                  {
                    "tag_code": "oversized_ok",
                    "state": false
                  },
                  {
                    "tag_code": "monthly_available",
                    "state": false
                  },
                  {
                    "tag_code": "motorcycle_ok",
                    "state": true
                  },
                  {
                    "tag_code": "wheelchair_accessible",
                    "state": false
                  },
                  {
                    "tag_code": "barrier_free",
                    "state": false
                  },
                  {
                    "tag_code": "ev_charging",
                    "state": false
                  },
                  {
                    "tag_code": "reservable",
                    "state": false
                  },
                  {
                    "tag_code": "has_max_fee",
                    "state": false
                  },
                  {
                    "tag_code": "security_camera",
                    "state": true
                  },
                  {
                    "tag_code": "coin_500_or_less",
                    "state": false
                  },
                  {
                    "tag_code": "near_station",
                    "state": false
                  },
                  {
                    "tag_code": "low_price",
                    "state": false
                  },
                  {
                    "tag_code": "partner_facility",
                    "state": false
                  },
                  {
                    "tag_code": "pay_cash",
                    "state": true
                  },
                  {
                    "tag_code": "pay_bills_only",
                    "state": false
                  },
                  {
                    "tag_code": "pay_credit_card",
                    "state": false
                  },
                  {
                    "tag_code": "pay_e_money",
                    "state": false
                  },
                  {
                    "tag_code": "pay_qr_code",
                    "state": false
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "登録成功",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ParkingLotBundleResponse"
                },
                "example": {
                  "parking_lot": {
                    "id": "01234567-89ab-cdef-0123-456789abcdef",
                    "name": "自社ビル前駐車場",
                    "status": "pending",
                    "address": "東京都品川区大崎1-11-1",
                    "geometry": {
                      "shape_type": "point",
                      "point": {
                        "lat": 35.619778,
                        "lng": 139.728539
                      }
                    },
                    "created_at": "2026-04-22T10:30:00.000Z"
                  },
                  "hours_count": 1,
                  "pricing_rules_count": 2,
                  "images_count": 1,
                  "tags_count": 1,
                  "owners_count": 1
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingLotsMine2"
      }
    },
    "/v1/owner/parking-lots/mine/{lotId}": {
      "get": {
        "tags": [
          "駐車場 / Parking Lots"
        ],
        "summary": "駐車場詳細 / Parking Lot Detail",
        "description": "### 用途\nオーナーが所有する単一駐車場の全カラムを返す。編集画面の初期値表示や、\nブースト作成時の物件メタ表示で使用する。\n\n### オーナーポータルでの使用タイミング\n- 駐車場詳細画面に遷移したとき\n- 「駐車場を編集」モーダルを開いたとき（最新値で再取得）\n- ブースト作成ウィザードで対象駐車場の住所・台数を確認するとき\n\n### 認証・認可\n`requireOwner`。`parking_lot_owners` を `parking_lot_id` で照合し、\nRLS により自オーナーのリンクしか見えないので、行がなければ `owner_not_lot_owner` を返す。\n\n### 挙動・制約\n- 駐車場行が無い場合は `parking_lot_not_found`\n- レスポンスは `OwnerParkingLotRow`（schema/owner.ts と data 層 `findOwnerParkingLotRowById` で列を明示揃え）\n- `withOwnerContext` 内のトランザクションで権限チェックと SELECT を実行\n\n### 関連\n- `GET /v1/owner/parking-lots/mine` — 一覧\n- `PATCH /v1/owner/parking-lots/mine/{lotId}` — 編集",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "lotId",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "詳細",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OwnerParkingLotRow"
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingLotsMineGet"
      },
      "patch": {
        "tags": [
          "駐車場 / Parking Lots"
        ],
        "summary": "自分の駐車場を全量更新 / Update My Parking Lot (Full Replace)",
        "description": "### 用途\nオーナーが自分の駐車場の情報を 1 リクエストで更新する。admin 版と同一の子配列\nセマンティクス（省略=触らない / 空配列=全削除 or 何もしない）。\n\n### オーナーポータルでの使用タイミング\n- 駐車場詳細の編集画面でまとめ保存\n- マップ上のピン位置補正 / 営業時間追加 / 写真差し替え\n\n### 認証・認可\n`requireOwner` + `ownerContext()`。RLS により自分の駐車場以外の UPDATE は 0 行になる\n（= `parking_lot_not_found` で返す）。子テーブル書き込みも `is_lot_owner()` 述語で\n自動スコープされる。\n\n### admin 版との違い\n- `parking_lot.status` は変更不可（body から除外、server も強制 upstream しない）\n- `owner_ids` は変更不可（admin 経由でのみ変更可能）\n- `id` / `created_at` / `updated_at` / `deleted_at` / `location` / `area` は禁則\n\n### 関連\n- `POST /v1/owner/parking-lots/mine` — 新規登録\n- `GET /v1/owner/parking-lots/mine/{lotId}` — 詳細取得",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "lotId",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OwnerParkingLotBundleUpdateBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "更新後",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ParkingLotBundleResponse"
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingLotsMineUpdate"
      }
    },
    "/v1/owner/parking-lots/search": {
      "get": {
        "tags": [
          "駐車場 / Parking Lots"
        ],
        "summary": "駐車場を検索 / Search Parking Lots",
        "description": "### 用途\nParky に登録済みの全駐車場から、オーナー申請をかけたい物件を探すための検索。\n返すのは公開情報のみ（id / 名称 / 住所 / 緯度経度 / `has_owner` フラグ）。\n\n### オーナーポータルでの使用タイミング\n- 「既存の駐車場のオーナー権限を申請する」ウィザードの検索ボックス\n- 自分の物件がすでに登録されていないか名称・住所で確認するとき\n- 申請可否（`has_owner=false`）の事前判定\n\n### 認証・認可\n`requireOwner`（オーナーログインが前提）。ただし返却データは公開情報のみ。\n`has_owner` の集計を正しく行うため、このルートに限り service-role 接続 (`getSql`) で\nRLS をバイパスする（`parking_lot_owners` を全件参照する必要があるため）。\n\n### 挙動・制約\n- `q` で `name` / `address` の ILIKE 部分一致\n- `has_owner` は `EXISTS (SELECT 1 FROM parking_lot_owners ...)` で boolean を返す\n- 並び順は `name ASC` 固定\n- 機微カラム（料金体系・運用メモ・契約情報など）は返さない\n\n### 関連\n- `POST /v1/owner/applications` — ヒットした駐車場に対するオーナー申請を作成",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^\\d+$",
              "description": "1 はじまりのページ番号",
              "examples": [
                "1"
              ]
            },
            "required": false,
            "name": "page",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^\\d+$",
              "description": "1 ページあたりの件数（最大 2000）",
              "examples": [
                "20"
              ]
            },
            "required": false,
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "description": "cursor ページング利用時の不透明トークン。offset ページング（page/limit）とは排他。"
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": false,
            "name": "q",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "一覧",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/OwnerSearchParkingLot"
                      }
                    },
                    "page": {
                      "type": "integer",
                      "minimum": 1
                    },
                    "limit": {
                      "type": "integer",
                      "minimum": 1
                    },
                    "total": {
                      "type": "integer",
                      "minimum": 0
                    },
                    "total_is_estimate": {
                      "type": "boolean",
                      "description": "true のとき total は pg_class.reltuples 由来の概算値（数千行ズレ得る）。exact COUNT のときは field 自体が省略される。"
                    }
                  },
                  "required": [
                    "items",
                    "page",
                    "limit",
                    "total"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingLotsSearch"
      }
    },
    "/v1/owner/parking-lots/mine/{lotId}/area": {
      "patch": {
        "tags": [
          "駐車場 / Parking Lots"
        ],
        "summary": "自分の駐車場の敷地ポリゴンを更新",
        "description": "### 用途\nオーナーポータルの「位置・形状」タブから Mapbox GL Draw で描いた\n敷地ポリゴン (GeoJSON Polygon) を保存する。\nbundle endpoint の `PATCH /mine/{lotId}` では `area` が禁則列のため、\ndedicated endpoint として提供する。\n\n### 認証・認可\n`requireOwner` + `ownerContext()` による RLS 強制。\n`parking_lot_owners.owner_id = current_owner_id()` の RLS が所有権を保証する。\n\n### area クリア\n`area: null` を送ると `parking_lots.area` を NULL にリセットする。\n\n### 挙動・制約\n- 存在しない lotId または所有していない lot は 404 `parking_lot_not_found` を返す\n- GeoJSON の座標精度は DB 側 geometry(Polygon, 4326) に従う (SRID=4326)\n- ST_GeomFromGeoJSON 変換エラーは 400 (invalid_geojson) として返す\n\n### 関連\n- `PATCH /v1/owner/parking-lots/mine/{lotId}` — 基本情報の更新 (area 以外)\n- `GET /v1/owner/parking-lots/mine/{lotId}` — 詳細取得",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "lotId",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OwnerParkingLotAreaPatchBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "更新成功。lot の id を返す。",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OwnerParkingLotAreaPatchResponse"
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "internal_error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingLotsMineAreaUpdate"
      }
    },
    "/v1/owner/parking-lots/mine/{lotId}/date-overrides": {
      "get": {
        "tags": [
          "駐車場 / Parking Lots"
        ],
        "summary": "自分の駐車場の日付オーバーライド一覧",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "lotId",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
            },
            "required": false,
            "name": "from",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
            },
            "required": false,
            "name": "to",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "一覧",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ParkingLotDateOverride"
                      }
                    }
                  },
                  "required": [
                    "items"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingLotsMineDateOverridesList"
      },
      "post": {
        "tags": [
          "駐車場 / Parking Lots"
        ],
        "summary": "自分の駐車場の日付オーバーライドを登録 / 上書き",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "lotId",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DateOverrideUpsertBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "登録 / 更新後",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ParkingLotDateOverride"
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingLotsMineDateOverridesCreate"
      }
    },
    "/v1/owner/parking-lots/mine/{lotId}/date-overrides/{ref}": {
      "patch": {
        "tags": [
          "駐車場 / Parking Lots"
        ],
        "summary": "自分の駐車場の日付オーバーライドを部分更新（date または uuid）",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "lotId",
            "in": "path"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "ref",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DateOverridePatchBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "更新後",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ParkingLotDateOverride"
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingLotsMineDateOverridesUpdate"
      },
      "delete": {
        "tags": [
          "駐車場 / Parking Lots"
        ],
        "summary": "自分の駐車場の日付オーバーライドを削除（date または uuid）",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "lotId",
            "in": "path"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "ref",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "削除成功",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingLotsMineDateOverridesDelete"
      }
    },
    "/v1/owner/parking-lots/mine/{lotId}/discounts": {
      "get": {
        "tags": [
          "駐車場 / Parking Lots"
        ],
        "summary": "自駐車場の割引一覧",
        "description": "### 用途\n自駐車場に登録された有効な割引を一覧表示。Owner Portal の「割引」タブで使う。\nstack_priority ASC + created_at ASC で並べる。\n\n### 認可\n`requireOwner` + `parking_lot_owners` チェック。",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "lotId",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "割引一覧",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OwnerParkingLotDiscountListResponse"
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingLotsMineDiscountsList"
      },
      "post": {
        "tags": [
          "駐車場 / Parking Lots"
        ],
        "summary": "割引を新規登録",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "lotId",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OwnerParkingLotDiscountCreateBody"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "登録後",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OwnerParkingLotDiscount"
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingLotsMineDiscountsCreate"
      }
    },
    "/v1/owner/parking-lots/mine/{lotId}/discounts/{discountId}": {
      "patch": {
        "tags": [
          "駐車場 / Parking Lots"
        ],
        "summary": "割引を部分更新",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "lotId",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "discountId",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OwnerParkingLotDiscountPatchBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "更新後",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OwnerParkingLotDiscount"
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingLotsMineDiscountsUpdate"
      },
      "delete": {
        "tags": [
          "駐車場 / Parking Lots"
        ],
        "summary": "割引を soft-delete",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "lotId",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "discountId",
            "in": "path"
          }
        ],
        "responses": {
          "204": {
            "description": "削除完了 (no body)"
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingLotsMineDiscountsDelete"
      }
    },
    "/v1/owner/parking-lots/mine/{lotId}/hours": {
      "get": {
        "tags": [
          "駐車場 / Parking Lots"
        ],
        "summary": "自分の駐車場の営業時間一覧",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "lotId",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "business",
                "entry",
                "exit",
                "after_hours_exit"
              ],
              "description": "時間窓の種別（codes.category_id=`parking_hours_window_type`）。\n- `business`         : 通常営業時間（既存行はすべてこれ扱い。DEFAULT）\n- `entry`            : 入庫可能時間（夜間入庫不可施設など）\n- `exit`             : 出庫可能時間\n- `after_hours_exit` : 営業時間外の出庫可否フラグ（曜日単位）",
              "examples": [
                "business"
              ]
            },
            "required": false,
            "name": "window_type",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "一覧",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ParkingLotHour"
                  }
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingLotsMineHoursList"
      },
      "put": {
        "tags": [
          "駐車場 / Parking Lots"
        ],
        "summary": "自分の駐車場の営業時間を完全置換",
        "description": "指定 window_type（省略時は全 window_type）に該当する既存行を DELETE → body の hours を INSERT で完全置換する。\nRLS により自分が所有していない lot は 404 / 403 になる。",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "lotId",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ParkingLotHoursReplaceBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "置換後の行一覧",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ParkingLotHour"
                  }
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingLotsMineHoursReplace"
      }
    },
    "/v1/owner/parking-lots/mine/{lotId}/images": {
      "get": {
        "tags": [
          "駐車場 / Parking Lots"
        ],
        "summary": "自分の駐車場の画像一覧",
        "description": "指定 lot の画像を `is_main DESC, sort_order ASC, created_at ASC` で返す。\nRLS により自分の lot 以外は空配列。",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "lotId",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "画像一覧",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/OwnerParkingLotImage"
                  }
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingLotsMineImagesList"
      },
      "post": {
        "tags": [
          "駐車場 / Parking Lots"
        ],
        "summary": "駐車場に画像を追加 / Add Parking Lot Image",
        "description": "事前にアップロード済みの画像アセット (`assets`) を駐車場に紐付ける。\nRLS (parking_lot_images_owner_insert) により、自分の lot 以外への INSERT は拒否される。\nis_main=true を立てた場合、本 endpoint では他画像の is_main を解除しない。\nメイン切替は `PATCH /mine/{lotId}/images/{imageId}/main` を使うこと。",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "lotId",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OwnerParkingLotImageCreateBody"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "追加された画像",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OwnerParkingLotImage"
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingLotsMineImagesCreate"
      }
    },
    "/v1/owner/parking-lots/mine/{lotId}/images/{imageId}": {
      "patch": {
        "tags": [
          "駐車場 / Parking Lots"
        ],
        "summary": "画像メタを部分更新（sort_order / is_main 単独更新）",
        "description": "並び順の入れ替え (`sort_order`) や is_main フラグの単独更新を想定。\nis_main=true へ切替えて他画像の is_main を一括解除したい場合は\n`PATCH /main` (専用 endpoint) を使うこと。本 endpoint は対象 1 行のみ更新する。",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "lotId",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "imageId",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OwnerParkingLotImageUpdateBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "更新後の画像",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OwnerParkingLotImage"
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingLotsMineImagesUpdate"
      },
      "delete": {
        "tags": [
          "駐車場 / Parking Lots"
        ],
        "summary": "画像を削除 / Delete Image",
        "description": "中間レコード (parking_lot_images) のみ DELETE。`assets` 本体は他で参照されている\n可能性があるので残す。当該 lot に属さない imageId / 既に削除済みは 404。",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "lotId",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "imageId",
            "in": "path"
          }
        ],
        "responses": {
          "204": {
            "description": "削除完了"
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingLotsMineImagesDelete"
      }
    },
    "/v1/owner/parking-lots/mine/{lotId}/images/{imageId}/main": {
      "patch": {
        "tags": [
          "駐車場 / Parking Lots"
        ],
        "summary": "画像をメインに設定 / Set Main Image",
        "description": "指定画像を駐車場の唯一のメイン画像 (is_main=true) に切替える。\n同 lot の他画像は自動で is_main=false に落とす（ownerContext の tx 内で 2 文を実行）。\n対象が当該 lot に属していなければ 404。",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "lotId",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "imageId",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "切替成功",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingLotsMineImagesMainUpdate"
      }
    },
    "/v1/owner/parking-lots/mine/{lotId}/pending-fields": {
      "get": {
        "tags": [
          "駐車場 / Parking Lots"
        ],
        "summary": "自分の駐車場で運営審査待ちの編集一覧",
        "description": "### 用途\nオーナーが提出した PATCH の中で、まだ admin 承認されていない field_values を返す。\nオーナー画面の PublicationTab に「N 件の修正が運営審査中」と表示するため。\n\n### オーナーポータルでの使用タイミング\n- 駐車場詳細画面の PublicationTab を開いたとき\n- 編集 PATCH 直後に当該駐車場の申請状況を再取得するとき\n\n### 認証・認可\n`requireOwner` + `ownerContext` で RLS を物理適用。`parking_field_values` の RLS が\n`parking_lot_owners` リンク経由で自オーナーの行のみ見せる。\n\n### 挙動\n- `source='owner' AND approved_at IS NULL AND deleted_at IS NULL` の行を新しい順で返す\n- `parking_field_values` の RLS により、他オーナーの駐車場 ID を渡しても 0 件になる\n\n### 関連\n- `PATCH /v1/owner/parking-lots/mine/{lotId}` — 編集 (この行を生成する側)\n- admin 側の status pending → active 遷移で `approved_at` が一括埋まり pending から消える",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "lotId",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "申請中の field_values",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OwnerPendingFieldsResponse"
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingLotsMinePendingFieldsList"
      }
    },
    "/v1/owner/parking-lots/mine/{lotId}/pricing-groups": {
      "get": {
        "tags": [
          "駐車場 / Parking Lots"
        ],
        "summary": "自分の駐車場の料金 group 一覧",
        "description": "指定 lot の pricing_groups を display_order ASC, code ASC で返す。\nRLS により自分の lot 以外は空配列。",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "lotId",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "一覧",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PricingGroup"
                  }
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingLotsMinePricingGroupsList"
      },
      "post": {
        "tags": [
          "駐車場 / Parking Lots"
        ],
        "summary": "料金 group を新規作成",
        "description": "lot に新しい pricing group を追加する。code は lot 内一意 (citext)。\nis_default=true を指定した場合、既存の default group と衝突すると 409。\ndefault 切替は `PATCH` で既存を false にしてから新規を true にする運用。",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "lotId",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PricingGroupCreateBody"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "作成済み",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PricingGroup"
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingLotsMinePricingGroupsCreate"
      }
    },
    "/v1/owner/parking-lots/mine/{lotId}/pricing-groups/{id}": {
      "patch": {
        "tags": [
          "駐車場 / Parking Lots"
        ],
        "summary": "料金 group を部分更新",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "lotId",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PricingGroupUpdateBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "更新後",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PricingGroup"
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingLotsMinePricingGroupsUpdate"
      },
      "delete": {
        "tags": [
          "駐車場 / Parking Lots"
        ],
        "summary": "料金 group を削除",
        "description": "物理削除 (soft delete 非対応)。参照中の pricing_rules は FK CASCADE で連動削除、\nspots は FK RESTRICT なので参照 spot が居ると 409 (foreign_key_violation)。\ndefault group を削除する前に別 group を default=true にすること。",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "lotId",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "204": {
            "description": "削除完了"
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingLotsMinePricingGroupsDelete"
      }
    },
    "/v1/owner/parking-lots/mine/{lotId}/pricing-groups/{groupId}/rules": {
      "get": {
        "tags": [
          "駐車場 / Parking Lots"
        ],
        "summary": "自分の駐車場 group 内の料金ルール一覧",
        "description": "指定 lot/group 配下の pricing_rules を rule_order ASC で返す。\nRLS により自分の lot 以外は notFound。",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "lotId",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "groupId",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "一覧",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PricingRule"
                  }
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingLotsMinePricingGroupsRulesList"
      },
      "post": {
        "tags": [
          "駐車場 / Parking Lots"
        ],
        "summary": "料金ルールを 1 件追加",
        "description": "指定 group に新しい pricing rule を 1 件追加する。\nrule_order を省略した場合は 0 が入るので、必要に応じて呼出側で連番管理すること。\n上限設定は nested `cap` で表現。`cap=null` (または省略) は上限なし。",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "lotId",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "groupId",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PricingRuleCreateBody"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "作成済み",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PricingRule"
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingLotsMinePricingGroupsRulesCreate"
      },
      "put": {
        "tags": [
          "駐車場 / Parking Lots"
        ],
        "summary": "group 内の料金ルールを丸ごと置き換え",
        "description": "指定 group 配下の pricing_rules を全削除 → 一括 INSERT する。差分更新ではなく **完全置換**。\nrule_order を省略した行はリクエスト配列のインデックスを採用。\n空配列を渡すと「料金ルールなし」状態になる（DELETE のみ実行）。\n各 rule の `cap` は null=上限なし / object=上限あり。",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "lotId",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "groupId",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PricingRuleReplaceBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "置換後の rule 集合",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer"
                    },
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PricingRule"
                      }
                    }
                  },
                  "required": [
                    "count",
                    "items"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingLotsMinePricingGroupsRulesReplace"
      }
    },
    "/v1/owner/parking-lots/mine/{lotId}/pricing-groups/{groupId}/rules/{ruleId}": {
      "patch": {
        "tags": [
          "駐車場 / Parking Lots"
        ],
        "summary": "料金ルールを部分更新",
        "description": "指定 1 件の rule を部分更新する。pricing_group_id の付け替えは本 endpoint では不可\n（group 跨ぎの移動は DELETE → POST、あるいは group 単位の PUT を使う）。\n`cap` の扱い: 省略=変更しない / null=上限削除 / object=上限 upsert。",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "lotId",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "groupId",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "ruleId",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PricingRuleUpdateBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "更新後",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PricingRule"
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingLotsMinePricingGroupsRulesUpdate"
      },
      "delete": {
        "tags": [
          "駐車場 / Parking Lots"
        ],
        "summary": "料金ルールを削除",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "lotId",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "groupId",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "ruleId",
            "in": "path"
          }
        ],
        "responses": {
          "204": {
            "description": "削除完了"
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingLotsMinePricingGroupsRulesDelete"
      }
    },
    "/v1/owner/parking-lots/mine/{lotId}/tags": {
      "get": {
        "tags": [
          "駐車場 / Parking Lots"
        ],
        "summary": "自分の駐車場の付与済みタグ一覧",
        "description": "指定 lot に付与済みのタグを `tags.sort_order ASC, name ASC` で返す。\nRLS により自分の lot 以外は空配列。\n`is_owner_editable=true` のタグのみ Owner Portal から編集可能。",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "lotId",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "付与済みタグ一覧",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/OwnerLotTag"
                  }
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingLotsMineTagsList"
      }
    },
    "/v1/owner/parking-lots/mine/{lotId}/tags/{tagCode}": {
      "put": {
        "tags": [
          "駐車場 / Parking Lots"
        ],
        "summary": "タグを付与（べき等）",
        "description": "指定 lot に tag_code のタグを付与する（既に付与済みでも正常終了 = べき等）。\n- `is_owner_editable=false` のタグへの操作は 403 で拒否\n- 未知の `tag_code` は 400 で拒否\n- state は常に `true` で UPSERT される",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "lotId",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64,
              "pattern": "^[a-z][a-z0-9_]*$",
              "description": "付与するタグの slug",
              "examples": [
                "ev_charging"
              ]
            },
            "required": true,
            "name": "tagCode",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "付与成功",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingLotsMineTagsReplace"
      },
      "delete": {
        "tags": [
          "駐車場 / Parking Lots"
        ],
        "summary": "タグを削除（べき等）",
        "description": "指定 lot から tag_code のタグを削除する（付与されていない場合も 204 = べき等）。\n- `is_owner_editable=false` のタグへの操作は 403 で拒否\n- 未知の `tag_code` は 400 で拒否",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "lotId",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64,
              "pattern": "^[a-z][a-z0-9_]*$",
              "description": "削除するタグの slug",
              "examples": [
                "ev_charging"
              ]
            },
            "required": true,
            "name": "tagCode",
            "in": "path"
          }
        ],
        "responses": {
          "204": {
            "description": "削除成功（べき等）"
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingLotsMineTagsDelete"
      }
    },
    "/v1/owner/parking-spots": {
      "get": {
        "tags": [
          "parking-spots"
        ],
        "summary": "自分の駐車場の車室一覧",
        "description": "指定 `lot_id` の parking_spots 一覧を返す。RLS により自分が所有する lot 以外は空配列。\n既定で soft-deleted (`deleted_at IS NOT NULL`) は除外。\n`include_deleted=true` で含める (ゴミ箱 UI 用)。\n並び順は code ASC。",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "lot_id",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ]
            },
            "required": false,
            "name": "include_deleted",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "一覧",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ParkingSpot"
                  }
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingSpotsList"
      },
      "post": {
        "tags": [
          "parking-spots"
        ],
        "summary": "車室を新規作成",
        "description": "オーナー所有の lot に車室を新規登録する。RLS により他人の lot は INSERT 拒否。\n`pricing_group_id` は指定 lot に属する group である必要がある (DB CHECK なしのためサーバー側で検証)。\ncode は lot 内で大小無関係一意。",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ParkingSpotCreateBody"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "作成済み",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ParkingSpot"
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingSpotsCreate"
      }
    },
    "/v1/owner/parking-spots/{id}": {
      "get": {
        "tags": [
          "parking-spots"
        ],
        "summary": "車室 1 件取得",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "1 件",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ParkingSpot"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingSpotsGet"
      },
      "patch": {
        "tags": [
          "parking-spots"
        ],
        "summary": "車室を部分更新",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ParkingSpotUpdateBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "更新後",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ParkingSpot"
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingSpotsUpdate"
      },
      "delete": {
        "tags": [
          "parking-spots"
        ],
        "summary": "車室を soft delete",
        "description": "`deleted_at` に現在時刻をセット。物理削除は行わない (session 履歴保護のため)。\n参照中の parking_sessions はそのまま残る (FK は ON DELETE SET NULL だが soft delete では発火しない)。",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "204": {
            "description": "削除完了"
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerParkingSpotsDelete"
      }
    },
    "/v1/owner/authority-requests/mine": {
      "get": {
        "tags": [
          "authority-requests"
        ],
        "summary": "自分が出した管理権限申請の一覧",
        "description": "### 用途\nログイン中オーナーが過去に提出した「既存駐車場への管理権限申請」を一覧で返す。\nステータス（`new` / `in_progress` / `approved` / `rejected`）と却下理由を含む。\n\n### オーナーポータルでの使用タイミング\n- 「申請一覧」画面の初期表示・ページング操作\n- ダッシュボードでの「審査中の申請」件数バッジ\n- 却下された申請の `reject_reason` 確認 → 再申請判断\n\n### 認証・認可\n`requireOwner`。`owner_applications.owner_id = current_owner_id()` に RLS で厳密スコープ。\n他オーナーの申請は一切返さない。\n\n### 挙動・制約\n- 並び順は `created_at DESC` 固定\n- ステータスは admin 側 `/v1/admin/authority-requests/{id}/approve` で `approved` に遷移\n- ページングは `PageQuerySchema`\n\n### 関連\n- `POST /v1/owner/authority-requests` — 新規申請\n- `GET /v1/owner/parking-lots/search` — 申請対象の駐車場を探す",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^\\d+$",
              "description": "1 はじまりのページ番号",
              "examples": [
                "1"
              ]
            },
            "required": false,
            "name": "page",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^\\d+$",
              "description": "1 ページあたりの件数（最大 2000）",
              "examples": [
                "20"
              ]
            },
            "required": false,
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "description": "cursor ページング利用時の不透明トークン。offset ページング（page/limit）とは排他。"
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "一覧",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/OwnerApplication"
                      }
                    },
                    "page": {
                      "type": "integer",
                      "minimum": 1
                    },
                    "limit": {
                      "type": "integer",
                      "minimum": 1
                    },
                    "total": {
                      "type": "integer",
                      "minimum": 0
                    },
                    "total_is_estimate": {
                      "type": "boolean",
                      "description": "true のとき total は pg_class.reltuples 由来の概算値（数千行ズレ得る）。exact COUNT のときは field 自体が省略される。"
                    }
                  },
                  "required": [
                    "items",
                    "page",
                    "limit",
                    "total"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerAuthorityRequestsMine"
      }
    },
    "/v1/owner/authority-requests": {
      "post": {
        "tags": [
          "authority-requests"
        ],
        "summary": "管理権限申請を作成（proof_asset_id 必須）",
        "description": "### 用途\n既存駐車場に対し「自分がオーナーである」ことの審査申請を提出する。\n書面証明（登記簿・契約書スキャン等）を `proof_asset_id` で必ず添付する。\n\n### オーナーポータルでの使用タイミング\n- 「管理権限の申請」ウィザード最終ステップの送信時\n- ステップ前に `/v1/storage` で書面 PDF をアップロードして asset id を取得 → このAPIに渡す\n\n### 認証・認可\n`requireOwner`。作成される `owner_applications.owner_id` はリクエスト元 owner で固定される。\n`owner_name` / `owner_email` / `company_name` は申請書面と照合するために別途入力。\n\n### 挙動・制約\n- 同じ owner × parking_lot で `status IN ('new', 'in_progress')` の申請が既にある場合は\n  `owner_application_duplicate` を返す（重複申請禁止）\n- 初期 `status='new'` で作成。admin 側で `in_progress` → `approved` / `rejected` に遷移\n- `approved` 時には admin 側が `parking_lot_owners` を 1 行追加するだけで、\n  新規アカウント発行や追加メール送信は発生しない（既ログインオーナー前提）\n\n### 関連\n- `GET /v1/owner/authority-requests/mine` — 自分の申請一覧",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "parking_lot_id": {
                    "type": "string",
                    "format": "uuid",
                    "examples": [
                      "00000000-0000-0000-0000-000000000000"
                    ]
                  },
                  "proof_asset_id": {
                    "type": "string",
                    "format": "uuid",
                    "examples": [
                      "00000000-0000-0000-0000-000000000000"
                    ]
                  },
                  "owner_name": {
                    "type": "string",
                    "minLength": 1
                  },
                  "owner_email": {
                    "type": "string",
                    "format": "email"
                  },
                  "company_name": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "additional_notes": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "required": [
                  "parking_lot_id",
                  "proof_asset_id",
                  "owner_name",
                  "owner_email"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "作成済み",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OwnerApplication"
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "unprocessable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerAuthorityRequestsCreate"
      }
    },
    "/v1/owner/reviews/mine": {
      "get": {
        "tags": [
          "レビュー / Reviews"
        ],
        "summary": "レビュー一覧 / My Lot Reviews",
        "description": "### 用途\nオーナー所有の駐車場に投稿されたユーザーレビューを一覧表示する。\n返信状況・ステータス・対象駐車場でフィルタ可能で、未返信レビューのオーナー対応導線を担う。\n\n### オーナーポータルでの使用タイミング\n- 「レビュー管理」画面の初期表示（`reply_state=unreplied` で未対応のみ）\n- 駐車場詳細画面の「最新レビュー」ウィジェット\n- 公開／非公開ステータスでの絞り込み表示\n\n### 認証・認可\n`requireOwner`。`parking_reviews` を `parking_lot_owners` で INNER JOIN し、\nRLS により parking_lot_owners が current_owner_id() に絞られるので自オーナー分のみ返る。\n他オーナーの駐車場レビューは構造的に取得できない。\n\n### 挙動・制約\n- `parking_lot_id` 指定で単一物件に絞り込み（自分が所有する物件 ID のみ意味を持つ）\n- `status` でレビューの承認状態フィルタ\n- `reply_state=unreplied`: `owner_reply IS NULL` / `replied`: `owner_reply IS NOT NULL`\n- 並び順は `created_at DESC` 固定\n- レスポンスに `parking_lot.{id,name}` を埋め込む（一覧で物件名を表示するため）\n\n### 関連\n- `POST /v1/owner/reviews/{reviewId}/reply` — レビューへの返信投稿・上書き・削除",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^\\d+$",
              "description": "1 はじまりのページ番号",
              "examples": [
                "1"
              ]
            },
            "required": false,
            "name": "page",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^\\d+$",
              "description": "1 ページあたりの件数（最大 2000）",
              "examples": [
                "20"
              ]
            },
            "required": false,
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "description": "cursor ページング利用時の不透明トークン。offset ページング（page/limit）とは排他。"
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": false,
            "name": "parking_lot_id",
            "in": "query"
          },
          {
            "schema": {
              "$ref": "#/components/schemas/ReviewStatus"
            },
            "required": false,
            "name": "status",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "all",
                "unreplied",
                "replied"
              ]
            },
            "required": false,
            "name": "reply_state",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "一覧",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/OwnerReview"
                      }
                    },
                    "page": {
                      "type": "integer",
                      "minimum": 1
                    },
                    "limit": {
                      "type": "integer",
                      "minimum": 1
                    },
                    "total": {
                      "type": "integer",
                      "minimum": 0
                    },
                    "total_is_estimate": {
                      "type": "boolean",
                      "description": "true のとき total は pg_class.reltuples 由来の概算値（数千行ズレ得る）。exact COUNT のときは field 自体が省略される。"
                    }
                  },
                  "required": [
                    "items",
                    "page",
                    "limit",
                    "total"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerReviewsMine"
      }
    },
    "/v1/owner/reviews/{reviewId}/reply": {
      "post": {
        "tags": [
          "レビュー / Reviews"
        ],
        "summary": "レビューに返信 / Reply to Review",
        "description": "### 用途\nオーナー所有駐車場のレビューに対するオーナー返信を作成・上書き・削除する。\n1 レビュー = 1 返信モデル。`parking_reviews.owner_reply` に文字列を保存し、投稿時刻と投稿者 owner_id も合わせて記録。\n\n### オーナーポータルでの使用タイミング\n- レビュー詳細モーダルの「返信を送信」ボタン\n- 既存返信の編集（同じエンドポイントに新しい本文を投げる）\n- 返信削除（`owner_reply: null` を送信）\n\n### 認証・認可\n`requireOwner`。`parking_reviews` × `parking_lot_owners` の INNER JOIN で\n対象レビューが自オーナー所有駐車場のものか検証し、外れていれば `owner_review_not_for_your_lot`。\n\n### 挙動・制約\n- `owner_reply` が文字列: `owner_replied_at = NOW()` / `owner_replied_by = current owner_id` を同時更新\n- `owner_reply` が `null`: `owner_replied_at` / `owner_replied_by` も NULL クリア（返信削除相当）\n- `updated_at` も常に NOW() で更新\n- レビュー本体（`rating` / `comment` / `status`）は変更しない\n- 該当レビューが消えていれば `not_found`\n\n### 関連\n- `GET /v1/owner/reviews/mine` — 一覧（未返信フィルタで対応待ちを抽出）",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "reviewId",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "owner_reply": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "required": [
                  "owner_reply"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "更新後",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OwnerReview"
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "unprocessable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerReviewsReply"
      }
    },
    "/v1/owner/boosts": {
      "get": {
        "tags": [
          "ブースト / Boosts"
        ],
        "summary": "ブースト一覧 / My Boosts",
        "description": "### 用途\nオーナーが自分の駐車場に対して設定しているブースト（有料の検索結果上位化）の一覧を返す。\n予算・配信状況（`status`）・累計インプレッション/クリック/セッションを含む運用ダッシュボード用データ。\n\n### オーナーポータルでの使用タイミング\n- 「ブースト管理」画面の初期表示・ページング\n- 駐車場別フィルタでの配信状況確認\n- 配信中（`status='active'`）／停止中（`paused` / `ended`）の切替表示\n\n### 認証・認可\n`requireOwner`。`boosts.owner_id = current_owner_id()` に固定スコープ（RLS）。\nadmin 側 `/v1/admin/boosts` は全オーナー横断だが、本ルートは自分の owner_id 配下のみ。\n\n### 挙動・制約\n- `parking_lot_id` / `status` でフィルタ\n- 並び順は `created_at DESC` 固定\n- `credit_per_impression` / `daily_budget` / `total_budget` は NULL 許可（無制限運用）\n\n### 関連\n- `POST /v1/owner/boosts` — 新規作成\n- `PATCH /v1/owner/boosts/{id}` — 編集（停止 / 予算変更）\n- `GET /v1/owner/boosts/{id}/stats` — 配信統計とクレジット消費",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^\\d+$",
              "description": "1 はじまりのページ番号",
              "examples": [
                "1"
              ]
            },
            "required": false,
            "name": "page",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^\\d+$",
              "description": "1 ページあたりの件数（最大 2000）",
              "examples": [
                "20"
              ]
            },
            "required": false,
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "description": "cursor ページング利用時の不透明トークン。offset ページング（page/limit）とは排他。"
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": false,
            "name": "parking_lot_id",
            "in": "query"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": false,
            "name": "status",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "stats"
              ]
            },
            "required": false,
            "name": "include",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "一覧",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/OwnerBoostWithStats"
                      }
                    },
                    "page": {
                      "type": "integer",
                      "minimum": 1
                    },
                    "limit": {
                      "type": "integer",
                      "minimum": 1
                    },
                    "total": {
                      "type": "integer",
                      "minimum": 0
                    },
                    "total_is_estimate": {
                      "type": "boolean",
                      "description": "true のとき total は pg_class.reltuples 由来の概算値（数千行ズレ得る）。exact COUNT のときは field 自体が省略される。"
                    }
                  },
                  "required": [
                    "items",
                    "page",
                    "limit",
                    "total"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerBoostsList"
      },
      "post": {
        "tags": [
          "ブースト / Boosts"
        ],
        "summary": "ブーストを作成 / Create Boost",
        "description": "### 用途\n指定駐車場に対する新しいブーストキャンペーンを登録する。クレジットを消費して検索結果に\n優先表示するための配信枠で、予算とインプレッション単価を後から PATCH で調整できる。\n\n### オーナーポータルでの使用タイミング\n- 「ブースト作成」ウィザード最終ステップの送信時\n- 駐車場詳細画面の「上位表示する」CTA\n\n### 認証・認可\n`requireOwner`。送信された `parking_lot_id` が自オーナー所有か `parking_lot_owners` で照合し、\n外れていれば `owner_not_lot_owner`。`owner_id` はサーバー側で強制上書き（クライアント指定は無視）。\n\n### 挙動・制約\n- 配信開始時刻・予算等は `OwnerBoostCreateBody` の allowlist（主要列は型明示）\n- 作成時点では実際のクレジット引落しは発生しない（インプレッション発生時に `credit_transactions` で消費）\n- 残高不足ハンドリングはインプレッション発生フロー側の責務\n\n### 関連\n- `PATCH /v1/owner/boosts/{id}` — 予算・期間・状態の更新\n- `GET /v1/owner/credits/balance` — 事前残高確認",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OwnerBoostCreateBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "作成済み",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OwnerBoost"
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "unprocessable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerBoostsCreate"
      }
    },
    "/v1/owner/boosts/{id}": {
      "patch": {
        "tags": [
          "ブースト / Boosts"
        ],
        "summary": "ブーストを更新 / Update Boost",
        "description": "### 用途\n既存ブーストの編集。配信停止（`status='paused'` / `'ended'`）・予算引き上げ・\n単価調整・配信期間変更などの運用操作を一括で受け付ける。\n\n### オーナーポータルでの使用タイミング\n- 「停止」「再開」ボタンの押下\n- 予算引き上げモーダルの送信時\n- インプレッション単価の調整スライダー操作\n\n### 認証・認可\n`requireOwner`。RLS により自オーナーの boosts しか見えないので、\n行が無ければ `owner_boost_not_found`（存在隠蔽）。\n\n### 挙動・制約\n- 禁則カラム: `id` / `owner_id` / `created_at` / `impressions` / `clicks` / `sessions`（集計値はサーバ側のみ更新）\n- body は `OwnerBoostUpdateBody` の strict allowlist。zod schema が SSoT で、未定義キーは 400 (zod validation error) で reject\n- 空ボディは現行値を返して終わる（冪等）\n\n### 関連\n- `GET /v1/owner/boosts/{id}/stats` — 集計値の最新値取得",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OwnerBoostUpdateBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "更新後",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OwnerBoost"
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "unprocessable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerBoostsUpdate"
      }
    },
    "/v1/owner/boosts/{id}/stats": {
      "get": {
        "tags": [
          "ブースト / Boosts"
        ],
        "summary": "ブースト統計 / Boost Stats",
        "description": "### 用途\n単一ブーストの累計配信実績とクレジット消費量を返す。`boosts` テーブル上のカウンタと、\n`credit_transactions` の `boost_id` 紐付け消費（負の `amount`）を SUM して算出する。\n\n### オーナーポータルでの使用タイミング\n- ブースト詳細画面のサマリカード表示\n- ダッシュボードの「配信中ブースト」カード（CTR や予算消化率の計算）\n- 配信終了後のレポート表示\n\n### 認証・認可\n`requireOwner`。RLS により自オーナー分のみ可視。外れていれば `owner_boost_not_found`。\n他オーナーのブースト統計は構造的に取得不可。\n\n### 挙動・制約\n- `credit_consumed` は `SUM(-amount)` over `credit_transactions WHERE boost_id = ? AND amount < 0`\n- `impressions` / `clicks` / `sessions` が NULL の場合は 0 を返す（COALESCE）\n- 配信が無いブーストでも 0 埋めで返却（UI 側の null チェック不要）\n\n### 関連\n- `GET /v1/owner/credits/transactions` — クレジット消費の明細（boost_id で逆引き可）",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "examples": [
                "00000000-0000-0000-0000-000000000000"
              ]
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "統計",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "boost_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "impressions": {
                      "type": "integer"
                    },
                    "clicks": {
                      "type": "integer"
                    },
                    "sessions": {
                      "type": "integer"
                    },
                    "credit_consumed": {
                      "type": "integer"
                    }
                  },
                  "required": [
                    "boost_id",
                    "impressions",
                    "clicks",
                    "sessions",
                    "credit_consumed"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerBoostsStats"
      }
    },
    "/v1/owner/credits/balance": {
      "get": {
        "tags": [
          "クレジット / Credits"
        ],
        "summary": "クレジット残高 / Credit Balance",
        "description": "### 用途\nログイン中オーナーのクレジット残高（`balance`）と累計購入額・累計消費額を返す。\nブースト課金の財布。`owner_credits` テーブル 1 行を引いて返すだけのシンプルな参照。\n\n### オーナーポータルでの使用タイミング\n- ヘッダーの残高インジケータ表示\n- ダッシュボードの「クレジット残高」カード\n- ブースト作成前の残高チェック（不足ならチャージ導線へ誘導）\n\n### 認証・認可\n`requireOwner`。`owner_credits.owner_id = current_owner_id()` に RLS で厳密スコープ。\n他オーナーの残高は一切返さない。\n\n### 挙動・制約\n- `owner_credits` 行が未生成のオーナーでも 200 を返し、すべて 0 のレスポンスを合成（UI 側の null チェック不要）\n- 残高更新は `credit_transactions` 投入時のトリガで `balance_after` から伝播する設計\n\n### 関連\n- `GET /v1/owner/credits/transactions` — 残高変動の明細\n- `POST /v1/owner/credits/checkout-session` — Stripe チャージ",
        "responses": {
          "200": {
            "description": "残高",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "owner_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "balance": {
                      "type": "integer"
                    },
                    "total_purchased": {
                      "type": "integer"
                    },
                    "total_consumed": {
                      "type": "integer"
                    }
                  },
                  "required": [
                    "owner_id",
                    "balance",
                    "total_purchased",
                    "total_consumed"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerCreditsBalanceList"
      }
    },
    "/v1/owner/credits/transactions": {
      "get": {
        "tags": [
          "クレジット / Credits"
        ],
        "summary": "クレジット取引履歴 / Credit Transaction History",
        "description": "### 用途\nクレジット残高の変動明細。チャージ（正の `amount`）・ブースト消費（負の `amount`）・運営調整を\n時系列で返し、`balance_after` で各時点の残高遷移を追跡できる。\n\n### オーナーポータルでの使用タイミング\n- 「クレジット明細」画面の初期表示・ページング\n- ブースト詳細から逆引き（`boost_id` でフィルタ表示する想定）\n- 経理向け CSV エクスポート前のプレビュー\n\n### 認証・認可\n`requireOwner`。`credit_transactions.owner_id = current_owner_id()` で RLS により厳密スコープ。\n\n### 挙動・制約\n- 並び順は `created_at DESC` 固定\n- `boost_id` は消費取引のみ非 NULL\n- `type` は `purchase` / `consumption` / `adjustment` / `refund` / `gift` などのコード値\n- ページングは `PageQuerySchema`\n\n### 関連\n- `GET /v1/owner/credits/balance` — サマリ残高\n- `GET /v1/owner/boosts/{id}/stats` — 個別ブーストの消費合計",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^\\d+$",
              "description": "1 はじまりのページ番号",
              "examples": [
                "1"
              ]
            },
            "required": false,
            "name": "page",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^\\d+$",
              "description": "1 ページあたりの件数（最大 2000）",
              "examples": [
                "20"
              ]
            },
            "required": false,
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "description": "cursor ページング利用時の不透明トークン。offset ページング（page/limit）とは排他。"
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "履歴",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/OwnerCreditTxn"
                      }
                    },
                    "page": {
                      "type": "integer",
                      "minimum": 1
                    },
                    "limit": {
                      "type": "integer",
                      "minimum": 1
                    },
                    "total": {
                      "type": "integer",
                      "minimum": 0
                    },
                    "total_is_estimate": {
                      "type": "boolean",
                      "description": "true のとき total は pg_class.reltuples 由来の概算値（数千行ズレ得る）。exact COUNT のときは field 自体が省略される。"
                    }
                  },
                  "required": [
                    "items",
                    "page",
                    "limit",
                    "total"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "ownerCreditsTransactionsList"
      }
    },
    "/v1/owner/credits/checkout-session": {
      "post": {
        "tags": [
          "クレジット / Credits"
        ],
        "summary": "クレジット購入用 Stripe Checkout セッション URL",
        "description": "### 用途\nクレジット購入用の Stripe Checkout セッションを発行する。Owner Portal は\n返却された `url` を新規タブで開き、ユーザーは Stripe 上でカード入力を完了する。\n決済完了後の入金は本エンドポイントではなく webhook (`/v1/webhooks/stripe`) で\n`credit_transactions` に書き込まれる。\n\n### オーナーポータルでの使用タイミング\n- 「クレジットを購入」モーダルの「Checkout へ」ボタン押下時\n- 残高不足アラートからのチャージ導線\n\n### 認証・認可\n`requireOwner`。session の `client_reference_id` にリクエスト元 owner ID を埋め込み、\nwebhook 側で `credit_transactions.owner_id` と整合させる。\n\n### 挙動・制約\n- 単価は `STRIPE_PRICE_PER_CREDIT_JPY` 環境変数で決定（未設定時は 1 CR = 1 JPY）\n- success_url / cancel_url は `OWNER_PORTAL_BASE_URL/owner/credits` に戻る\n- Stripe 側は冪等性キー無しで動かす（重複押下対策は UI 側の disabled 制御）\n- `STRIPE_SECRET_KEY` 未設定なら 503 `stripe_not_configured` を返す\n\n### 関連\n- `GET /v1/owner/credits/balance` — チャージ後の残高確認\n- `GET /v1/owner/credits/transactions` — チャージ反映後の明細確認\n- `POST /v1/webhooks/stripe` — Stripe からの入金通知 (webhook)",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "credits": {
                    "type": "integer",
                    "exclusiveMinimum": 0,
                    "maximum": 1000000
                  }
                },
                "required": [
                  "credits"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Checkout Session URL",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OwnerCreditCheckoutSession"
                }
              }
            }
          },
          "400": {
            "description": "validation_error / bad_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "unprocessable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "bad_gateway",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Stripe 未設定",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "request_id": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message",
                        "request_id"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        },
        "operationId": "ownerCreditsCheckoutSessionCreate"
      }
    }
  },
  "webhooks": {}
}
