{"openapi":"3.1.0","info":{"title":"Parky API","version":"0.1.0","description":"## 日本語\nParky BFF — Cloudflare Workers 上で動作する `/v1/*` API。モバイル・管理ポータル・公開 Web のすべてのクライアントがこの API のみを叩く。\n\n## English\nParky BFF — the `/v1/*` API running on Cloudflare Workers. Every client (mobile, admin portal, public web) hits only this API.\n\n> Route summaries / descriptions are primarily in Japanese. An English overlay is applied when the docs page language is switched to EN — see `docs/i18n/openapi-en-overlay.json` for current coverage."},"servers":[{"url":"https://dev-api.parky.co.jp","description":"Dev"},{"url":"https://api.parky.co.jp","description":"Production"},{"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":{"CodeRow":{"type":"object","properties":{"category_id":{"type":"string"},"code":{"type":"string"},"display_label":{"type":"string"},"lang":{"type":"string"},"sort_order":{"type":"integer"},"metadata":{"type":"object","nullable":true,"additionalProperties":{"nullable":true}}},"required":["category_id","code","display_label","lang","sort_order","metadata"]},"CodesResponse":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/CodeRow"}},"lang":{"type":"string"}},"required":["items","lang"]},"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","example":"not_found"},"message":{"type":"string","example":"Not Found"},"request_id":{"type":"string","example":"7d4e5…-…"}},"required":["code","message","request_id"]}},"required":["error"]},"Me":{"type":"object","properties":{"user_id":{"type":"string","format":"uuid"},"email":{"type":"string","nullable":true},"app_user":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"display_name":{"type":"string","nullable":true},"status":{"type":"string"},"created_at":{"type":"string"}},"required":["id","display_name","status","created_at"]},"admin":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","nullable":true},"status":{"type":"string"}},"required":["id","name","status"]}},"required":["user_id","email","app_user","admin"]},"MeUpdate":{"type":"object","properties":{"display_name":{"type":"string","minLength":1,"maxLength":100}}},"SavedParkingLot":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"user_id":{"type":"string","format":"uuid"},"parking_lot_id":{"type":"string","format":"uuid"},"created_at":{"type":"string"}},"required":["id","user_id","parking_lot_id","created_at"]},"UserVehicle":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"user_id":{"type":"string","format":"uuid"},"vehicle_type":{"type":"string"},"nickname":{"type":"string","nullable":true},"plate_number":{"type":"string","nullable":true},"color":{"type":"string","nullable":true},"is_default":{"type":"boolean"},"created_at":{"type":"string"}},"required":["id","user_id","vehicle_type","nickname","plate_number","color","is_default","created_at"]},"SearchQueryV1":{"type":"object","properties":{"v":{"type":"number","enum":[1],"description":"スキーマバージョン","example":1},"center":{"type":"object","properties":{"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180},"placeName":{"type":"string","maxLength":200}},"required":["lat","lng"]},"radius_m":{"type":"integer","minimum":0,"exclusiveMinimum":true,"maximum":50000},"price_min":{"type":"integer","nullable":true,"minimum":0,"maximum":100000},"price_max":{"type":"integer","nullable":true,"minimum":0,"maximum":100000},"attributes":{"type":"array","items":{"type":"string","enum":["24h","max_fee","reservable","oversized_ok","ev_charging","barrier_free","motorcycle_ok","covered"]},"maxItems":20},"difficulty":{"type":"array","items":{"type":"string","enum":["easy","normal","hard"]},"maxItems":3},"operator_codes":{"type":"array","items":{"type":"string","maxLength":50},"maxItems":50},"vehicle":{"type":"object","properties":{"height_m":{"type":"number","nullable":true,"minimum":0,"exclusiveMinimum":true,"maximum":10},"width_m":{"type":"number","nullable":true,"minimum":0,"exclusiveMinimum":true,"maximum":5},"length_m":{"type":"number","nullable":true,"minimum":0,"exclusiveMinimum":true,"maximum":20},"weight_t":{"type":"number","nullable":true,"minimum":0,"exclusiveMinimum":true,"maximum":50},"clearance_cm":{"type":"integer","nullable":true,"minimum":0,"maximum":100}}},"keywords":{"type":"array","items":{"type":"string","minLength":1,"maxLength":50},"maxItems":10},"meter_ticket_included":{"type":"boolean"},"sort":{"type":"string","enum":["distance","price","recommended"]}},"additionalProperties":false},"SearchPreset":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"user_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"query_json":{"$ref":"#/components/schemas/SearchQueryV1"},"is_default":{"type":"boolean"},"sort_order":{"type":"integer"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","user_id","name","query_json","is_default","sort_order","created_at","updated_at"]},"ParkingSession":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"user_id":{"type":"string","format":"uuid"},"parking_lot_id":{"type":"string","format":"uuid"},"vehicle_type":{"type":"string","nullable":true},"status":{"type":"string"},"start_at":{"type":"string","nullable":true},"end_at":{"type":"string","nullable":true},"fee_amount":{"type":"integer","nullable":true},"memo":{"type":"string","nullable":true},"personal_rating":{"type":"string","nullable":true}},"required":["id","user_id","parking_lot_id","vehicle_type","status","start_at","end_at","fee_amount","memo","personal_rating"]},"MyReview":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"parking_lot_id":{"type":"string","format":"uuid"},"user_id":{"type":"string","format":"uuid"},"rating":{"type":"integer","minimum":1,"maximum":5},"comment":{"type":"string","nullable":true},"status":{"type":"string"},"created_at":{"type":"string"}},"required":["id","parking_lot_id","user_id","rating","comment","status","created_at"]},"PublicReview":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"parking_lot_id":{"type":"string","format":"uuid"},"user_id":{"type":"string","nullable":true,"format":"uuid"},"user_name":{"type":"string"},"rating":{"type":"integer","minimum":1,"maximum":5},"comment":{"type":"string","nullable":true},"status":{"type":"string"},"created_at":{"type":"string"}},"required":["id","parking_lot_id","user_id","user_name","rating","comment","status","created_at"]},"UserNotification":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"body":{"type":"string"},"type":{"type":"string"},"target":{"type":"string"},"status":{"type":"string"},"scheduled_at":{"type":"string","nullable":true},"sent_at":{"type":"string","nullable":true},"created_at":{"type":"string"}},"required":["id","title","body","type","target","status","scheduled_at","sent_at","created_at"]},"UserPushToken":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"user_id":{"type":"string","format":"uuid"},"fcm_token":{"type":"string"},"device_type":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","user_id","fcm_token","device_type","created_at","updated_at"]},"MyExp":{"type":"object","properties":{"total_exp":{"type":"integer"},"level":{"type":"integer"},"next_level_exp":{"type":"integer","nullable":true},"exp_to_next_level":{"type":"integer","nullable":true}},"required":["total_exp","level","next_level_exp","exp_to_next_level"]},"MyBadge":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"badge_id":{"type":"string","format":"uuid"},"earned_at":{"type":"string"},"badge":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"icon":{"type":"string"},"category":{"type":"string"}},"required":["id","name","description","icon","category"]}},"required":["id","badge_id","earned_at","badge"]},"MyBadgeProgress":{"type":"object","properties":{"badge_id":{"type":"string","format":"uuid"},"count":{"type":"integer"},"threshold":{"type":"integer"},"percent":{"type":"number"},"badge":{"type":"object","nullable":true,"properties":{"name":{"type":"string"},"description":{"type":"string"},"icon":{"type":"string"},"category":{"type":"string"}},"required":["name","description","icon","category"]}},"required":["badge_id","count","threshold","percent","badge"]},"ThemeListItem":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"is_free":{"type":"boolean"},"price_yen":{"type":"integer","nullable":true},"preview_asset_id":{"type":"string","nullable":true,"format":"uuid"},"sort_order":{"type":"integer"}},"required":["id","name","description","is_free","price_yen","preview_asset_id","sort_order"]},"MyTheme":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"theme_id":{"type":"string","format":"uuid"},"acquired_at":{"type":"string"},"acquisition_type":{"type":"string"},"theme":{"$ref":"#/components/schemas/ThemeListItem"}},"required":["id","theme_id","acquired_at","acquisition_type","theme"]},"SubscriptionPlan":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"code":{"type":"string"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"price_minor":{"type":"integer"},"currency":{"type":"string"},"billing_period":{"type":"string"},"accent_color":{"type":"string","nullable":true},"features":{"nullable":true},"sort_order":{"type":"integer"}},"required":["id","code","name","description","price_minor","currency","billing_period","accent_color","sort_order"]},"MySubscription":{"type":"object","properties":{"id":{"type":"string","nullable":true,"format":"uuid"},"plan_id":{"type":"string","nullable":true,"format":"uuid"},"plan":{"$ref":"#/components/schemas/SubscriptionPlan"},"status":{"type":"string","nullable":true},"started_at":{"type":"string","nullable":true},"ended_at":{"type":"string","nullable":true}},"required":["id","plan_id","plan","status","started_at","ended_at"]},"VerifyIapResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"user_id":{"type":"string","format":"uuid"},"plan_id":{"type":"string","format":"uuid"},"status":{"type":"string"},"started_at":{"type":"string"},"ended_at":{"type":"string","nullable":true},"external_subscription_id":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","user_id","plan_id","status","started_at","ended_at","external_subscription_id","created_at","updated_at"]},"VerifyIapRequest":{"type":"object","properties":{"platform":{"type":"string","enum":["ios","android"]},"receipt":{"type":"string","minLength":1},"product_id":{"type":"string","minLength":1},"transaction_id":{"type":"string"}},"required":["platform","receipt","product_id"]},"ParkingLot":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"address":{"type":"string","nullable":true},"lat":{"type":"number","nullable":true},"lng":{"type":"number","nullable":true},"total_spaces":{"type":"integer","nullable":true},"status":{"type":"string","nullable":true},"structure":{"type":"string","nullable":true},"operating_hours":{"type":"string","nullable":true},"created_at":{"type":"string"},"max_height_m":{"type":"number","nullable":true},"max_width_m":{"type":"number","nullable":true},"max_length_m":{"type":"number","nullable":true},"max_weight_t":{"type":"number","nullable":true},"min_clearance_cm":{"type":"integer","nullable":true},"max_parking_duration_min":{"type":"integer","nullable":true},"entry_method":{"type":"string","nullable":true},"source":{"type":"string","nullable":true},"shape_type":{"type":"string","nullable":true},"area":{"nullable":true},"operator_code":{"type":"string","nullable":true},"entry_difficulty":{"type":"string","nullable":true}},"required":["id","name","address","lat","lng","total_spaces","status","structure","operating_hours","created_at"]},"NearbyParkingLot":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"address":{"type":"string","nullable":true},"lat":{"type":"number","nullable":true},"lng":{"type":"number","nullable":true},"distance_m":{"type":"number"}},"required":["id","name","address","lat","lng","distance_m"]},"ParkingLotWithDetail":{"allOf":[{"$ref":"#/components/schemas/ParkingLot"},{"type":"object","properties":{"pricing_rules":{"type":"array","items":{"nullable":true}},"images":{"type":"array","items":{"nullable":true}},"tags":{"type":"array","items":{"nullable":true}},"operator":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"slug":{"type":"string"},"color":{"type":"string"}},"required":["id","name","slug","color"]}}}]},"PricingRule":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"parking_lot_id":{"type":"string","format":"uuid"},"category":{"type":"string"},"rule_order":{"type":"integer"},"time_start":{"type":"string","nullable":true},"time_end":{"type":"string","nullable":true},"day_type":{"type":"string","nullable":true},"per_minutes":{"type":"integer","nullable":true},"price":{"type":"integer","nullable":true},"cap_type":{"type":"string","nullable":true},"cap_duration_hours":{"type":"number","nullable":true},"cap_price":{"type":"integer","nullable":true},"cap_repeat":{"type":"boolean","nullable":true}},"required":["id","parking_lot_id","category","rule_order","time_start","time_end","day_type","per_minutes","price","cap_type","cap_duration_hours","cap_price","cap_repeat"]},"NearbyStationItem":{"type":"object","properties":{"distance_m":{"type":"number","nullable":true},"walk_min":{"type":"number","nullable":true},"station":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"code":{"type":"string","nullable":true},"lat":{"type":"number","nullable":true},"lng":{"type":"number","nullable":true}},"required":["id","name","code","lat","lng"]}},"required":["distance_m","station"]},"ParkingLotImage":{"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","nullable":true}},"required":["id","parking_lot_id","asset_id","is_main","sort_order"]},"FeeCalcResponse":{"type":"object","properties":{"total_amount":{"type":"integer"},"breakdown":{"type":"array","items":{"nullable":true}},"note":{"type":"string"}},"required":["total_amount","breakdown"]},"FeeCalcRequest":{"type":"object","properties":{"entry_at":{"type":"string","format":"date-time"},"exit_at":{"type":"string","format":"date-time"},"vehicle_type":{"type":"string","default":"sedan"}},"required":["entry_at","exit_at"]},"Review":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"parking_lot_id":{"type":"string","format":"uuid"},"user_id":{"type":"string","format":"uuid"},"rating":{"type":"integer","minimum":1,"maximum":5},"comment":{"type":"string","nullable":true},"status":{"type":"string"},"created_at":{"type":"string"}},"required":["id","parking_lot_id","user_id","rating","comment","status","created_at"]},"Tag":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"color":{"type":"string","nullable":true},"sort_order":{"type":"integer","nullable":true}},"required":["id","name","color","sort_order"]},"ArticleListItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string","nullable":true},"title":{"type":"string"},"excerpt":{"type":"string","nullable":true},"category":{"type":"string"},"content_format":{"type":"string","nullable":true},"author_name":{"type":"string","nullable":true},"author_slug":{"type":"string","nullable":true},"published_at":{"type":"string","nullable":true},"updated_at":{"type":"string","nullable":true},"thumbnail_url":{"type":"string","nullable":true},"hero_image_url":{"type":"string","nullable":true},"tags":{"type":"array","items":{"type":"string"}},"related_hubs":{"type":"array","items":{"nullable":true}},"story_number":{"type":"integer","nullable":true},"view_count":{"type":"integer","nullable":true}},"required":["id","slug","title","excerpt","category","content_format","author_name","author_slug","published_at","updated_at","thumbnail_url","hero_image_url","tags","related_hubs","story_number","view_count"]},"Article":{"allOf":[{"$ref":"#/components/schemas/ArticleListItem"},{"type":"object","properties":{"updated_at":{"type":"string"},"view_count":{"type":"integer"},"body":{"type":"string","nullable":true},"created_at":{"type":"string"}},"required":["body","created_at"]}]},"Ad":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"ad_type":{"type":"string"},"placement":{"type":"string"},"banner_url":{"type":"string","nullable":true},"link_url":{"type":"string","nullable":true},"alt_text":{"type":"string","nullable":true},"start_date":{"type":"string","nullable":true},"end_date":{"type":"string","nullable":true}},"required":["id","name","ad_type","placement","banner_url","link_url","alt_text","start_date","end_date"]},"SupportTicket":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"user_id":{"type":"string","nullable":true,"format":"uuid"},"user_email":{"type":"string"},"user_name":{"type":"string"},"subject":{"type":"string"},"body":{"type":"string"},"category":{"type":"string"},"priority":{"type":"string"},"status":{"type":"string"},"created_at":{"type":"string"}},"required":["id","user_id","user_email","user_name","subject","body","category","priority","status","created_at"]},"ErrorReport":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"user_id":{"type":"string","nullable":true,"format":"uuid"},"user_email":{"type":"string"},"user_name":{"type":"string"},"parking_lot_id":{"type":"string","nullable":true,"format":"uuid"},"parking_lot_name":{"type":"string"},"report_type":{"type":"string"},"description":{"type":"string"},"status":{"type":"string"},"photo_asset_id":{"type":"string","nullable":true,"format":"uuid"},"created_at":{"type":"string"}},"required":["id","user_id","user_email","user_name","parking_lot_id","parking_lot_name","report_type","description","status","photo_asset_id","created_at"]},"AreaSponsor":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"category":{"type":"string"},"description":{"type":"string","nullable":true},"logo_url":{"type":"string","nullable":true},"banner_url":{"type":"string","nullable":true},"link_url":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true},"address":{"type":"string","nullable":true},"lat":{"type":"number","nullable":true},"lng":{"type":"number","nullable":true},"radius_m":{"type":"integer"}},"required":["id","name","category","description","logo_url","banner_url","link_url","phone","address","lat","lng","radius_m"]},"UploadUrlResponse":{"type":"object","properties":{"asset_id":{"type":"string","format":"uuid"},"upload_url":{"type":"string","format":"uri"},"s3_key":{"type":"string"},"public_url":{"type":"string","format":"uri"},"expires_in":{"type":"integer"}},"required":["asset_id","upload_url","s3_key","public_url","expires_in"]},"Asset":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"file_name":{"type":"string"},"file_size":{"type":"integer"},"mime_type":{"type":"string"},"s3_key":{"type":"string"},"category":{"type":"string"},"entity_type":{"type":"string","nullable":true},"entity_id":{"type":"string","nullable":true,"format":"uuid"},"is_public":{"type":"boolean"},"uploaded_by":{"type":"string","nullable":true,"format":"uuid"},"created_at":{"type":"string"}},"required":["id","file_name","file_size","mime_type","s3_key","category","entity_type","entity_id","is_public","uploaded_by","created_at"]},"SearchLot":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"address":{"type":"string","nullable":true},"lat":{"type":"number","nullable":true},"lng":{"type":"number","nullable":true},"total_spaces":{"type":"integer","nullable":true},"status":{"type":"string","nullable":true},"structure":{"type":"string","nullable":true},"operating_hours":{"type":"string","nullable":true},"max_height_m":{"type":"number","nullable":true},"max_width_m":{"type":"number","nullable":true},"max_length_m":{"type":"number","nullable":true},"max_weight_t":{"type":"number","nullable":true},"min_clearance_cm":{"type":"integer","nullable":true},"max_parking_duration_min":{"type":"integer","nullable":true},"entry_method":{"type":"string","nullable":true},"shape_type":{"type":"string","nullable":true},"area":{"nullable":true},"operator_code":{"type":"string","nullable":true},"operator_name":{"type":"string","nullable":true},"entry_difficulty":{"type":"string","nullable":true},"pricing_rules":{"type":"array","items":{"nullable":true}},"tags":{"type":"array","items":{"nullable":true}}},"required":["id","name","address","lat","lng","total_spaces","status","structure","operating_hours","max_height_m","max_width_m","max_length_m","max_weight_t","min_clearance_cm","max_parking_duration_min","entry_method","shape_type","operator_code","operator_name","entry_difficulty","pricing_rules","tags"]},"AiSearchQuery":{"type":"object","properties":{"keywords":{"type":"array","items":{"type":"string"}},"max_price_per_hour":{"type":"integer"},"roof":{"type":"boolean"},"open_24h":{"type":"boolean"},"vehicle_type":{"type":"string","enum":["sedan","kei","minivan","suv","truck"]}}},"AiSearchResponse":{"type":"object","properties":{"status":{"type":"string","enum":["parsed","need_info","error"]},"query":{"$ref":"#/components/schemas/AiSearchQuery"},"reply":{"type":"string"}},"required":["status","reply"]},"AiSearchRequest":{"type":"object","properties":{"message":{"type":"string","minLength":1,"maxLength":500},"session_id":{"type":"string"}},"required":["message"]},"HubStation":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"code":{"type":"string","nullable":true},"lat":{"type":"number","nullable":true},"lng":{"type":"number","nullable":true},"city":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"slug":{"type":"string","nullable":true}},"required":["id","name","slug"]},"prefecture":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"slug":{"type":"string","nullable":true}},"required":["id","name","slug"]}},"required":["id","name","code","lat","lng","city","prefecture"]},"HubPublishableItem":{"type":"object","properties":{"stats":{"type":"object","properties":{"station_id":{"type":"string","format":"uuid"},"total_count":{"type":"integer"},"in_stock_count":{"type":"integer"},"out_of_stock_count":{"type":"integer"}},"required":["station_id","total_count","in_stock_count","out_of_stock_count"]},"station":{"$ref":"#/components/schemas/HubStation"}},"required":["stats","station"]},"HubParkingLot":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"address":{"type":"string","nullable":true},"lat":{"type":"number","nullable":true},"lng":{"type":"number","nullable":true},"total_spaces":{"type":"integer","nullable":true},"status":{"type":"string","nullable":true},"structure":{"type":"string","nullable":true},"operating_hours":{"type":"string","nullable":true},"max_height_m":{"type":"number","nullable":true},"max_width_m":{"type":"number","nullable":true},"max_length_m":{"type":"number","nullable":true},"max_weight_t":{"type":"number","nullable":true},"min_clearance_cm":{"type":"integer","nullable":true},"operator_code":{"type":"string","nullable":true},"operator_name":{"type":"string","nullable":true},"entry_difficulty":{"type":"string","nullable":true},"pricing_rules":{"type":"array","items":{"nullable":true}},"tags":{"type":"array","items":{"nullable":true}}},"required":["id","name","address","lat","lng","total_spaces","status","structure","operating_hours","max_height_m","max_width_m","max_length_m","max_weight_t","min_clearance_cm","operator_code","operator_name","entry_difficulty","pricing_rules","tags"]},"HubParkingLotItem":{"type":"object","properties":{"distance_m":{"type":"number","nullable":true},"walk_min":{"type":"number","nullable":true},"parking_lot":{"$ref":"#/components/schemas/HubParkingLot"}},"required":["distance_m","parking_lot"]},"ActivityTypeMeta":{"type":"object","properties":{"type":{"type":"string"},"description":{"type":"string"},"category":{"type":"string","enum":["session","engagement","asset","discovery","account"]},"emitted_by":{"type":"string"},"emitted":{"type":"boolean"},"metadata_schema":{"nullable":true}},"required":["type","description","category","emitted_by","emitted"]},"ActivityTypesResponse":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ActivityTypeMeta"}}},"required":["items"]},"Admin":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"user_id":{"type":"string","nullable":true,"format":"uuid"},"name":{"type":"string"},"email":{"type":"string"},"role_id":{"type":"string","format":"uuid"},"status":{"type":"string"},"last_login_at":{"type":"string","nullable":true},"created_at":{"type":"string"}},"required":["id","user_id","name","email","role_id","status","last_login_at","created_at"]},"AdminNotificationPrefs":{"type":"object","properties":{"new_owner":{"type":"boolean","default":true},"new_parking":{"type":"boolean","default":true},"sales_daily":{"type":"boolean","default":true},"sales_monthly":{"type":"boolean","default":true},"system_alert":{"type":"boolean","default":true}}},"Role":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"color":{"type":"string"},"is_system":{"type":"boolean"},"created_at":{"type":"string"}},"required":["id","name","description","color","is_system","created_at"]},"AdminParkingLot":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"address":{"type":"string","nullable":true},"lat":{"type":"number","nullable":true},"lng":{"type":"number","nullable":true},"status":{"type":"string","nullable":true},"total_spaces":{"type":"integer","nullable":true},"operating_hours":{"type":"string","nullable":true},"operator_code":{"type":"string","nullable":true},"entry_difficulty":{"type":"string","nullable":true}},"required":["id","name","address","lat","lng","status","total_spaces","operating_hours"]},"AdminAppUser":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"auth_user_id":{"type":"string","nullable":true,"format":"uuid"},"display_name":{"type":"string"},"email":{"type":"string"},"vehicle_type":{"type":"string","nullable":true},"premium":{"type":"boolean"},"status":{"type":"string"},"created_at":{"type":"string"}},"required":["id","auth_user_id","display_name","email","vehicle_type","premium","status","created_at"]},"AdminTag":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"color":{"type":"string"},"sort_order":{"type":"integer"},"created_at":{"type":"string"},"slug":{"type":"string","nullable":true},"category":{"type":"string","nullable":true},"usage_count":{"type":"integer"}},"required":["id","name","color","sort_order","created_at","slug","category"]},"AdminOperator":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"color":{"type":"string"},"sort_order":{"type":"integer"},"created_at":{"type":"string","nullable":true},"updated_at":{"type":"string","nullable":true},"deleted_at":{"type":"string","nullable":true},"usage_count":{"type":"integer"}},"required":["id","name","slug","color","sort_order","created_at","updated_at","deleted_at"]},"AdminNotification":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"message":{"type":"string"},"category":{"type":"string"},"avatar":{"type":"string"},"read":{"type":"boolean"},"created_at":{"type":"string"},"deleted_at":{"type":"string","nullable":true}},"required":["id","title","message","category","avatar","read","created_at","deleted_at"]},"AdminUserNotification":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"body":{"type":"string"},"type":{"type":"string"},"target":{"type":"string"},"status":{"type":"string"},"scheduled_at":{"type":"string","nullable":true},"sent_at":{"type":"string","nullable":true},"total_recipients":{"type":"integer","nullable":true},"success_count":{"type":"integer","nullable":true},"failure_count":{"type":"integer","nullable":true},"created_at":{"type":"string"},"deleted_at":{"type":"string","nullable":true}},"required":["id","title","body","type","target","status","scheduled_at","sent_at","total_recipients","success_count","failure_count","created_at","deleted_at"]},"DispatchEnqueued":{"type":"object","properties":{"notification_id":{"type":"string","format":"uuid"},"enqueued":{"type":"integer"},"batches":{"type":"integer"}},"required":["notification_id","enqueued","batches"]},"AdminReview":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"parking_lot_id":{"type":"string","format":"uuid"},"user_id":{"type":"string","format":"uuid"},"rating":{"type":"integer"},"comment":{"type":"string","nullable":true},"status":{"type":"string"},"admin_note":{"type":"string","nullable":true},"created_at":{"type":"string"},"deleted_at":{"type":"string","nullable":true}},"required":["id","parking_lot_id","user_id","rating","comment","status","admin_note","created_at","deleted_at"]},"AdminSupportTicket":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"user_id":{"type":"string","nullable":true,"format":"uuid"},"user_email":{"type":"string"},"user_name":{"type":"string"},"subject":{"type":"string"},"body":{"type":"string"},"category":{"type":"string"},"priority":{"type":"string"},"status":{"type":"string"},"created_at":{"type":"string"}},"required":["id","user_id","user_email","user_name","subject","body","category","priority","status","created_at"]},"AdminErrorReport":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"user_id":{"type":"string","nullable":true,"format":"uuid"},"user_email":{"type":"string"},"user_name":{"type":"string"},"parking_lot_id":{"type":"string","nullable":true,"format":"uuid"},"parking_lot_name":{"type":"string"},"report_type":{"type":"string"},"description":{"type":"string"},"status":{"type":"string"},"admin_note":{"type":"string","nullable":true},"created_at":{"type":"string"},"resolved_at":{"type":"string","nullable":true},"user":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"display_name":{"type":"string","nullable":true}},"required":["id","display_name"]},"parking_lot":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}},"required":["id","name"]}},"required":["id","user_id","user_email","user_name","parking_lot_id","parking_lot_name","report_type","description","status","admin_note","created_at","resolved_at"]},"AdminTask":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"task_kind":{"type":"string"},"ref_id":{"type":"string","format":"uuid"},"assignee_id":{"type":"string","nullable":true,"format":"uuid"},"urgency":{"type":"string"},"due_at":{"type":"string","nullable":true},"memo":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","task_kind","ref_id","assignee_id","urgency","due_at","memo","created_at","updated_at"]},"AdminArticle":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string","nullable":true},"title":{"type":"string"},"body":{"type":"string","nullable":true},"excerpt":{"type":"string","nullable":true},"category":{"type":"string"},"author_name":{"type":"string","nullable":true},"status":{"type":"string"},"published_at":{"type":"string","nullable":true},"view_count":{"type":"integer"},"tags":{"type":"array","items":{"type":"string"}},"thumbnail_url":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","slug","title","body","excerpt","category","author_name","status","published_at","view_count","tags","thumbnail_url","created_at","updated_at"]},"AdminAd":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"ad_type":{"type":"string"},"placement":{"type":"string"},"banner_url":{"type":"string","nullable":true},"link_url":{"type":"string","nullable":true},"alt_text":{"type":"string","nullable":true},"status":{"type":"string"},"start_date":{"type":"string","nullable":true},"end_date":{"type":"string","nullable":true},"impressions":{"type":"integer"},"clicks":{"type":"integer"},"memo":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","name","ad_type","placement","banner_url","link_url","alt_text","status","start_date","end_date","impressions","clicks","memo","created_at","updated_at"]},"AdminBoost":{"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"},"daily_budget":{"type":"integer","nullable":true},"total_budget":{"type":"integer","nullable":true},"status":{"type":"string"},"started_at":{"type":"string"},"ended_at":{"type":"string","nullable":true},"owner":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","nullable":true},"email":{"type":"string","nullable":true}},"required":["id","name","email"]},"parking_lot":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"address":{"type":"string","nullable":true}},"required":["id","name","address"]}},"required":["id","owner_id","parking_lot_id","name","credit_per_impression","daily_budget","total_budget","status","started_at","ended_at"]},"AdminSponsor":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"category":{"type":"string"},"description":{"type":"string","nullable":true},"logo_url":{"type":"string","nullable":true},"banner_url":{"type":"string","nullable":true},"link_url":{"type":"string","nullable":true}},"required":["id","name","category","description","logo_url","banner_url","link_url"]},"AdminOwner":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"owner_type":{"type":"string"},"name":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string","nullable":true},"status":{"type":"string"},"company_name":{"type":"string","nullable":true},"representative_name":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"},"parking_count":{"type":"integer"}},"required":["id","owner_type","name","email","phone","status","company_name","representative_name","created_at","updated_at"]},"AdminOwnerCredit":{"type":"object","properties":{"owner_id":{"type":"string","format":"uuid"},"balance":{"type":"integer"},"total_purchased":{"type":"integer"},"total_consumed":{"type":"integer"},"updated_at":{"type":"string","nullable":true},"owner":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"owner_type":{"type":"string","nullable":true}},"required":["id","name","email","owner_type"]}},"required":["owner_id","balance","total_purchased","total_consumed","owner"]},"AdminOwnerApplication":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"owner_id":{"type":"string","nullable":true,"format":"uuid"},"owner_name":{"type":"string"},"owner_email":{"type":"string"},"company_name":{"type":"string","nullable":true},"parking_lot_id":{"type":"string","format":"uuid"},"proof_asset_id":{"type":"string","nullable":true,"format":"uuid"},"additional_notes":{"type":"string","nullable":true},"status":{"type":"string"},"reviewed_by":{"type":"string","nullable":true,"format":"uuid"},"reviewed_at":{"type":"string","nullable":true},"reject_reason":{"type":"string","nullable":true},"created_at":{"type":"string"},"owner":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"owner_type":{"type":"string","nullable":true}},"required":["id","name","email","owner_type"]},"parking_lot":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"address":{"type":"string","nullable":true}},"required":["id","name","address"]},"proof_asset":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"s3_key":{"type":"string"},"file_name":{"type":"string"},"mime_type":{"type":"string"},"category":{"type":"string","nullable":true}},"required":["id","s3_key","file_name","mime_type","category"]},"reviewer":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","nullable":true}},"required":["id","name"]}},"required":["id","owner_id","owner_name","owner_email","company_name","parking_lot_id","status","reviewed_by","reviewed_at","reject_reason","created_at"]},"AdminActivityLog":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"admin_id":{"type":"string","nullable":true,"format":"uuid"},"admin_email_snapshot":{"type":"string"},"action":{"type":"string"},"target_type":{"type":"string","nullable":true},"target_id":{"type":"string","nullable":true},"target_label":{"type":"string","nullable":true},"metadata":{"nullable":true},"ip_address":{"type":"string","nullable":true},"user_agent":{"type":"string","nullable":true},"created_at":{"type":"string"}},"required":["id","admin_id","admin_email_snapshot","action","target_type","target_id","target_label","ip_address","user_agent","created_at"]},"RevenueMonthlyRow":{"type":"object","properties":{"month":{"type":"string"},"channel":{"type":"string"},"amount_minor":{"type":"integer"},"count":{"type":"integer"}},"required":["month","channel","amount_minor","count"]},"RevenueTransaction":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"occurred_at":{"type":"string"},"channel":{"type":"string"},"transaction_type":{"type":"string"},"amount_minor":{"type":"integer"},"currency":{"type":"string"},"external_id":{"type":"string","nullable":true},"description":{"type":"string","nullable":true},"user_id":{"type":"string","nullable":true,"format":"uuid"},"plan_id":{"type":"string","nullable":true,"format":"uuid"},"created_at":{"type":"string"}},"required":["id","occurred_at","channel","transaction_type","amount_minor","currency","external_id","description","user_id","plan_id","created_at"]},"RevenueTransactionWithRelations":{"allOf":[{"$ref":"#/components/schemas/RevenueTransaction"},{"type":"object","properties":{"user":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"display_name":{"type":"string","nullable":true},"email":{"type":"string","nullable":true}},"required":["id","display_name","email"]},"plan":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"code":{"type":"string","nullable":true},"name":{"type":"string","nullable":true}},"required":["id","code","name"]}},"required":["user","plan"]}]},"AdminUserSubscription":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"user_id":{"type":"string","format":"uuid"},"plan_id":{"type":"string","format":"uuid"},"status":{"type":"string"},"started_at":{"type":"string"},"ended_at":{"type":"string","nullable":true},"external_subscription_id":{"type":"string","nullable":true},"created_at":{"type":"string"}},"required":["id","user_id","plan_id","status","started_at","ended_at","external_subscription_id","created_at"]},"AdminSubscriptionPlan":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"code":{"type":"string"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"price_minor":{"type":"integer"},"currency":{"type":"string"},"billing_period":{"type":"string"},"accent_color":{"type":"string","nullable":true},"features":{"nullable":true},"sort_order":{"type":"integer"},"is_active":{"type":"boolean"}},"required":["id","code","name","description","price_minor","currency","billing_period","accent_color","sort_order","is_active"]},"StoreIntegration":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"store":{"type":"string"},"display_name":{"type":"string"},"package_or_app_id":{"type":"string","nullable":true},"vendor_number":{"type":"string","nullable":true},"connection_status":{"type":"string"},"last_status_message":{"type":"string","nullable":true},"last_synced_at":{"type":"string","nullable":true},"last_sync_error":{"type":"string","nullable":true}},"required":["id","store","display_name","package_or_app_id","vendor_number","connection_status","last_status_message","last_synced_at","last_sync_error"]},"StoreSalesRow":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"store":{"type":"string"},"report_date":{"type":"string"},"product_id":{"type":"string"},"country_code":{"type":"string"},"units":{"type":"integer"},"proceeds_minor":{"type":"integer"},"gross_minor":{"type":"integer"},"currency":{"type":"string"},"fetched_at":{"type":"string"}},"required":["id","store","report_date","product_id","country_code","units","proceeds_minor","gross_minor","currency","fetched_at"]},"StoreMetricsRow":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"store":{"type":"string"},"metric_date":{"type":"string"},"installs":{"type":"integer","nullable":true},"uninstalls":{"type":"integer","nullable":true},"active_devices":{"type":"integer","nullable":true},"impressions":{"type":"integer","nullable":true},"product_page_views":{"type":"integer","nullable":true},"crash_rate":{"type":"number","nullable":true},"anr_rate":{"type":"number","nullable":true},"rating_average":{"type":"number","nullable":true},"rating_count":{"type":"integer","nullable":true}},"required":["id","store","metric_date","installs","uninstalls","active_devices","impressions","product_page_views","crash_rate","anr_rate","rating_average","rating_count"]},"StoreReview":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"store":{"type":"string"},"external_review_id":{"type":"string"},"author_name":{"type":"string","nullable":true},"rating":{"type":"integer","nullable":true},"title":{"type":"string","nullable":true},"body":{"type":"string","nullable":true},"reply_body":{"type":"string","nullable":true},"reply_at":{"type":"string","nullable":true},"posted_at":{"type":"string"}},"required":["id","store","external_review_id","author_name","rating","title","body","reply_body","reply_at","posted_at"]},"StoreSyncRun":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"store":{"type":"string"},"task":{"type":"string"},"status":{"type":"string"},"started_at":{"type":"string"},"finished_at":{"type":"string","nullable":true},"rows_upserted":{"type":"integer"},"message":{"type":"string","nullable":true},"triggered_by":{"type":"string"}},"required":["id","store","task","status","started_at","finished_at","rows_upserted","message","triggered_by"]},"BadgeDefinition":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"icon":{"type":"string"},"activity_type":{"type":"string"},"threshold":{"type":"integer"},"sort_order":{"type":"integer"},"is_active":{"type":"boolean"},"asset_id":{"type":"string","nullable":true,"format":"uuid"},"conditions":{"nullable":true},"category":{"type":"string"},"created_at":{"type":"string"},"holders_count":{"type":"integer"},"asset":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"s3_key":{"type":"string"},"file_name":{"type":"string"},"mime_type":{"type":"string"},"category":{"type":"string","nullable":true}},"required":["id","s3_key","file_name","mime_type","category"]},"tags":{"type":"array","items":{"type":"string"}}},"required":["id","name","description","icon","activity_type","threshold","sort_order","is_active","asset_id","category","created_at"]},"ActivityExpRule":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"activity_type":{"type":"string"},"exp_amount":{"type":"integer"},"description":{"type":"string"},"is_active":{"type":"boolean"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","activity_type","exp_amount","description","is_active","created_at","updated_at"]},"LevelDefinition":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"level":{"type":"integer"},"required_exp":{"type":"integer"},"created_at":{"type":"string"}},"required":["id","level","required_exp","created_at"]},"AdminTheme":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"is_free":{"type":"boolean"},"price_yen":{"type":"integer","nullable":true},"preview_asset_id":{"type":"string","nullable":true,"format":"uuid"},"is_active":{"type":"boolean"},"sort_order":{"type":"integer"},"created_at":{"type":"string"},"updated_at":{"type":"string"},"preview_asset":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"s3_key":{"type":"string"},"file_name":{"type":"string"},"mime_type":{"type":"string"},"category":{"type":"string","nullable":true}},"required":["id","s3_key","file_name","mime_type","category"]},"owners_count":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"theme_id":{"type":"string","format":"uuid"},"category":{"type":"string"},"part_id":{"type":"string","format":"uuid"}},"required":["id","theme_id","category","part_id"]}}},"required":["id","name","description","is_free","price_yen","preview_asset_id","is_active","sort_order","created_at","updated_at"]},"AdminThemePart":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"category":{"type":"string"},"primary_color":{"type":"string","nullable":true},"accent_color":{"type":"string","nullable":true},"pin_asset_id":{"type":"string","nullable":true,"format":"uuid"},"icon_asset_id":{"type":"string","nullable":true,"format":"uuid"},"loading_asset_id":{"type":"string","nullable":true,"format":"uuid"},"loading_type":{"type":"string","nullable":true},"is_active":{"type":"boolean"},"sort_order":{"type":"integer"},"used_in_themes_count":{"type":"integer"},"tags":{"type":"array","items":{"type":"string"}},"pin_asset":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"s3_key":{"type":"string"},"file_name":{"type":"string"},"mime_type":{"type":"string"},"category":{"type":"string","nullable":true}},"required":["id","s3_key","file_name","mime_type","category"]},"icon_asset":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"s3_key":{"type":"string"},"file_name":{"type":"string"},"mime_type":{"type":"string"},"category":{"type":"string","nullable":true}},"required":["id","s3_key","file_name","mime_type","category"]},"loading_asset":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"s3_key":{"type":"string"},"file_name":{"type":"string"},"mime_type":{"type":"string"},"category":{"type":"string","nullable":true}},"required":["id","s3_key","file_name","mime_type","category"]}},"required":["id","name","description","category","primary_color","accent_color","pin_asset_id","icon_asset_id","loading_asset_id","loading_type","is_active","sort_order"]},"AiProvider":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"provider_key":{"type":"string"},"display_name":{"type":"string"},"model_name":{"type":"string"},"vault_secret_id":{"type":"string","nullable":true,"format":"uuid"},"is_enabled":{"type":"boolean"},"priority":{"type":"integer"},"config":{"nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","provider_key","display_name","model_name","vault_secret_id","is_enabled","priority","created_at","updated_at"]},"AiUsageLog":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"provider_id":{"type":"string","format":"uuid"},"provider_key":{"type":"string"},"model_name":{"type":"string"},"user_input":{"type":"string"},"parsed_query":{"nullable":true},"response_status":{"type":"string"},"input_tokens":{"type":"integer"},"output_tokens":{"type":"integer"},"total_tokens":{"type":"integer"},"estimated_cost_usd":{"type":"number"},"latency_ms":{"type":"integer"},"attempt_number":{"type":"integer"},"fallback_reason":{"type":"string","nullable":true},"error_code":{"type":"string","nullable":true}},"required":["id","provider_id","provider_key","model_name","user_input","response_status","input_tokens","output_tokens","total_tokens","estimated_cost_usd","latency_ms","attempt_number","fallback_reason","error_code"]},"AdminCode":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"category_id":{"type":"string"},"code":{"type":"string"},"display_label":{"type":"string"},"lang":{"type":"string"},"sort_order":{"type":"integer","nullable":true},"is_deleted":{"type":"boolean"}},"required":["id","category_id","code","display_label","lang","sort_order","is_deleted"]},"AdminParkingSession":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"user_id":{"type":"string","nullable":true,"format":"uuid"},"parking_lot_id":{"type":"string","format":"uuid"},"vehicle_id":{"type":"string","nullable":true,"format":"uuid"},"started_at":{"type":"string","nullable":true},"ended_at":{"type":"string","nullable":true},"status":{"type":"string"},"total_amount":{"type":"number","nullable":true},"memo":{"type":"string","nullable":true},"created_at":{"type":"string"}},"required":["id","user_id","parking_lot_id","vehicle_id","started_at","ended_at","status","total_amount","created_at"]},"AdminParkingSessionWithRelations":{"allOf":[{"$ref":"#/components/schemas/AdminParkingSession"},{"type":"object","properties":{"user":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"display_name":{"type":"string","nullable":true},"email":{"type":"string","nullable":true}},"required":["id","display_name","email"]},"parking_lot":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"address":{"type":"string","nullable":true}},"required":["id","name","address"]}},"required":["user","parking_lot"]}]},"IgSlideCategory":{"type":"object","properties":{"code":{"type":"string"},"label":{"type":"string"},"prefix":{"type":"string","nullable":true},"sort_order":{"type":"integer"},"is_deleted":{"type":"integer"}},"required":["code","label","prefix","sort_order","is_deleted"]},"IgPostCategory":{"type":"object","properties":{"code":{"type":"string"},"label":{"type":"string"},"color":{"type":"string","nullable":true},"sort_order":{"type":"integer"},"is_deleted":{"type":"integer"}},"required":["code","label","color","sort_order","is_deleted"]},"IgTag":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"color":{"type":"string","nullable":true},"usage_count":{"type":"integer"}},"required":["id","name","color","usage_count"]},"IgPostTemplate":{"type":"object","properties":{"id":{"type":"string"},"code":{"type":"string"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"slide_refs":{"type":"string"}},"required":["id","code","name","description","slide_refs"]},"IgTemplate":{"type":"object","properties":{"id":{"type":"string"},"code":{"type":"string"},"name":{"type":"string"},"slide_type":{"type":"string"},"html_body":{"type":"string"},"slot_schema":{"type":"string"},"sample_content":{"type":"string","default":"{}"},"sample_html":{"type":"string","default":""},"sort_order":{"type":"integer"},"is_active":{"type":"integer"}},"required":["id","code","name","slide_type","html_body","slot_schema","sort_order","is_active"]},"IgCampaign":{"type":"object","properties":{"id":{"type":"string"},"code":{"type":"string"},"title":{"type":"string"},"theme":{"type":"string","nullable":true},"area":{"type":"string","nullable":true},"status":{"type":"string"},"scheduled_at":{"type":"string","nullable":true},"ig_media_id":{"type":"string","nullable":true},"notes":{"type":"string","nullable":true},"source_material":{"type":"string","nullable":true},"post_category_code":{"type":"string","nullable":true},"created_by":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","code","title","theme","area","status","scheduled_at","ig_media_id","notes","source_material","post_category_code","created_by","created_at","updated_at"]},"IgSlide":{"type":"object","properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"template_id":{"type":"string"},"slide_index":{"type":"integer"},"content":{"type":"string"},"html_override":{"type":"string","nullable":true},"png_r2_key":{"type":"string","nullable":true},"png_url":{"type":"string","nullable":true},"revision_notes":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","campaign_id","template_id","slide_index","content","html_override","png_r2_key","png_url","revision_notes","created_at","updated_at"]},"IgCaption":{"type":"object","nullable":true,"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"body":{"type":"string","nullable":true},"hashtags":{"type":"string","nullable":true},"draft_body":{"type":"string","nullable":true},"generated_at":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","campaign_id","body","hashtags","draft_body","generated_at","created_at","updated_at"]},"IgCompetitorSnapshot":{"type":"object","properties":{"id":{"type":"string"},"campaign_id":{"type":"string","nullable":true},"source_url":{"type":"string","nullable":true},"account_handle":{"type":"string","nullable":true},"raw_notes":{"type":"string","nullable":true},"ai_ideas":{"type":"string","nullable":true},"created_by":{"type":"string","nullable":true},"created_at":{"type":"string"}},"required":["id","campaign_id","source_url","account_handle","raw_notes","ai_ideas","created_by","created_at"]},"AdminAsset":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"category":{"type":"string"},"s3_key":{"type":"string"},"file_name":{"type":"string"},"mime_type":{"type":"string"},"file_size":{"type":"integer"},"width":{"type":"integer","nullable":true},"height":{"type":"integer","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string","nullable":true}},"required":["id","category","s3_key","file_name","mime_type","file_size","width","height","created_at"]},"AdminUserVehicle":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"user_id":{"type":"string","format":"uuid"},"nickname":{"type":"string","nullable":true},"vehicle_type_code":{"type":"string","nullable":true},"maker_code":{"type":"string","nullable":true},"size_code":{"type":"string","nullable":true},"color_code":{"type":"string","nullable":true},"model_name":{"type":"string","nullable":true},"year":{"type":"integer","nullable":true},"asset_id":{"type":"string","nullable":true,"format":"uuid"},"is_primary":{"type":"boolean"},"notes":{"type":"string","nullable":true},"deleted_at":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"},"user":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"display_name":{"type":"string","nullable":true}},"required":["id","display_name"]},"asset":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"s3_key":{"type":"string"},"file_name":{"type":"string"},"mime_type":{"type":"string"},"category":{"type":"string","nullable":true}},"required":["id","s3_key","file_name","mime_type","category"]}},"required":["id","user_id","nickname","vehicle_type_code","maker_code","size_code","color_code","model_name","year","asset_id","is_primary","notes","deleted_at","created_at","updated_at"]},"AdminUserSearchPreset":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"user_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"query_json":{"$ref":"#/components/schemas/SearchQueryV1"},"is_default":{"type":"boolean"},"sort_order":{"type":"integer"},"deleted_at":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"},"user":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"display_name":{"type":"string","nullable":true}},"required":["id","display_name"]}},"required":["id","user_id","name","query_json","is_default","sort_order","deleted_at","created_at","updated_at"]},"OwnerParkingLot":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"address":{"type":"string","nullable":true},"status":{"type":"string","nullable":true},"total_spaces":{"type":"integer","nullable":true},"structure":{"type":"string","nullable":true},"created_at":{"type":"string","nullable":true},"updated_at":{"type":"string","nullable":true}},"required":["id","name","address","status","total_spaces","structure","created_at","updated_at"]},"OwnerSearchParkingLot":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"address":{"type":"string","nullable":true},"lat":{"type":"number","nullable":true},"lng":{"type":"number","nullable":true},"has_owner":{"type":"boolean"}},"required":["id","name","address","lat","lng","has_owner"]},"OwnerApplication":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"owner_id":{"type":"string","nullable":true,"format":"uuid"},"owner_name":{"type":"string"},"owner_email":{"type":"string"},"company_name":{"type":"string","nullable":true},"parking_lot_id":{"type":"string","format":"uuid"},"proof_asset_id":{"type":"string","nullable":true,"format":"uuid"},"additional_notes":{"type":"string","nullable":true},"status":{"type":"string"},"reviewed_at":{"type":"string","nullable":true},"reject_reason":{"type":"string","nullable":true},"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"]},"OwnerReview":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"parking_lot_id":{"type":"string","format":"uuid"},"user_name":{"type":"string"},"rating":{"type":"integer","minimum":1,"maximum":5},"comment":{"type":"string","nullable":true},"status":{"type":"string"},"owner_reply":{"type":"string","nullable":true},"owner_replied_at":{"type":"string","nullable":true},"owner_replied_by":{"type":"string","nullable":true,"format":"uuid"},"created_at":{"type":"string"},"updated_at":{"type":"string"},"parking_lot":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}},"required":["id","name"]}},"required":["id","parking_lot_id","user_name","rating","comment","status","owner_reply","owner_replied_at","owner_replied_by","created_at","updated_at","parking_lot"]},"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","nullable":true},"daily_budget":{"type":"integer","nullable":true},"total_budget":{"type":"integer","nullable":true},"started_at":{"type":"string","nullable":true},"ended_at":{"type":"string","nullable":true},"impressions":{"type":"integer","nullable":true},"clicks":{"type":"integer","nullable":true},"sessions":{"type":"integer","nullable":true},"status":{"type":"string","nullable":true},"created_at":{"type":"string","nullable":true}},"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"]},"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","nullable":true},"boost_id":{"type":"string","nullable":true,"format":"uuid"},"created_at":{"type":"string"}},"required":["id","owner_id","type","amount","balance_after","description","boost_id","created_at"]}},"parameters":{}},"paths":{"/v1/codes":{"get":{"tags":["codes"],"summary":"コードマスターをバルク取得（カテゴリ横断）","parameters":[{"schema":{"type":"string","example":"ja"},"required":false,"name":"lang","in":"query"}],"responses":{"200":{"description":"コード一覧","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CodesResponse"}}}},"500":{"description":"サーバーエラー","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/me":{"get":{"tags":["me"],"summary":"自分のプロフィールと権限スコープを取得","responses":{"200":{"description":"自分の情報","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"}}}},"401":{"description":"未認証","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["me"],"summary":"自分のプロフィールを更新","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeUpdate"}}}},"responses":{"200":{"description":"更新後のプロフィール","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"}}}},"401":{"description":"未認証","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"app_users に該当なし","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/me/withdraw":{"post":{"tags":["me"],"summary":"退会（匿名化 + ステータス変更）","responses":{"200":{"description":"退会完了","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]}},"required":["ok"]}}}},"401":{"description":"未認証","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/me/saved-parking-lots":{"get":{"tags":["me"],"summary":"保存した駐車場の一覧","responses":{"200":{"description":"保存一覧","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SavedParkingLot"}}}}}}},"post":{"tags":["me"],"summary":"保存を追加","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"parking_lot_id":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"}},"required":["parking_lot_id"]}}}},"responses":{"200":{"description":"追加した行","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SavedParkingLot"}}}},"409":{"description":"既に保存済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/me/saved-parking-lots/{lotId}":{"delete":{"tags":["me"],"summary":"保存を解除","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"lotId","in":"path"}],"responses":{"204":{"description":"削除成功"}}}},"/v1/me/vehicles":{"get":{"tags":["me"],"summary":"自分の車両一覧","responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UserVehicle"}}}}}}},"post":{"tags":["me"],"summary":"車両を登録","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"vehicle_type":{"type":"string"},"nickname":{"type":"string","nullable":true,"maxLength":50},"plate_number":{"type":"string","nullable":true,"maxLength":20},"color":{"type":"string","nullable":true,"maxLength":30},"is_default":{"type":"boolean"}},"required":["vehicle_type"]}}}},"responses":{"200":{"description":"登録済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserVehicle"}}}},"401":{"description":"未認証","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/me/vehicles/{id}":{"patch":{"tags":["me"],"summary":"車両を更新","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"vehicle_type":{"type":"string"},"nickname":{"type":"string","nullable":true,"maxLength":50},"plate_number":{"type":"string","nullable":true,"maxLength":20},"color":{"type":"string","nullable":true,"maxLength":30},"is_default":{"type":"boolean"}}}}}},"responses":{"200":{"description":"更新済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserVehicle"}}}},"404":{"description":"存在しない","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["me"],"summary":"車両をソフト削除","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"204":{"description":"削除成功"}}}},"/v1/me/search-presets":{"get":{"tags":["me","search-presets"],"summary":"自分の検索プリセット一覧（sort_order 昇順）","responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SearchPreset"}}}}}}},"post":{"tags":["me","search-presets"],"summary":"プリセットを新規作成（最大 20 件まで）","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":50},"query_json":{"$ref":"#/components/schemas/SearchQueryV1"},"is_default":{"type":"boolean"},"sort_order":{"type":"integer"}},"required":["name","query_json"]}}}},"responses":{"200":{"description":"作成済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchPreset"}}}},"400":{"description":"入力不正 or 件数上限","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/me/search-presets/{id}":{"get":{"tags":["me","search-presets"],"summary":"プリセット 1 件取得","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"1 件","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchPreset"}}}},"404":{"description":"存在しない","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["me","search-presets"],"summary":"プリセットを部分更新（名前・条件・並び順）","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":50},"query_json":{"$ref":"#/components/schemas/SearchQueryV1"},"sort_order":{"type":"integer"}}}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchPreset"}}}},"404":{"description":"存在しない","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["me","search-presets"],"summary":"プリセットをソフト削除","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"204":{"description":"削除成功"}}}},"/v1/me/search-presets/{id}/set-default":{"post":{"tags":["me","search-presets"],"summary":"指定プリセットをデフォルトに設定（他を解除）","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchPreset"}}}},"404":{"description":"存在しない","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/me/parking-sessions":{"get":{"tags":["me"],"summary":"自分の駐車セッション一覧","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"status","in":"query"}],"responses":{"200":{"description":"履歴","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ParkingSession"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}}},"/v1/me/parking-sessions/{id}":{"get":{"tags":["me"],"summary":"自分の駐車セッション詳細","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"詳細","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ParkingSession"}}}},"404":{"description":"存在しないか他人の","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["me"],"summary":"メモ・個人評価を更新","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"memo":{"type":"string","nullable":true},"personal_rating":{"type":"string","nullable":true}}}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ParkingSession"}}}}}}},"/v1/me/reviews/{id}":{"patch":{"tags":["me"],"summary":"自分のレビューを編集（再審査扱いで status=pending に戻る運用を想定）","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"rating":{"type":"integer","minimum":1,"maximum":5},"comment":{"type":"string","nullable":true,"maxLength":2000}}}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MyReview"}}}},"404":{"description":"存在しない","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/reviews":{"get":{"tags":["reviews"],"summary":"公開レビューの横断一覧（status=approved、SSG ビルド向け）","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","example":"approved"},"required":false,"name":"status","in":"query"}],"responses":{"200":{"description":"レビュー一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/PublicReview"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}}},"/v1/me/notifications":{"get":{"tags":["me"],"summary":"自分宛の通知一覧","description":"ログインユーザー自身の `user_notifications` を新しい順で返す。\n\n- **認証**: 必須。`user_id` は JWT から取得し、他人の通知は絶対に返さない（コード層 + RLS 両方で防御）。\n- **ページング**: `page` / `limit`（最大 100）。PullToRefresh で先頭のみ、スクロール末尾で次ページ。\n- **Realtime 併用**: 同条件で supabase-flutter の Realtime を購読すれば INSERT を即時受信可能（データプレーン例外）。","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"通知一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/UserNotification"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}}},"/v1/me/notifications/mark-read":{"post":{"tags":["me"],"summary":"通知を既読にする（IDs か before 指定、両方 null なら全件）","description":"通知を既読化する。既読は `read_at` に現在時刻を書き込むことで表現される。\n\n- **モード**: `ids` → 特定通知のみ / `before` → その時刻以前をまとめて / 両方 null → 自分の未読全件。\n- **冪等**: 既読済み行への呼び出しは no-op（`read_at` を上書きしない）。\n- **レスポンス**: `updated` に更新行数を返す。バッジ表示の差分更新に利用できる。","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"ids":{"type":"array","items":{"type":"string","format":"uuid"}},"before":{"type":"string","format":"date-time"}}}}}},"responses":{"200":{"description":"既読にした件数","content":{"application/json":{"schema":{"type":"object","properties":{"updated":{"type":"integer"}},"required":["updated"]}}}}}}},"/v1/me/push-tokens":{"put":{"tags":["me"],"summary":"FCM デバイストークンを upsert","description":"端末の FCM 登録トークンをサーバに登録する。Push 通知配信の前提となる。\n\n- **呼び出しタイミング**: アプリ起動直後・`onTokenRefresh` イベント時に叩く。FCM トークンは変わり得る。\n- **upsert**: `(user_id, device_type)` で一意。再登録は値上書き。\n- **サインアウト時**: 端末側で DELETE を投げる（誤配信防止）。\n- **現状**: サーバ側配信（`parky-fcm-dispatch` キュー + consumer）は完成済。Flutter 側 `firebase_messaging` 組み込みが残タスク。","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"fcm_token":{"type":"string","minLength":1},"device_type":{"type":"string","enum":["android","ios","web"],"default":"android"}},"required":["fcm_token"]}}}},"responses":{"200":{"description":"登録済みトークン","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserPushToken"}}}}}}},"/v1/me/exp":{"get":{"tags":["me"],"summary":"自分の EXP・レベル（次レベルまでの残 EXP を含む）","responses":{"200":{"description":"EXP 情報","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MyExp"}}}}}}},"/v1/me/badges":{"get":{"tags":["me"],"summary":"獲得済みバッジ一覧","responses":{"200":{"description":"バッジ一覧","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MyBadge"}}}}}}}},"/v1/me/badge-progress":{"get":{"tags":["me"],"summary":"進捗中のバッジ一覧（未獲得のみ）","responses":{"200":{"description":"進捗一覧","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MyBadgeProgress"}}}}}}}},"/v1/me/themes":{"get":{"tags":["me"],"summary":"所有テーマ一覧","responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MyTheme"}}}}}}}},"/v1/me/themes/{id}/apply":{"post":{"tags":["me"],"summary":"所有テーマを適用（app_users.active_theme_id などに反映される想定）","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"適用結果","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"theme_id":{"type":"string","format":"uuid"}},"required":["ok","theme_id"]}}}}}}},"/v1/me/subscription":{"get":{"tags":["me"],"summary":"自分の現行サブスク（アクティブが無ければ null フィールドで返す）","responses":{"200":{"description":"契約状態","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MySubscription"}}}}}}},"/v1/me/subscription/verify-iap":{"post":{"tags":["me"],"summary":"IAP 購入レシートを検証して user_subscriptions を更新","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyIapRequest"}}}},"responses":{"200":{"description":"検証成功。user_subscriptions の最新行を返す","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyIapResponse"}}}},"422":{"description":"productId に対応する subscription_plans が無い","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"request_id":{"type":"string"}},"required":["code","message"]}},"required":["error"]}}}},"503":{"description":"該当プラットフォームの IAP 設定（キー類）が未投入","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"request_id":{"type":"string"}},"required":["code","message"]}},"required":["error"]}}}}}}},"/v1/parking-lots":{"get":{"tags":["parking-lots"],"summary":"駐車場を検索（フィルタ + ページング）","description":"公開されている駐車場の一覧を名称・住所・ステータスで絞り込んで返す。\n\n- **認証**: 不要（optionalUser）。JWT があれば文脈に載るが、結果は全ユーザーで同じ。\n- **ページング**: `page` / `limit`（デフォルト 1 ページ 20 件）。レスポンスは `{ items, page, limit, total }`。\n- **フィルタ**: `q` は `name` / `address` の ILIKE 部分一致、`status` はコード値完全一致（例 `active`）。\n- **キャッシュ**: Cache-Control で Cloudflare エッジに 5 分（`s-maxage=300`）、ブラウザ 30 秒。\n- **PostGIS 不要**: 距離検索をしたい場合は `/v1/parking-lots/nearby` を使う。","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","description":"名称・住所の部分一致"},"required":false,"name":"q","in":"query"},{"schema":{"type":"string","description":"コード値（active 等）"},"required":false,"name":"status","in":"query"}],"responses":{"200":{"description":"検索結果","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ParkingLot"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}}},"/v1/parking-lots/nearby":{"get":{"tags":["parking-lots"],"summary":"GPS 周辺の駐車場（PostGIS RPC）","description":"指定座標（`lat` / `lng`）を中心とした半径内の駐車場を距離昇順で返す。\n\n- **計算**: PostgreSQL の `nearby_parking_lots` RPC（PostGIS `ST_DWithin` + `ST_Distance`）。\n- **半径**: `radius_m` 省略時は 1000m。正の数値必須で、不正な値は 400。\n- **レスポンス**: `distance_m` 付きの配列。クライアントは距離表示やソートに利用できる。\n- **キャッシュ**: Edge 60 秒 / ブラウザ 30 秒。GPS は高頻度更新になるので TTL は短め。\n- **モバイル主用途**: マップ初期ロード、'近くの駐車場' ボタン、駐車開始画面の候補リスト。","parameters":[{"schema":{"type":"string","example":"35.6762"},"required":true,"name":"lat","in":"query"},{"schema":{"type":"string","example":"139.6503"},"required":true,"name":"lng","in":"query"},{"schema":{"type":"string","example":"1000"},"required":false,"name":"radius_m","in":"query"}],"responses":{"200":{"description":"周辺一覧（距離昇順）","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NearbyParkingLot"}}}}},"400":{"description":"lat/lng/radius_m が不正","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/parking-lots/{id}":{"get":{"tags":["parking-lots"],"summary":"駐車場詳細（画像・タグ・属性を含む）","description":"指定 ID の駐車場の詳細情報を返す。モバイルの詳細画面 / Web SSG の個別ページで利用する。\n\n- **include**: `images` / `tags` / `pricing_rules` / `operator` のうち必要なものをカンマ区切りで指定。不要なら省略して軽量取得。\n- **寸法・制約**: `max_height_m` / `max_width_m` / `max_length_m` / `max_weight_t` / `min_clearance_cm` / `max_parking_duration_min` を含むので、車両適合チェックはクライアント側で実施可能。\n- **operator**: Include 時は `{ id, name, slug, color }` の運営会社サマリを返す。\n- **キャッシュ**: Edge 5 分。存在しない ID は 404。","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","description":"カンマ区切りで追加取得 (images / tags / pricing_rules / operator)","example":"images,tags,pricing_rules,operator"},"required":false,"name":"include","in":"query"}],"responses":{"200":{"description":"駐車場詳細","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ParkingLotWithDetail"}}}},"404":{"description":"存在しない","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/parking-lots/{id}/pricing-rules":{"get":{"tags":["parking-lots"],"summary":"駐車場の料金ルール一覧","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"料金ルール","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PricingRule"}}}}}}}},"/v1/parking-lots/{id}/nearby-stations":{"get":{"tags":["parking-lots"],"summary":"駐車場の近傍駅 TOP 5（距離昇順）","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"近傍駅一覧","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NearbyStationItem"}}}}}}}},"/v1/parking-lots/{id}/images":{"get":{"tags":["parking-lots"],"summary":"駐車場の画像一覧","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"画像一覧","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ParkingLotImage"}}}}}}}},"/v1/parking-lots/{id}/calc-fee":{"post":{"tags":["parking-lots"],"summary":"入庫〜出庫の料金を試算（RPC calc_parking_fee）","description":"指定した駐車場で `entry_at` 〜 `exit_at` に駐車したと仮定したときの料金を試算する。\n\n- **計算ロジック**: PostgreSQL の `calc_parking_fee` RPC（時間帯ルール + 上限 cap + 車種別割増をまとめて評価）。\n- **レスポンス**: `total_amount`（JPY 整数）と `breakdown`（時間帯別の内訳配列）。モバイルの料金シミュレータ画面で利用。\n- **冪等**: 副作用なし。何度叩いても同じ入力なら同じ結果。\n- **認証**: 不要。ゲストでも試算できる（駐車開始は別 API で要認証）。","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeeCalcRequest"}}}},"responses":{"200":{"description":"試算結果","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeeCalcResponse"}}}},"400":{"description":"時刻指定が不正","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/parking-lots/{id}/reviews":{"get":{"tags":["reviews"],"summary":"駐車場の承認済みレビュー一覧","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","enum":["newest","rating"]},"required":false,"name":"sort","in":"query"}],"responses":{"200":{"description":"レビュー一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Review"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}},"post":{"tags":["reviews"],"summary":"レビューを投稿（status=pending で作成）","description":"ログインユーザーとして指定駐車場に対するレビュー（星評価 + 任意コメント）を投稿する。\n\n- **認証**: 必須（Supabase JWT）。`requireUser` ミドルウェアを通過する必要がある。\n- **初期ステータス**: `pending`。管理者モデレーションで `approved` / `rejected` に遷移し、承認済みのみ公開一覧に出る。\n- **画像**: このエンドポイントでは画像は受け取らない。レビュー写真は別途 `/v1/storage/upload-url` で asset を作ってから紐付ける運用。\n- **重複投稿**: 同一ユーザーが同一駐車場にすでにレビューを持つ場合は編集にフォールバックさせる（`/v1/me/reviews/{id}` PATCH）。","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"rating":{"type":"integer","minimum":1,"maximum":5},"comment":{"type":"string","nullable":true,"maxLength":2000}},"required":["rating"]}}}},"responses":{"200":{"description":"作成済みレビュー","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Review"}}}},"401":{"description":"未認証","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/parking-sessions":{"post":{"tags":["parking-sessions"],"summary":"駐車開始（RPC create_parking_session）","description":"ログインユーザーが指定駐車場に駐車を開始したことを記録する。\n\n- **RPC**: `create_parking_session` が `parking_sessions` に 1 行 INSERT し、`session_id` を返す。\n- **冪等**: `client_request_id`（任意 uuid）を必須で受け取り、同一キーで再送しても 1 セッションしか作らない。ネットワーク再送・二重タップ対策。\n- **GPS**: `start_lat` / `start_lng` 省略可。地図上でのピン表示用なので精度は粗くて良い。\n- **認証**: 必須。`user_id` は JWT から取得し、クライアント入力を信用しない。\n- **次の動線**: 終了時は `POST /v1/parking-sessions/{id}/finalize`、5 分以内のキャンセルは `/cancel`。","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"parking_lot_id":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"vehicle_type":{"type":"string","default":"sedan"},"start_lat":{"type":"number"},"start_lng":{"type":"number"},"client_request_id":{"type":"string","description":"冪等キー（再送時に重複作成を防ぐ）"}},"required":["parking_lot_id","client_request_id"]}}}},"responses":{"200":{"description":"作成結果（セッション詳細）","content":{"application/json":{"schema":{"nullable":true}}}},"401":{"description":"未認証","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/parking-sessions/{id}/finalize":{"post":{"tags":["parking-sessions"],"summary":"駐車終了 + 料金確定（RPC finalize_parking_session）","description":"駐車セッションを終了し、料金を確定する。\n\n- **RPC**: `finalize_parking_session` が `end_at` を確定、`fee_amount` を `calc_parking_fee` と同じロジックで計算して保存する。\n- **冪等**: `client_request_id` で重複終了を防止。すでに終了済みなら現在の料金をそのまま返す。\n- **レスポンス**: `{ total_amount, breakdown }`（calc-fee と同じ形）。モバイルはこれをレシート画面に表示する。\n- **キャンセルとの違い**: finalize は料金発生を確定させる。5 分以内の誤操作取り消しは `/cancel` を使う。","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"exit_at":{"type":"string","format":"date-time"},"client_request_id":{"type":"string"}},"required":["client_request_id"]}}}},"responses":{"200":{"description":"確定結果","content":{"application/json":{"schema":{"nullable":true}}}}}}},"/v1/parking-sessions/{id}/cancel":{"post":{"tags":["parking-sessions"],"summary":"駐車キャンセル（RPC cancel_parking_session）","description":"駐車開始直後の誤操作を取り消す（5 分以内）。料金は発生しない。\n\n- **RPC**: `cancel_parking_session` がセッションを `cancelled` に遷移し、`end_at` を `start_at` 近傍に寄せる。\n- **制限**: 開始から 5 分を超えた場合は finalize しか受け付けない（RPC 側で弾く）。\n- **冪等**: すでに cancelled なら no-op で 200 を返す。","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"キャンセル結果","content":{"application/json":{"schema":{"nullable":true}}}}}}},"/v1/tags":{"get":{"tags":["tags"],"summary":"タグ一覧（マスター）","responses":{"200":{"description":"タグ一覧","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Tag"}}}}}}}},"/v1/articles":{"get":{"tags":["articles"],"summary":"公開記事の一覧（published のみ）","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"category","in":"query"},{"schema":{"type":"string"},"required":false,"name":"tag","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ArticleListItem"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}}},"/v1/articles/by-author/{slug}":{"get":{"tags":["articles"],"summary":"author_slug 指定の公開記事一覧","parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"responses":{"200":{"description":"記事一覧","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ArticleListItem"}}}}}}}},"/v1/articles/{slug}":{"get":{"tags":["articles"],"summary":"記事本体を slug から取得","parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"responses":{"200":{"description":"記事","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Article"}}}},"404":{"description":"存在しない","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/ads":{"get":{"tags":["ads"],"summary":"配信対象の広告一覧（期間・ステータスで絞り込み済み）","parameters":[{"schema":{"type":"string","description":"article_body など特定枠を絞る"},"required":false,"name":"placement","in":"query"}],"responses":{"200":{"description":"広告一覧","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Ad"}}}}}}}},"/v1/support/tickets":{"post":{"tags":["support"],"summary":"サポートチケットを作成","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"subject":{"type":"string","minLength":1,"maxLength":200},"body":{"type":"string","minLength":1,"maxLength":10000},"category":{"type":"string","default":"other"},"priority":{"type":"string","enum":["low","medium","high","urgent"],"default":"medium"},"user_email":{"type":"string","format":"email"},"user_name":{"type":"string","minLength":1,"maxLength":100}},"required":["subject","body","user_email","user_name"]}}}},"responses":{"200":{"description":"作成済みチケット","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupportTicket"}}}}}},"get":{"tags":["support"],"summary":"自分のサポートチケット一覧","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"status","in":"query"}],"responses":{"200":{"description":"チケット一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/SupportTicket"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}}},"/v1/error-reports":{"post":{"tags":["error-reports"],"summary":"駐車場情報の誤り報告を投稿","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"parking_lot_id":{"type":"string","nullable":true,"format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"parking_lot_name":{"type":"string","minLength":1,"maxLength":200},"report_type":{"type":"string","enum":["price","hours","location","closed","facilities","other"],"default":"other"},"description":{"type":"string","minLength":1,"maxLength":4000},"user_email":{"type":"string","format":"email"},"user_name":{"type":"string","minLength":1,"maxLength":100},"photo_asset_id":{"type":"string","nullable":true,"format":"uuid","example":"00000000-0000-0000-0000-000000000000"}},"required":["parking_lot_name","description","user_email","user_name"]}}}},"responses":{"200":{"description":"作成済み報告","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorReport"}}}}}}},"/v1/sponsors":{"get":{"tags":["sponsors"],"summary":"公開中スポンサー一覧（地図ピン・Web ハブ向け）","responses":{"200":{"description":"スポンサー一覧","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AreaSponsor"}}}}}}}},"/v1/sponsors/nearby":{"get":{"tags":["sponsors"],"summary":"指定座標の半径内にあるスポンサー","description":"指定座標の半径内で公開中のスポンサー施設を距離昇順で返す。駐車中のユーザーに「近くでお得な店」を提案するのに使う。\n\n- **RPC**: `nearby_sponsors(lng, lat, radius_m)`（PostGIS）を Hyperdrive 越しに呼ぶ。\n- **半径**: 省略時 1500m。`radius_m` 正値必須。\n- **耐障害性**: RPC 未登録などで失敗しても 200 + 空配列で返す（SSG ビルドや地図 UI を壊さない方針）。\n- **Cron**: 同じ RPC を 10 分毎の `handleSponsorProximity` でも利用。駐車中ユーザーに近接通知を送る。","parameters":[{"schema":{"type":"string","example":"139.6503"},"required":true,"name":"lng","in":"query"},{"schema":{"type":"string","example":"35.6762"},"required":true,"name":"lat","in":"query"},{"schema":{"type":"string","example":"1500"},"required":false,"name":"radius_m","in":"query"}],"responses":{"200":{"description":"近傍スポンサー一覧","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AreaSponsor"}}}}},"400":{"description":"lng/lat 不正","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/sponsors/{id}/checkin":{"post":{"tags":["sponsors"],"summary":"スポンサー施設にチェックイン（EXP 付与は DB トリガー経由を想定）","description":"ログインユーザーがスポンサー施設に来店したことを記録する。ゲーミフィケーション（EXP / バッジ）のトリガー。\n\n- **認証**: 必須。`sponsor_checkins` に行を追加し、DB トリガーが EXP / バッジ進捗を自動更新する。\n- **重複防止**: 同一ユーザー × 同一スポンサーのチェックインは日単位で制限（DB 制約で重複弾く）。\n- **GPS 検証**: body に現在位置が含まれる場合、サーバ側でスポンサー座標との距離を検証し、遠距離からの不正チェックインを防ぐ。","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"lat":{"type":"number"},"lng":{"type":"number"},"memo":{"type":"string","maxLength":500}}}}}},"responses":{"200":{"description":"チェックイン結果","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"checked_in_at":{"type":"string"}},"required":["id","checked_in_at"]}}}},"401":{"description":"未認証","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/themes":{"get":{"tags":["themes"],"summary":"公開中テーマ一覧","responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ThemeListItem"}}}}}}}},"/v1/subscription-plans":{"get":{"tags":["subscriptions"],"summary":"購読プラン一覧（公開）","responses":{"200":{"description":"プラン一覧","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SubscriptionPlan"}}}}}}}},"/v1/storage/upload-url":{"post":{"tags":["storage"],"summary":"Cloudflare R2 の presigned PUT URL を発行","description":"画像・PDF 等のバイナリアップロード用に、Cloudflare R2 に PUT できる presigned URL を返す。\n\n- **2 ステップ**: (1) このエンドポイントで URL + asset_id を取得 → (2) クライアントが presigned URL に直接 `PUT` する。バイト列は Workers を経由しない（エグレス削減）。\n- **DB 副作用**: Workers は `assets` テーブルに行を先に INSERT する（`uploaded_by` / `s3_key` / `mime_type` / `file_name` 等）。PUT 失敗時は孤立する可能性があるので、クライアント側は PUT 後に親エンティティに `asset_id` を紐付ける。\n- **s3_key 生成規則**: `{category}/{yyyymm}/{uuid}_{sanitized-name}`。衝突しないので再試行も安全。\n- **公開 URL**: `R2_PUBLIC_BASE=https://cdn.parky.co.jp` が設定されていれば匿名 GET 可能な URL が `public_url` で返る。\n- **認証**: 必須（`requireUser`）。`uploaded_by` に JWT 由来の `user_id` を入れ、後から監査可能にする。\n- **Content-Type 注意**: presign で `content_type` を指定した場合、クライアントの PUT ヘッダも完全一致させないと 403 になる。","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"file_name":{"type":"string","minLength":1,"maxLength":300},"file_size":{"type":"integer","minimum":0,"exclusiveMinimum":true},"mime_type":{"type":"string","minLength":1},"category":{"type":"string","default":"other"},"entity_type":{"type":"string","nullable":true},"entity_id":{"type":"string","nullable":true,"format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"is_public":{"type":"boolean","default":true}},"required":["file_name","file_size","mime_type"]}}}},"responses":{"200":{"description":"presigned URL + メタ","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadUrlResponse"}}}}}}},"/v1/storage/assets/{id}/finalize":{"post":{"tags":["storage"],"summary":"アップロード完了をコミット（メタ調整が必要な場合に）","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"entity_type":{"type":"string","nullable":true},"entity_id":{"type":"string","nullable":true,"format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"is_public":{"type":"boolean"}}}}}},"responses":{"200":{"description":"確定後の asset","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Asset"}}}}}}},"/v1/search/lots":{"get":{"tags":["search-lots"],"summary":"active 駐車場を料金/属性/タグ付きで一括取得（SSG ビルド向け）","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"最大件数（デフォルト 5000）","example":"5000"},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"駐車場ダンプ","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/SearchLot"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}}},"/v1/search/ai":{"post":{"tags":["search"],"summary":"自然言語クエリを駐車場検索条件にパース","description":"ユーザーの自然言語入力（例: '渋谷駅から徒歩 5 分以内で 1 時間 500 円以下の屋根付き駐車場'）を構造化検索フィルタに変換する。\n\n- **プロバイダ**: Anthropic Claude (primary) → Google Gemini → OpenAI GPT のフォールバック順。全て Cloudflare AI Gateway (`parky-ai-gateway`) 経由でキャッシュ・ログ・リトライを得る。\n- **契約**: 各プロバイダに同一 JSON Schema を与え、tool_use / function_calling で構造化レスポンスを強制する。\n- **API キー**: Supabase Vault に暗号化保存。Workers が `vault_read_secret` RPC で復号して利用（レスポンスには漏れない）。\n- **レート制限**: `RATE_LIMIT_USER` binding で user_id 単位 10 req / 60 秒。超過時 429。\n- **usage ログ**: Analytics Engine (`parky_ai_usage`) + PG `ai_usage_logs` に dual write。\n- **status**: `parsed`（query に構造化結果）/ `need_info`（聞き返し文 reply）/ `error`（プロバイダ全滅）をクライアントが分岐で処理する。","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiSearchRequest"}}}},"responses":{"200":{"description":"パース結果 or 聞き返し or エラー（クライアントは status で判別）","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiSearchResponse"}}}},"401":{"description":"未認証","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"レート制限","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"利用可能な AI プロバイダーなし","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/hubs/publishable":{"get":{"tags":["hubs"],"summary":"公開可能なハブ（station, 在庫 >= min）一覧","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"最低駐車場件数 (default 5)","example":"1"},"required":false,"name":"min","in":"query"}],"responses":{"200":{"description":"ハブ一覧","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/HubPublishableItem"}}}}}}}},"/v1/hubs/by-slug/{prefSlug}/{citySlug}/{spotSlug}":{"get":{"tags":["hubs"],"summary":"slug 指定で単一駅ハブを取得","parameters":[{"schema":{"type":"string","minLength":1},"required":true,"name":"prefSlug","in":"path"},{"schema":{"type":"string","minLength":1},"required":true,"name":"citySlug","in":"path"},{"schema":{"type":"string","minLength":1},"required":true,"name":"spotSlug","in":"path"}],"responses":{"200":{"description":"ハブ 1 件","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HubPublishableItem"}}}},"404":{"description":"該当なし","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"nullable":true}}}}}}}}},"/v1/hubs/{stationId}/parking-lots":{"get":{"tags":["hubs"],"summary":"駅ハブ近傍の駐車場（距離昇順）","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"stationId","in":"path"}],"responses":{"200":{"description":"駐車場一覧","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/HubParkingLotItem"}}}}}}}},"/v1/meta/activity-types":{"get":{"tags":["meta"],"summary":"全 activity_type の定義と metadata JSON Schema を返す","description":"BFF が `award_user_activity` に emit する全 activity_type のカタログ。\n\n- 各エントリに JSON Schema 7 形式の `metadata_schema` を含む。\n- `emitted=false` は seed には定義されているが BFF 側 emit は未配線の予約済み種別。\n- SSoT: `api/src/lib/activity-types.ts`。新しい種別を足したら当エンドポイントの出力にも自動反映される。","responses":{"200":{"description":"カタログ全件","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivityTypesResponse"}}}}}}},"/v1/admin/admins":{"get":{"tags":["admin","admins"],"summary":"管理者一覧（ページング + フィルタ + ソート）","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"q","in":"query"},{"schema":{"type":"string"},"required":false,"name":"status","in":"query"},{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":false,"name":"role_id","in":"query"},{"schema":{"type":"string","enum":["name","email","created_at","last_login_at"]},"required":false,"name":"sort","in":"query"},{"schema":{"type":"string","enum":["asc","desc"]},"required":false,"name":"order","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Admin"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}},"post":{"tags":["admin","admins"],"summary":"管理者を新規作成（Auth ユーザーも作成し初期 PW を返す）","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email"},"name":{"type":"string","minLength":1,"maxLength":100},"role_id":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"password":{"type":"string","minLength":8,"maxLength":128}},"required":["email","name","role_id"]}}}},"responses":{"200":{"description":"作成済み + 発行した初期 PW","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Admin"},{"type":"object","properties":{"initial_password":{"type":"string","nullable":true}},"required":["initial_password"]}]}}}}}}},"/v1/admin/admins/me/notification-prefs":{"get":{"tags":["admin","admins"],"summary":"自分（ログイン中の管理者）の通知設定を取得","responses":{"200":{"description":"通知設定 JSON（未設定キーはデフォルト値で埋める）","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminNotificationPrefs"}}}}}},"put":{"tags":["admin","admins"],"summary":"自分（ログイン中の管理者）の通知設定を更新","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminNotificationPrefs"}}}},"responses":{"200":{"description":"更新後の通知設定 JSON","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminNotificationPrefs"}}}}}}},"/v1/admin/admins/{id}":{"patch":{"tags":["admin","admins"],"summary":"管理者情報を更新（name / role_id / status）","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100},"role_id":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"status":{"type":"string"}}}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Admin"}}}},"404":{"description":"存在しない","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["admin","admins"],"summary":"管理者を削除（Auth ユーザーも同時に削除）","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"204":{"description":"削除成功"}}}},"/v1/admin/admins/{id}/reset-password":{"post":{"tags":["admin","admins"],"summary":"管理者 PW をリセットして新 PW を返す","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"発行した PW","content":{"application/json":{"schema":{"type":"object","properties":{"new_password":{"type":"string"}},"required":["new_password"]}}}}}}},"/v1/admin/roles":{"get":{"tags":["admin","roles"],"summary":"ロール一覧","responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Role"}},"page":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":0},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}},"post":{"tags":["admin","roles"],"summary":"ロールを作成","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":50},"description":{"type":"string","maxLength":500,"default":""},"color":{"type":"string","default":"#8a85a0"}},"required":["name"]}}}},"responses":{"200":{"description":"作成済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Role"}}}}}}},"/v1/admin/roles/{id}":{"patch":{"tags":["admin","roles"],"summary":"ロールを更新","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":50},"description":{"type":"string","maxLength":500},"color":{"type":"string"}}}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Role"}}}}}},"delete":{"tags":["admin","roles"],"summary":"ロールを削除（is_system=true は不可）","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"204":{"description":"削除成功"}}}},"/v1/admin/roles/{id}/permissions":{"get":{"tags":["admin","roles"],"summary":"ロール権限一覧","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"権限キー一覧","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"permission":{"type":"string"}},"required":["permission"]}}}}}}},"put":{"tags":["admin","roles"],"summary":"ロール権限マトリクスを一括保存（置き換え）","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"permissions":{"type":"array","items":{"type":"string"}}},"required":["permissions"]}}}},"responses":{"200":{"description":"置き換え後の件数","content":{"application/json":{"schema":{"type":"object","properties":{"role_id":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"count":{"type":"integer"}},"required":["role_id","count"]}}}}}}},"/v1/admin/role-permissions":{"get":{"tags":["admin","roles"],"summary":"全ロール × 権限マップ","responses":{"200":{"description":"role_id → 権限キー配列のマップ","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}}}}}}}},"/v1/admin/parking-lots":{"post":{"tags":["admin","parking-lots"],"summary":"駐車場を作成","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1},"address":{"type":"string","nullable":true},"lat":{"type":"number","nullable":true},"lng":{"type":"number","nullable":true},"status":{"type":"string"},"total_spaces":{"type":"integer","nullable":true},"operating_hours":{"type":"string","nullable":true},"operator_code":{"type":"string","nullable":true},"entry_difficulty":{"type":"string","nullable":true,"enum":["easy","normal","hard"]}},"required":["name"]}}}},"responses":{"200":{"description":"作成済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminParkingLot"}}}}}}},"/v1/admin/parking-lots/{id}":{"patch":{"tags":["admin","parking-lots"],"summary":"駐車場情報を更新","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminParkingLot"}}}}}}},"/v1/admin/parking-lots/{id}/pricing-rules":{"put":{"tags":["admin","parking-lots"],"summary":"料金ルールを丸ごと置き換え","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"rules":{"type":"array","items":{"type":"object","properties":{}}}},"required":["rules"]}}}},"responses":{"200":{"description":"件数","content":{"application/json":{"schema":{"type":"object","properties":{"count":{"type":"integer"}},"required":["count"]}}}}}}},"/v1/admin/parking-lots/{id}/payment-methods":{"put":{"tags":["admin","parking-lots"],"summary":"対応決済手段を一括置き換え","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"methods":{"type":"array","items":{"type":"string"}}},"required":["methods"]}}}},"responses":{"200":{"description":"件数","content":{"application/json":{"schema":{"type":"object","properties":{"count":{"type":"integer"}},"required":["count"]}}}}}}},"/v1/admin/parking-lots/{id}/images":{"post":{"tags":["admin","parking-lots"],"summary":"駐車場に画像を 1 枚追加（asset_id 参照）","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"asset_id":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"is_main":{"type":"boolean","default":false},"sort_order":{"type":"integer"}},"required":["asset_id"]}}}},"responses":{"200":{"description":"追加した画像","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"parking_lot_id":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"asset_id":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"is_main":{"type":"boolean"},"sort_order":{"type":"integer","nullable":true}},"required":["id","parking_lot_id","asset_id","is_main","sort_order"]}}}}}}},"/v1/admin/parking-lots/{id}/images/{imageId}/main":{"patch":{"tags":["admin","parking-lots"],"summary":"画像をメインに設定（既存メインは解除）","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","format":"uuid","example":"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"]}}}}}}},"/v1/admin/parking-lots/{id}/images/{imageId}":{"delete":{"tags":["admin","parking-lots"],"summary":"画像を削除","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"imageId","in":"path"}],"responses":{"204":{"description":"削除成功"}}}},"/v1/admin/parking-lots/{id}/tags":{"post":{"tags":["admin","parking-lots"],"summary":"タグを付与","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"tag_id":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"}},"required":["tag_id"]}}}},"responses":{"200":{"description":"付与成功","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]}},"required":["ok"]}}}}}}},"/v1/admin/parking-lots/{id}/tags/{tagId}":{"delete":{"tags":["admin","parking-lots"],"summary":"タグを解除","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"tagId","in":"path"}],"responses":{"204":{"description":"削除成功"}}}},"/v1/admin/parking-lots/{id}/owners":{"get":{"tags":["admin","parking-lots"],"summary":"紐付きオーナー一覧","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"オーナー一覧","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"owner_id":{"type":"string","format":"uuid"},"owners":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"email":{"type":"string"},"status":{"type":"string"}},"required":["id","name","email","status"]}},"required":["owner_id","owners"]}}}}}}},"post":{"tags":["admin","parking-lots"],"summary":"オーナーを紐付け","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"owner_id":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"}},"required":["owner_id"]}}}},"responses":{"200":{"description":"紐付け成功","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]}},"required":["ok"]}}}}}}},"/v1/admin/parking-lots/engagement-stats":{"get":{"tags":["admin","parking-lots"],"summary":"全駐車場のエンゲージメント統計（保存 / セッション / 検索カウント）","responses":{"200":{"description":"parking_lot_id をキーにしたマップ","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"object","properties":{"parking_lot_id":{"type":"string"},"saved_count":{"type":"integer"},"session_count":{"type":"integer"},"search_count":{"type":"integer"}},"required":["parking_lot_id","saved_count","session_count","search_count"]}}}}}}}},"/v1/admin/parking-lots/{id}/engagement-stats":{"get":{"tags":["admin","parking-lots"],"summary":"単一駐車場のエンゲージメント統計","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"件数","content":{"application/json":{"schema":{"type":"object","properties":{"saved_count":{"type":"integer"},"session_count":{"type":"integer"},"search_count":{"type":"integer"}},"required":["saved_count","session_count","search_count"]}}}}}}},"/v1/admin/parking-lots/import/preview":{"post":{"tags":["admin","parking-lots"],"summary":"Pコレ_Master の取り込みプレビュー（DB は書き込まない）","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"sheet_url":{"type":"string","format":"uri"},"csv_text":{"type":"string"},"only_verified_active":{"type":"boolean"},"limit":{"type":"integer","minimum":0,"exclusiveMinimum":true}}}}}},"responses":{"200":{"description":"プレビュー結果","content":{"application/json":{"schema":{"type":"object","properties":{"total_rows":{"type":"number"},"unknown_headers":{"type":"array","items":{"type":"string"}},"to_create":{"type":"number"},"to_update":{"type":"number"},"unchanged":{"type":"number"},"skipped":{"type":"object","properties":{"disposal":{"type":"number"},"no_place_id":{"type":"number"},"no_name":{"type":"number"}},"required":["disposal","no_place_id","no_name"]},"sample_create":{"type":"array","items":{"type":"object","properties":{"place_id":{"type":"string"},"name":{"type":"string"},"address":{"type":"string","nullable":true},"status":{"type":"string"}},"required":["place_id","name","address","status"]}}},"required":["total_rows","unknown_headers","to_create","to_update","unchanged","skipped","sample_create"]}}}}}}},"/v1/admin/parking-lots/import/commit":{"post":{"tags":["admin","parking-lots"],"summary":"Pコレ_Master を parking_lots に取り込む（UPSERT）","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"sheet_url":{"type":"string","format":"uri"},"csv_text":{"type":"string"},"only_verified_active":{"type":"boolean"},"limit":{"type":"integer","minimum":0,"exclusiveMinimum":true}}}}}},"responses":{"200":{"description":"取り込み結果","content":{"application/json":{"schema":{"type":"object","properties":{"total_rows":{"type":"number"},"created":{"type":"number"},"updated":{"type":"number"},"unchanged":{"type":"number"},"skipped":{"type":"number"},"errors":{"type":"array","items":{"type":"object","properties":{"place_id":{"type":"string"},"message":{"type":"string"}},"required":["place_id","message"]}}},"required":["total_rows","created","updated","unchanged","skipped","errors"]}}}}}}},"/v1/admin/users":{"get":{"tags":["admin","users"],"summary":"ユーザー一覧（ページング）","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"q","in":"query"},{"schema":{"type":"string"},"required":false,"name":"status","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AdminAppUser"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}}},"/v1/admin/users/count":{"get":{"tags":["admin","users"],"summary":"ユーザー総数","responses":{"200":{"description":"件数","content":{"application/json":{"schema":{"type":"object","properties":{"total":{"type":"integer"}},"required":["total"]}}}}}}},"/v1/admin/users/options":{"get":{"tags":["admin","users"],"summary":"選択肢用の軽量ユーザー一覧","parameters":[{"schema":{"type":"string"},"required":false,"name":"q","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$"},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"軽量一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"display_name":{"type":"string"},"email":{"type":"string"}},"required":["id","display_name","email"]}},"page":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":0},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}}},"/v1/admin/users/{id}":{"get":{"tags":["admin","users"],"summary":"ユーザー詳細","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"詳細","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminAppUser"}}}}}}},"/v1/admin/users/bulk-status":{"patch":{"tags":["admin","users"],"summary":"ステータス一括変更","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"ids":{"type":"array","items":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"}},"status":{"type":"string"}},"required":["ids","status"]}}}},"responses":{"200":{"description":"件数","content":{"application/json":{"schema":{"type":"object","properties":{"updated":{"type":"integer"}},"required":["updated"]}}}}}}},"/v1/admin/users/{id}/saved-parking-lots":{"get":{"tags":["admin","users"],"summary":"ユーザーの保存駐車場","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"parking_lot_id":{"type":"string","format":"uuid"},"parking_lots":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"address":{"type":"string","nullable":true}},"required":["id","name","address"]}},"required":["id","parking_lot_id","parking_lots"]}},"page":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":0},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}}},"/v1/admin/users/{id}/exp-progress":{"get":{"tags":["admin","users"],"summary":"EXP 進捗（user_exp と level_definitions をまとめて返す）","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"生データ","content":{"application/json":{"schema":{"type":"object","properties":{"user_exp":{"nullable":true},"levels":{"type":"array","items":{"type":"object","properties":{"level":{"type":"integer"},"required_exp":{"type":"integer"}},"required":["level","required_exp"]}}},"required":["levels"]}}}}}}},"/v1/admin/users/{id}/activity-counts":{"get":{"tags":["admin","users"],"summary":"活動カウント（存在しない場合は null）","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"行 or null","content":{"application/json":{"schema":{"nullable":true}}}}}}},"/v1/admin/tags":{"get":{"tags":["admin","tags"],"summary":"タグ一覧（ページング）","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AdminTag"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}},"post":{"tags":["admin","tags"],"summary":"タグを作成","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":50},"color":{"type":"string","default":"#7c5cfc"},"sort_order":{"type":"integer","default":0},"slug":{"type":"string","nullable":true,"minLength":1,"maxLength":50,"pattern":"^[a-z0-9_]+$"},"category":{"type":"string","nullable":true}},"required":["name"]}}}},"responses":{"200":{"description":"作成済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminTag"}}}}}}},"/v1/admin/tags/{id}":{"patch":{"tags":["admin","tags"],"summary":"タグを更新","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":50},"color":{"type":"string"},"sort_order":{"type":"integer"},"slug":{"type":"string","nullable":true,"minLength":1,"maxLength":50,"pattern":"^[a-z0-9_]+$"},"category":{"type":"string","nullable":true}}}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminTag"}}}}}},"delete":{"tags":["admin","tags"],"summary":"タグを削除（CASCADE で parking_lot_tags も削除）","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"204":{"description":"削除成功"}}}},"/v1/admin/operators":{"get":{"tags":["admin","operators"],"summary":"運営会社一覧（ページング / codes(category='operator') 直参照）","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AdminOperator"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}},"post":{"tags":["admin","operators"],"summary":"運営会社を作成（codes 行を追加）","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100},"slug":{"type":"string","minLength":1,"maxLength":50,"pattern":"^[a-z0-9_]+$"},"color":{"type":"string","default":"#7c5cfc"},"sort_order":{"type":"integer","default":0}},"required":["name","slug"]}}}},"responses":{"200":{"description":"作成済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminOperator"}}}}}}},"/v1/admin/operators/{id}":{"patch":{"tags":["admin","operators"],"summary":"運営会社を更新（codes 行を UPDATE）","parameters":[{"schema":{"type":"string","minLength":1},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100},"slug":{"type":"string","minLength":1,"maxLength":50,"pattern":"^[a-z0-9_]+$"},"color":{"type":"string"},"sort_order":{"type":"integer"}}}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminOperator"}}}}}},"delete":{"tags":["admin","operators"],"summary":"運営会社を削除（ソフトデリート / 紐付き駐車場の operator_code は NULL 化）","parameters":[{"schema":{"type":"string","minLength":1},"required":true,"name":"id","in":"path"}],"responses":{"204":{"description":"削除成功"}}}},"/v1/admin/notifications":{"get":{"tags":["admin","notifications"],"summary":"管理者通知一覧（未削除 + カテゴリ / 既読フィルタ）","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"category","in":"query"},{"schema":{"type":"string","enum":["true","false"]},"required":false,"name":"read","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AdminNotification"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}},"post":{"tags":["admin","notifications"],"summary":"管理者→管理者通知を作成","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":200},"message":{"type":"string","minLength":1,"maxLength":2000},"category":{"type":"string","default":"システム"},"avatar":{"type":"string","default":"P"}},"required":["title","message"]}}}},"responses":{"200":{"description":"作成済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminNotification"}}}}}}},"/v1/admin/notifications/deleted":{"get":{"tags":["admin","notifications"],"summary":"削除済み一覧（ゴミ箱）","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"category","in":"query"},{"schema":{"type":"string","enum":["true","false"]},"required":false,"name":"read","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AdminNotification"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}}},"/v1/admin/notifications/{id}/read":{"post":{"tags":["admin","notifications"],"summary":"既読","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"成功","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]}},"required":["ok"]}}}}}}},"/v1/admin/notifications/read-all":{"post":{"tags":["admin","notifications"],"summary":"全件既読","responses":{"200":{"description":"件数","content":{"application/json":{"schema":{"type":"object","properties":{"updated":{"type":"integer"}},"required":["updated"]}}}}}}},"/v1/admin/notifications/{id}":{"delete":{"tags":["admin","notifications"],"summary":"ソフト削除","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"204":{"description":"成功"}}}},"/v1/admin/notifications/{id}/restore":{"post":{"tags":["admin","notifications"],"summary":"復元","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"成功","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]}},"required":["ok"]}}}}}}},"/v1/admin/notifications/{id}/purge":{"delete":{"tags":["admin","notifications"],"summary":"完全削除","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"204":{"description":"成功"}}}},"/v1/admin/user-notifications":{"get":{"tags":["admin","user-notifications"],"summary":"配信済み・予約通知の一覧（未削除 + ステータス / タイプ / タイトル・本文検索）","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"status","in":"query"},{"schema":{"type":"string"},"required":false,"name":"type","in":"query"},{"schema":{"type":"string"},"required":false,"name":"q","in":"query"},{"schema":{"type":"string","enum":["true","false"]},"required":false,"name":"deleted","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AdminUserNotification"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}},"post":{"tags":["admin","user-notifications"],"summary":"通知を下書き作成","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":200},"body":{"type":"string","minLength":1,"maxLength":2000},"type":{"type":"string","default":"info"},"target":{"type":"string","default":"all"},"scheduled_at":{"type":"string","nullable":true,"format":"date-time"}},"required":["title","body"]}}}},"responses":{"200":{"description":"作成済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminUserNotification"}}}}}}},"/v1/admin/user-notifications/deleted":{"get":{"tags":["admin","user-notifications"],"summary":"削除済み一覧（ゴミ箱）","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AdminUserNotification"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}}},"/v1/admin/user-notifications/{id}":{"patch":{"tags":["admin","user-notifications"],"summary":"通知を更新","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminUserNotification"}}}}}},"delete":{"tags":["admin","user-notifications"],"summary":"ソフト削除","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"204":{"description":"成功"}}}},"/v1/admin/user-notifications/{id}/send":{"post":{"tags":["admin","user-notifications"],"summary":"FCM 配信キューに enqueue（非同期 fan-out）","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"202":{"description":"キューに投入完了。実配信は consumer が行う","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DispatchEnqueued"}}}},"503":{"description":"FCM 未設定 or キュー未設定","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}},"required":["error"]}}}}}}},"/v1/admin/user-notifications/{id}/restore":{"post":{"tags":["admin","user-notifications"],"summary":"復元","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"成功","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]}},"required":["ok"]}}}}}}},"/v1/admin/user-notifications/{id}/purge":{"delete":{"tags":["admin","user-notifications"],"summary":"完全削除","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"204":{"description":"成功"}}}},"/v1/admin/reviews":{"get":{"tags":["admin","reviews"],"summary":"モデレーション用レビュー一覧","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"status","in":"query"},{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":false,"name":"parking_lot_id","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AdminReview"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}},"post":{"tags":["admin","reviews"],"summary":"レビューを新規作成（管理者入力）","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"parking_lot_id":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"user_id":{"type":"string","nullable":true,"format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"user_name":{"type":"string","nullable":true},"rating":{"type":"integer","minimum":1,"maximum":5},"comment":{"type":"string","nullable":true},"status":{"type":"string","default":"approved"}},"required":["parking_lot_id","rating"]}}}},"responses":{"200":{"description":"作成済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminReview"}}}}}}},"/v1/admin/reviews/{id}":{"patch":{"tags":["admin","reviews"],"summary":"レビューを承認 / 却下 / 管理メモ更新","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["pending","approved","rejected","hidden"]},"admin_note":{"type":"string","nullable":true}}}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminReview"}}}}}},"delete":{"tags":["admin","reviews"],"summary":"レビューを削除（ポリシー違反等）","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"204":{"description":"成功"}}}},"/v1/admin/support/tickets":{"get":{"tags":["admin","support"],"summary":"サポートチケット一覧","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"status","in":"query"},{"schema":{"type":"string"},"required":false,"name":"priority","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AdminSupportTicket"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}}},"/v1/admin/support/tickets/{id}":{"get":{"tags":["admin","support"],"summary":"チケット詳細","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"1件","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminSupportTicket"}}}}}},"patch":{"tags":["admin","support"],"summary":"チケットを更新","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminSupportTicket"}}}}}}},"/v1/admin/support/tickets/bulk-status":{"patch":{"tags":["admin","support"],"summary":"ステータス一括変更","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"ids":{"type":"array","items":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"}},"status":{"type":"string"}},"required":["ids","status"]}}}},"responses":{"200":{"description":"件数","content":{"application/json":{"schema":{"type":"object","properties":{"updated":{"type":"integer"}},"required":["updated"]}}}}}}},"/v1/admin/error-reports":{"get":{"tags":["admin","error-reports"],"summary":"誤情報報告一覧","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"status","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AdminErrorReport"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}},"post":{"tags":["admin","error-reports"],"summary":"誤情報報告を新規作成（管理者入力）","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"parking_lot_id":{"type":"string","nullable":true,"format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"parking_lot_name":{"type":"string","nullable":true},"user_name":{"type":"string","nullable":true},"description":{"type":"string","minLength":1},"status":{"type":"string","default":"new"},"category":{"type":"string","nullable":true},"memo":{"type":"string","nullable":true}},"required":["description"]}}}},"responses":{"200":{"description":"作成済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminErrorReport"}}}}}}},"/v1/admin/error-reports/{id}":{"get":{"tags":["admin","error-reports"],"summary":"誤情報報告 1 件（parking_lot join 付き）","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"1 件","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/AdminErrorReport"},{"type":"object","properties":{"parking_lot":{"nullable":true}}}]}}}}}},"patch":{"tags":["admin","error-reports"],"summary":"報告を更新","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminErrorReport"}}}}}}},"/v1/admin/error-reports/bulk":{"patch":{"tags":["admin","error-reports"],"summary":"ステータス or 担当を一括変更","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"ids":{"type":"array","items":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"}},"patch":{"type":"object","properties":{}}},"required":["ids","patch"]}}}},"responses":{"200":{"description":"件数","content":{"application/json":{"schema":{"type":"object","properties":{"updated":{"type":"integer"}},"required":["updated"]}}}}}}},"/v1/admin/tasks":{"get":{"tags":["admin","tasks"],"summary":"タスク横断一覧","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"task_kind","in":"query"},{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":false,"name":"assignee_id","in":"query"},{"schema":{"type":"string"},"required":false,"name":"urgency","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AdminTask"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}}},"/v1/admin/tasks/{id}":{"patch":{"tags":["admin","tasks"],"summary":"タスクを更新（担当・期日・緊急度・メモ）","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminTask"}}}}}}},"/v1/admin/tasks/by-ref":{"put":{"tags":["admin","tasks"],"summary":"ref_id 指定で upsert（サポート/報告/申請から呼ぶ）","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"task_kind":{"type":"string","enum":["misinformation_report","support","owner_application","parking_new_registration"]},"ref_id":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"assignee_id":{"type":"string","nullable":true,"format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"urgency":{"type":"string","enum":["urgent","high","medium","low"]},"due_at":{"type":"string","nullable":true,"format":"date-time"},"memo":{"type":"string","nullable":true}},"required":["task_kind","ref_id"]}}}},"responses":{"200":{"description":"upsert 後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminTask"}}}}}}},"/v1/admin/articles":{"get":{"tags":["admin","articles"],"summary":"記事一覧（下書き含む全ステータス + タイトル検索）","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"status","in":"query"},{"schema":{"type":"string"},"required":false,"name":"category","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/AdminArticle"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}},"post":{"tags":["admin","articles"],"summary":"記事を作成","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"作成済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminArticle"}}}}}}},"/v1/admin/articles/{id}":{"patch":{"tags":["admin","articles"],"summary":"記事を更新","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminArticle"}}}}}},"delete":{"tags":["admin","articles"],"summary":"記事を削除","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"204":{"description":"成功"}}}},"/v1/admin/ads":{"get":{"tags":["admin","ads"],"summary":"広告一覧（管理 + 名前検索）","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"status","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/AdminAd"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}},"post":{"tags":["admin","ads"],"summary":"広告を作成","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"作成済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminAd"}}}}}}},"/v1/admin/ads/{id}":{"patch":{"tags":["admin","ads"],"summary":"広告を更新","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminAd"}}}}}},"delete":{"tags":["admin","ads"],"summary":"広告を削除","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"204":{"description":"成功"}}}},"/v1/admin/boosts":{"get":{"tags":["admin","boosts"],"summary":"ブースト一覧（owner / lot / status / name 検索）","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":false,"name":"owner_id","in":"query"},{"schema":{"type":"string","format":"uuid","example":"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"},"required":false,"name":"q","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AdminBoost"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}},"post":{"tags":["admin","boosts"],"summary":"ブーストを作成","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"作成済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminBoost"}}}}}}},"/v1/admin/boosts/{id}":{"patch":{"tags":["admin","boosts"],"summary":"ブーストを更新","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminBoost"}}}}}}},"/v1/admin/sponsors":{"get":{"tags":["admin","sponsors"],"summary":"スポンサー一覧（管理 + 各種フィルタ）","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"status","in":"query"},{"schema":{"type":"string"},"required":false,"name":"category","in":"query"},{"schema":{"type":"string"},"required":false,"name":"q","in":"query"},{"schema":{"type":"string","enum":["true","false"]},"required":false,"name":"include_deleted","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AdminSponsor"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}},"post":{"tags":["admin","sponsors"],"summary":"スポンサーを作成","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"作成済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminSponsor"}}}}}}},"/v1/admin/sponsors/{id}":{"patch":{"tags":["admin","sponsors"],"summary":"スポンサーを更新","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminSponsor"}}}}}},"delete":{"tags":["admin","sponsors"],"summary":"スポンサーをソフト削除","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"204":{"description":"成功"}}}},"/v1/admin/owners":{"get":{"tags":["admin","owners"],"summary":"オーナー一覧（ページング + フィルタ）","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"q","in":"query"},{"schema":{"type":"string"},"required":false,"name":"owner_type","in":"query"},{"schema":{"type":"string"},"required":false,"name":"status","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AdminOwner"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}},"post":{"tags":["admin","owners"],"summary":"オーナーを作成","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"作成済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminOwner"}}}}}}},"/v1/admin/owners/credits":{"get":{"tags":["admin","owners"],"summary":"全オーナーのクレジット残高一覧（残高 DESC）","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AdminOwnerCredit"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}}},"/v1/admin/owners/{id}":{"patch":{"tags":["admin","owners"],"summary":"オーナーを更新","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminOwner"}}}}}}},"/v1/admin/owners/{id}/parking-lots":{"get":{"tags":["admin","owners"],"summary":"オーナーが管理する駐車場一覧","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"parking_lot_id":{"type":"string","format":"uuid"},"parking_lots":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"address":{"type":"string","nullable":true},"status":{"type":"string","nullable":true}},"required":["id","name","address","status"]}},"required":["parking_lot_id","parking_lots"]}}}}}}}},"/v1/admin/owners/{id}/credit":{"get":{"tags":["admin","owners"],"summary":"オーナーのクレジット残高","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"残高","content":{"application/json":{"schema":{"type":"object","properties":{"owner_id":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"balance":{"type":"integer"},"total_purchased":{"type":"integer"},"total_consumed":{"type":"integer"}},"required":["owner_id","balance","total_purchased","total_consumed"]}}}}}}},"/v1/admin/owners/{id}/credit-transactions":{"get":{"tags":["admin","owners"],"summary":"クレジット取引履歴","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"履歴","content":{"application/json":{"schema":{"type":"array","items":{"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","nullable":true},"boost_id":{"type":"string","nullable":true,"format":"uuid"},"created_at":{"type":"string"}},"required":["id","owner_id","type","amount","balance_after","description","boost_id","created_at"]}}}}}}},"post":{"tags":["admin","owners"],"summary":"クレジット調整（チャージ・ボーナス）","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string"},"amount":{"type":"integer"},"description":{"type":"string","maxLength":500}},"required":["type","amount"]}}}},"responses":{"200":{"description":"追加した取引","content":{"application/json":{"schema":{"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","nullable":true},"created_at":{"type":"string"}},"required":["id","owner_id","type","amount","balance_after","description","created_at"]}}}}}}},"/v1/admin/owner-applications":{"get":{"tags":["admin","owners"],"summary":"オーナー申請一覧（ページング + フィルタ）","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"status","in":"query"},{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":false,"name":"parking_lot_id","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/AdminOwnerApplication"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}}},"/v1/admin/owner-applications/{id}":{"patch":{"tags":["admin","owners"],"summary":"申請ステータスを更新","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminOwnerApplication"}}}}}}},"/v1/admin/owner-applications/{id}/approve":{"post":{"tags":["admin","owners"],"summary":"申請を承認（owner 作成 + parking_lot_owners 連携 + ステータス更新）","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"承認結果","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"application_id":{"type":"string","format":"uuid"},"owner_id":{"type":"string","nullable":true,"format":"uuid"},"invite":{"type":"object","properties":{"status":{"type":"string","enum":["skipped","sent","error"]},"error":{"type":"string","nullable":true}},"required":["status","error"]}},"required":["ok","application_id","owner_id","invite"]}}}}}}},"/v1/admin/activity-logs":{"get":{"tags":["admin","audit"],"summary":"監査ログ（ページング）","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"admin_id","in":"query"},{"schema":{"type":"string"},"required":false,"name":"action","in":"query"},{"schema":{"type":"string"},"required":false,"name":"target_type","in":"query"},{"schema":{"type":"string"},"required":false,"name":"q","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"parking_lot_id","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"user_id","in":"query"},{"schema":{"type":"string"},"required":false,"name":"activity_type","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AdminActivityLog"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}},"post":{"tags":["admin","audit"],"summary":"監査ログを追加（管理者操作の記録）","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","minLength":1},"target_type":{"type":"string","nullable":true},"target_id":{"type":"string","nullable":true},"target_label":{"type":"string","nullable":true},"metadata":{"nullable":true}},"required":["action"]}}}},"responses":{"200":{"description":"作成済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminActivityLog"}}}}}}},"/v1/admin/revenue/monthly":{"get":{"tags":["admin","revenue"],"summary":"月別サマリ（view）","parameters":[{"schema":{"type":"string"},"required":false,"name":"from","in":"query"},{"schema":{"type":"string"},"required":false,"name":"to","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RevenueMonthlyRow"}}}}}}}},"/v1/admin/revenue/transactions":{"get":{"tags":["admin","revenue"],"summary":"トランザクション一覧（ページング + user / plan を LEFT JOIN）","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"channel","in":"query"},{"schema":{"type":"string"},"required":false,"name":"transaction_type","in":"query"},{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":false,"name":"user_id","in":"query"},{"schema":{"type":"string"},"required":false,"name":"from","in":"query"},{"schema":{"type":"string"},"required":false,"name":"to","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/RevenueTransactionWithRelations"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}},"post":{"tags":["admin","revenue"],"summary":"取引を手動追加","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"occurred_at":{"type":"string","format":"date-time"},"channel":{"type":"string"},"transaction_type":{"type":"string"},"amount_minor":{"type":"integer"},"currency":{"type":"string","default":"JPY"},"external_id":{"type":"string"},"description":{"type":"string"},"user_id":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"plan_id":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"}},"required":["occurred_at","channel","transaction_type","amount_minor"]}}}},"responses":{"200":{"description":"作成済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevenueTransaction"}}}}}}},"/v1/admin/revenue/transactions/{id}":{"get":{"tags":["admin","revenue"],"summary":"トランザクション詳細","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"詳細","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevenueTransaction"}}}}}}},"/v1/admin/revenue/aggregate":{"get":{"tags":["admin","revenue"],"summary":"期間集計（合計・件数・平均）","parameters":[{"schema":{"type":"string"},"required":true,"name":"from","in":"query"},{"schema":{"type":"string"},"required":true,"name":"to","in":"query"},{"schema":{"type":"string"},"required":false,"name":"channel","in":"query"}],"responses":{"200":{"description":"集計","content":{"application/json":{"schema":{"type":"object","properties":{"total_amount_minor":{"type":"integer"},"count":{"type":"integer"},"avg_amount_minor":{"type":"number"}},"required":["total_amount_minor","count","avg_amount_minor"]}}}}}}},"/v1/admin/subscriptions":{"get":{"tags":["admin","subscriptions"],"summary":"契約一覧（横断）","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"status","in":"query"},{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":false,"name":"plan_id","in":"query"},{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":false,"name":"user_id","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AdminUserSubscription"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}}},"/v1/admin/subscriptions/active-count":{"get":{"tags":["admin","subscriptions"],"summary":"プラン別アクティブ契約数","responses":{"200":{"description":"プラン別集計","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"plan_id":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"count":{"type":"integer"}},"required":["plan_id","count"]}}}}}}}},"/v1/admin/subscriptions/plans":{"get":{"tags":["admin","subscriptions"],"summary":"購読プラン一覧（管理用。is_active 等のフィルタ対応）","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","enum":["true","false"]},"required":false,"name":"is_active","in":"query"},{"schema":{"type":"string"},"required":false,"name":"billing_period","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AdminSubscriptionPlan"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}}},"/v1/admin/store-integrations":{"get":{"tags":["admin","stores"],"summary":"ストア連携設定一覧","responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/StoreIntegration"}}}}}}}},"/v1/admin/store-sales":{"get":{"tags":["admin","stores"],"summary":"ストア売上日報","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","enum":["play_store","app_store"]},"required":false,"name":"store","in":"query"},{"schema":{"type":"string"},"required":false,"name":"from","in":"query"},{"schema":{"type":"string"},"required":false,"name":"to","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/StoreSalesRow"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}}},"/v1/admin/store-metrics":{"get":{"tags":["admin","stores"],"summary":"アプリ指標日報","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","enum":["play_store","app_store"]},"required":false,"name":"store","in":"query"},{"schema":{"type":"string"},"required":false,"name":"from","in":"query"},{"schema":{"type":"string"},"required":false,"name":"to","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/StoreMetricsRow"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}}},"/v1/admin/store-reviews":{"get":{"tags":["admin","stores"],"summary":"ストアレビュー一覧（未返信フィルタ可）","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","enum":["play_store","app_store"]},"required":false,"name":"store","in":"query"},{"schema":{"type":"string","enum":["true","false"]},"required":false,"name":"unreplied","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/StoreReview"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}}},"/v1/admin/store-sync-runs":{"get":{"tags":["admin","stores"],"summary":"同期ジョブ履歴","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/StoreSyncRun"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}}},"/v1/admin/store-sync-trigger":{"post":{"tags":["admin","stores"],"summary":"ストア同期を手動起動（Play/App Store から売上・メトリクス・レビューを取得）","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"store":{"type":"string","enum":["play_store","app_store","all"],"default":"all"},"task":{"type":"string","enum":["sales","metrics","reviews","all"],"default":"all"}}}}}},"responses":{"202":{"description":"同期ジョブが開始されました","content":{"application/json":{"schema":{"type":"object","properties":{"sync_run_ids":{"type":"array","items":{"type":"string","format":"uuid"}},"count":{"type":"integer"},"status":{"type":"string","enum":["queued"]}},"required":["sync_run_ids","count","status"]}}}}}}},"/v1/admin/badges":{"get":{"tags":["admin","badges"],"summary":"バッジ定義一覧（カテゴリ / アクティビティ / 有効フラグで絞り込み）","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"category","in":"query"},{"schema":{"type":"string"},"required":false,"name":"activity_type","in":"query"},{"schema":{"type":"string","enum":["true","false"]},"required":false,"name":"is_active","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/BadgeDefinition"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}},"post":{"tags":["admin","badges"],"summary":"バッジ定義を作成","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"作成済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadgeDefinition"}}}}}}},"/v1/admin/badges/{id}":{"patch":{"tags":["admin","badges"],"summary":"バッジ定義を更新","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadgeDefinition"}}}}}}},"/v1/admin/badges/{id}/tags":{"put":{"tags":["admin","badges"],"summary":"バッジのタグを一括置き換え","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"tags":{"type":"array","items":{"type":"string"}}},"required":["tags"]}}}},"responses":{"200":{"description":"件数","content":{"application/json":{"schema":{"type":"object","properties":{"count":{"type":"integer"}},"required":["count"]}}}}}}},"/v1/admin/badges/{id}/progress-summary":{"get":{"tags":["admin","badges"],"summary":"バッジ取得状況の集計（total / awarded / in_progress）","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"集計","content":{"application/json":{"schema":{"type":"object","properties":{"badge_id":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"total":{"type":"integer"},"awarded":{"type":"integer"},"in_progress":{"type":"integer"}},"required":["badge_id","total","awarded","in_progress"]}}}}}}},"/v1/admin/badges/{id}/progress-users":{"get":{"tags":["admin","badges"],"summary":"バッジ進捗を持つユーザー一覧（降順）","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","pattern":"^\\d+$"},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"badge_id":{"type":"string","format":"uuid"},"user_id":{"type":"string","nullable":true,"format":"uuid"},"progress":{"type":"number","nullable":true},"awarded":{"type":"boolean"},"awarded_at":{"type":"string","nullable":true},"display_name":{"type":"string","nullable":true}},"required":["badge_id","user_id","progress","awarded","awarded_at","display_name"]}},"page":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":0},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}}},"/v1/admin/badges/{id}/backfill":{"post":{"tags":["admin","badges"],"summary":"特定バッジの進捗を生ログから再計算（RPC）","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"再計算結果","content":{"application/json":{"schema":{"nullable":true}}}}}}},"/v1/admin/badges/backfill-all":{"post":{"tags":["admin","badges"],"summary":"全バッジ進捗を再計算（RPC）","responses":{"200":{"description":"結果","content":{"application/json":{"schema":{"nullable":true}}}}}}},"/v1/admin/exp-rules":{"get":{"tags":["admin","gamification"],"summary":"EXP ルール一覧","responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ActivityExpRule"}},"page":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":0},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}},"post":{"tags":["admin","gamification"],"summary":"EXP ルールを作成","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"activity_type":{"type":"string"},"exp_amount":{"type":"integer","minimum":0},"description":{"type":"string","default":""},"is_active":{"type":"boolean","default":true}},"required":["activity_type","exp_amount"]}}}},"responses":{"200":{"description":"作成済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivityExpRule"}}}}}}},"/v1/admin/exp-rules/{id}":{"patch":{"tags":["admin","gamification"],"summary":"EXP ルールを更新","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivityExpRule"}}}}}},"delete":{"tags":["admin","gamification"],"summary":"EXP ルールを削除","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"204":{"description":"成功"}}}},"/v1/admin/level-definitions":{"get":{"tags":["admin","gamification"],"summary":"レベル定義一覧","responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/LevelDefinition"}},"page":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":0},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}},"put":{"tags":["admin","gamification"],"summary":"レベル定義を一括 upsert","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"rows":{"type":"array","items":{"type":"object","properties":{"level":{"type":"integer","minimum":1},"required_exp":{"type":"integer","minimum":0}},"required":["level","required_exp"]}}},"required":["rows"]}}}},"responses":{"200":{"description":"件数","content":{"application/json":{"schema":{"type":"object","properties":{"count":{"type":"integer"}},"required":["count"]}}}}}}},"/v1/admin/user-levels/recalculate":{"post":{"tags":["admin","gamification"],"summary":"全ユーザーレベルを再計算（RPC）","responses":{"200":{"description":"結果","content":{"application/json":{"schema":{"nullable":true}}}}}}},"/v1/admin/themes":{"get":{"tags":["admin","themes"],"summary":"テーマ一覧（有効フラグ / 無料フラグで絞り込み）","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","enum":["true","false"]},"required":false,"name":"is_active","in":"query"},{"schema":{"type":"string","enum":["true","false"]},"required":false,"name":"is_free","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AdminTheme"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}},"post":{"tags":["admin","themes"],"summary":"テーマを作成","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"作成済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminTheme"}}}}}}},"/v1/admin/themes/{id}":{"patch":{"tags":["admin","themes"],"summary":"テーマを更新","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminTheme"}}}}}},"delete":{"tags":["admin","themes"],"summary":"テーマを削除","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"204":{"description":"成功"}}}},"/v1/admin/themes/{id}/items":{"put":{"tags":["admin","themes"],"summary":"テーマのスロット割当（category → part_id）を一括置換","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"category":{"type":"string"},"part_id":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"}},"required":["category","part_id"]}}},"required":["items"]}}}},"responses":{"200":{"description":"件数","content":{"application/json":{"schema":{"type":"object","properties":{"count":{"type":"integer"}},"required":["count"]}}}}}}},"/v1/admin/themes/{id}/gift":{"post":{"tags":["admin","themes"],"summary":"テーマをユーザーにプレゼント配布（RPC）","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"user_id":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"message":{"type":"string","maxLength":500}},"required":["user_id"]}}}},"responses":{"200":{"description":"配布結果","content":{"application/json":{"schema":{"nullable":true}}}}}}},"/v1/admin/theme-parts":{"get":{"tags":["admin","themes"],"summary":"テーマパーツ一覧（カテゴリで絞り込み）","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"category","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AdminThemePart"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}},"post":{"tags":["admin","themes"],"summary":"テーマパーツを作成","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"作成済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminThemePart"}}}}}}},"/v1/admin/theme-parts/{id}":{"patch":{"tags":["admin","themes"],"summary":"テーマパーツを更新","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminThemePart"}}}}}},"delete":{"tags":["admin","themes"],"summary":"テーマパーツを削除","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"204":{"description":"成功"}}}},"/v1/admin/theme-parts/{id}/tags":{"put":{"tags":["admin","themes"],"summary":"パーツのタグを一括置換","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"tags":{"type":"array","items":{"type":"string"}}},"required":["tags"]}}}},"responses":{"200":{"description":"件数","content":{"application/json":{"schema":{"type":"object","properties":{"count":{"type":"integer"}},"required":["count"]}}}}}}},"/v1/admin/ai-providers":{"get":{"tags":["admin","ai"],"summary":"AI プロバイダー一覧","responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AiProvider"}},"page":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":0},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}}},"/v1/admin/ai-providers/{id}":{"patch":{"tags":["admin","ai"],"summary":"AI プロバイダー設定を更新","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"display_name":{"type":"string"},"model_name":{"type":"string"},"is_enabled":{"type":"boolean"},"priority":{"type":"integer"},"config":{"nullable":true}}}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiProvider"}}}}}}},"/v1/admin/ai-providers/{id}/register-key":{"post":{"tags":["admin","ai"],"summary":"API キーを Vault に登録（RPC vault_insert_secret）","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"api_key":{"type":"string","minLength":10}},"required":["api_key"]}}}},"responses":{"200":{"description":"登録済み","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"vault_secret_id":{"type":"string","format":"uuid"}},"required":["ok","vault_secret_id"]}}}}}}},"/v1/admin/ai-usage-logs":{"get":{"tags":["admin","ai"],"summary":"AI 使用ログ一覧","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"provider_key","in":"query"},{"schema":{"type":"string"},"required":false,"name":"status","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AiUsageLog"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}}},"/v1/admin/codes":{"get":{"tags":["admin","codes"],"summary":"コード一覧（管理用 / id + is_deleted を含む）","parameters":[{"schema":{"type":"string","example":"ja"},"required":false,"name":"lang","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/AdminCode"}}}}}}},"post":{"tags":["admin","codes"],"summary":"コードを新規作成","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"category_id":{"type":"string","minLength":1},"code":{"type":"string","minLength":1},"display_label":{"type":"string","minLength":1},"lang":{"type":"string","default":"ja"},"sort_order":{"type":"integer","nullable":true}},"required":["category_id","code","display_label"]}}}},"responses":{"200":{"description":"作成済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminCode"}}}}}}},"/v1/admin/codes/{id}":{"patch":{"tags":["admin","codes"],"summary":"コードを更新","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminCode"}}}}}},"delete":{"tags":["admin","codes"],"summary":"コードを削除（hard delete）","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"204":{"description":"削除成功"}}}},"/v1/admin/dashboard/metrics":{"get":{"tags":["admin","dashboard"],"summary":"ダッシュボード KPI（6 指標を 1 リクエストで返す）","responses":{"200":{"description":"KPI","content":{"application/json":{"schema":{"type":"object","properties":{"users_total":{"type":"integer"},"active_sessions":{"type":"integer"},"parking_lots_total":{"type":"integer"},"today_sales":{"type":"number"},"pending_error_reports":{"type":"integer"},"pending_reviews":{"type":"integer"}},"required":["users_total","active_sessions","parking_lots_total","today_sales","pending_error_reports","pending_reviews"]}}}}}}},"/v1/admin/activity-log-refs/resolve":{"post":{"tags":["admin","audit"],"summary":"複数種類の ID を一括解決して表示用レコードを返す","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"parking_lot_ids":{"type":"array","items":{"type":"string","format":"uuid"}},"user_ids":{"type":"array","items":{"type":"string","format":"uuid"}},"parking_review_ids":{"type":"array","items":{"type":"string","format":"uuid"}},"user_activity_log_ids":{"type":"array","items":{"type":"string","format":"uuid"}},"error_report_ids":{"type":"array","items":{"type":"string","format":"uuid"}},"support_ticket_ids":{"type":"array","items":{"type":"string","format":"uuid"}}}}}}},"responses":{"200":{"description":"解決結果","content":{"application/json":{"schema":{"type":"object","properties":{"parking_lots":{"type":"array","items":{"nullable":true}},"app_users":{"type":"array","items":{"nullable":true}},"parking_reviews":{"type":"array","items":{"nullable":true}},"user_activity_logs":{"type":"array","items":{"nullable":true}},"error_reports":{"type":"array","items":{"nullable":true}},"support_tickets":{"type":"array","items":{"nullable":true}}},"required":["parking_lots","app_users","parking_reviews","user_activity_logs","error_reports","support_tickets"]}}}}}}},"/v1/admin/parking-sessions":{"get":{"tags":["admin","parking-sessions"],"summary":"駐車セッション一覧（ユーザー / 駐車場を LEFT JOIN して返す）","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"status","in":"query"},{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":false,"name":"user_id","in":"query"},{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":false,"name":"parking_lot_id","in":"query"},{"schema":{"type":"string"},"required":false,"name":"memo","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AdminParkingSessionWithRelations"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}},"post":{"tags":["admin","parking-sessions"],"summary":"駐車セッションを新規作成（管理者代理）","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"user_id":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"parking_lot_id":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"vehicle_id":{"type":"string","nullable":true,"format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"started_at":{"type":"string"},"status":{"type":"string"}},"required":["user_id","parking_lot_id"]}}}},"responses":{"200":{"description":"作成済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminParkingSession"}}}}}}},"/v1/admin/parking-sessions/{id}":{"patch":{"tags":["admin","parking-sessions"],"summary":"駐車セッションを部分更新（メモ・ステータス等）","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminParkingSession"}}}}}}},"/v1/admin/search/ai-parse":{"post":{"tags":["admin","search"],"summary":"AI によるユーザー発話→検索フィルタ変換（現状スタブ）","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["parse"],"default":"parse"},"message":{"type":"string","minLength":1}},"required":["message"]}}}},"responses":{"200":{"description":"パース結果（filters は空オブジェクトを返すことがある）","content":{"application/json":{"schema":{"type":"object","properties":{"filters":{"type":"object","additionalProperties":{"nullable":true}},"explanation":{"type":"string"}},"required":["filters"]}}}}}}},"/v1/admin/instagram/categories":{"get":{"tags":["admin","instagram"],"summary":"スライドカテゴリ一覧","responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IgSlideCategory"}}}}}}},"post":{"tags":["admin","instagram"],"summary":"スライドカテゴリ作成","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","minLength":1},"label":{"type":"string","minLength":1},"prefix":{"type":"string"},"sort_order":{"type":"integer"}},"required":["code","label"]}}}},"responses":{"200":{"description":"作成済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IgSlideCategory"}}}}}}},"/v1/admin/instagram/categories/{code}":{"patch":{"tags":["admin","instagram"],"summary":"スライドカテゴリ更新","parameters":[{"schema":{"type":"string"},"required":true,"name":"code","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string"},"prefix":{"type":"string","nullable":true},"sort_order":{"type":"integer"}}}}}},"responses":{"200":{"description":"更新済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IgSlideCategory"}}}}}},"delete":{"tags":["admin","instagram"],"summary":"スライドカテゴリ削除（ソフトデリート）","parameters":[{"schema":{"type":"string"},"required":true,"name":"code","in":"path"}],"responses":{"200":{"description":"削除完了","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}}}},"/v1/admin/instagram/post-categories":{"get":{"tags":["admin","instagram"],"summary":"投稿カテゴリ一覧","responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IgPostCategory"}}}}}}},"post":{"tags":["admin","instagram"],"summary":"投稿カテゴリ作成","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","minLength":1},"label":{"type":"string","minLength":1},"color":{"type":"string"},"sort_order":{"type":"integer"}},"required":["code","label"]}}}},"responses":{"200":{"description":"作成済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IgPostCategory"}}}}}}},"/v1/admin/instagram/post-categories/{code}":{"patch":{"tags":["admin","instagram"],"summary":"投稿カテゴリ更新","parameters":[{"schema":{"type":"string"},"required":true,"name":"code","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string"},"color":{"type":"string","nullable":true},"sort_order":{"type":"integer"}}}}}},"responses":{"200":{"description":"更新済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IgPostCategory"}}}}}},"delete":{"tags":["admin","instagram"],"summary":"投稿カテゴリ削除（ソフトデリート）","parameters":[{"schema":{"type":"string"},"required":true,"name":"code","in":"path"}],"responses":{"200":{"description":"削除","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}}}},"/v1/admin/instagram/tags":{"get":{"tags":["admin","instagram"],"summary":"タグ一覧","responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IgTag"}}}}}}},"post":{"tags":["admin","instagram"],"summary":"タグ作成（既存 name があれば既存を返す）","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":40},"color":{"type":"string"}},"required":["name"]}}}},"responses":{"200":{"description":"作成 or 既存","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IgTag"}}}}}}},"/v1/admin/instagram/tags/{id}":{"patch":{"tags":["admin","instagram"],"summary":"タグ更新","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"color":{"type":"string","nullable":true}}}}}},"responses":{"200":{"description":"更新済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IgTag"}}}}}},"delete":{"tags":["admin","instagram"],"summary":"タグ削除","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"削除","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}}}},"/v1/admin/instagram/posts/{id}/tags":{"put":{"tags":["admin","instagram"],"summary":"投稿のタグ一括設定","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"tag_ids":{"type":"array","items":{"type":"string"}}},"required":["tag_ids"]}}}},"responses":{"200":{"description":"更新後タグ一覧","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IgTag"}}}}}}}},"/v1/admin/instagram/templates/{id}/tags":{"put":{"tags":["admin","instagram"],"summary":"テンプレートのタグ一括設定","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"tag_ids":{"type":"array","items":{"type":"string"}}},"required":["tag_ids"]}}}},"responses":{"200":{"description":"更新後タグ一覧","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IgTag"}}}}}}}},"/v1/admin/instagram/post-templates":{"get":{"tags":["admin","instagram"],"summary":"投稿テンプレート一覧","responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IgPostTemplate"}}}}}}},"post":{"tags":["admin","instagram"],"summary":"投稿テンプレート作成","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","minLength":1},"name":{"type":"string","minLength":1},"description":{"type":"string"},"slide_refs":{"type":"string"}},"required":["code","name","slide_refs"]}}}},"responses":{"200":{"description":"作成済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IgPostTemplate"}}}}}}},"/v1/admin/instagram/post-templates/{id}":{"patch":{"tags":["admin","instagram"],"summary":"投稿テンプレート更新","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"slide_refs":{"type":"string"}}}}}},"responses":{"200":{"description":"更新済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IgPostTemplate"}}}}}},"delete":{"tags":["admin","instagram"],"summary":"投稿テンプレート削除","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"削除完了","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}}}},"/v1/admin/instagram/ai-providers":{"get":{"tags":["admin","instagram"],"summary":"使える AI プロバイダー一覧（セレクター用、最小情報のみ）","responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"provider_key":{"type":"string"},"display_name":{"type":"string"},"model_name":{"type":"string"},"is_enabled":{"type":"boolean"},"priority":{"type":"integer"}},"required":["id","provider_key","display_name","model_name","is_enabled","priority"]}}}}}}}},"/v1/admin/instagram/templates/analyze-html":{"post":{"tags":["admin","instagram"],"summary":"既存HTMLをAIが解析し、テンプレート化（{{key}}置換 + slot_schema生成）","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"html":{"type":"string","minLength":10},"slide_type":{"type":"string"},"hint":{"type":"string"},"provider_id":{"type":"string"},"model":{"type":"string"}},"required":["html"]}}}},"responses":{"200":{"description":"解析結果","content":{"application/json":{"schema":{"type":"object","properties":{"html_body":{"type":"string"},"slot_schema":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"},"type":{"type":"string"},"required":{"type":"boolean"},"placeholder":{"type":"string"}},"required":["key","label","type"]}},"sample_content":{"type":"object","additionalProperties":{"type":"string"}}},"required":["html_body","slot_schema","sample_content"]}}}}}}},"/v1/admin/instagram/templates":{"get":{"tags":["admin","instagram"],"summary":"テンプレート一覧","responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IgTemplate"}}}}}}},"post":{"tags":["admin","instagram"],"summary":"テンプレート作成","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","minLength":1,"maxLength":20},"name":{"type":"string","minLength":1,"maxLength":100},"slide_type":{"type":"string"},"html_body":{"type":"string","minLength":1},"slot_schema":{"type":"string","default":"[]"},"sample_content":{"type":"string","default":"{}"},"sample_html":{"type":"string","default":""},"sort_order":{"type":"integer","default":0}},"required":["code","name","slide_type","html_body"]}}}},"responses":{"200":{"description":"作成済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IgTemplate"}}}}}}},"/v1/admin/instagram/templates/{id}":{"patch":{"tags":["admin","instagram"],"summary":"テンプレート更新","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100},"slide_type":{"type":"string"},"code":{"type":"string"},"html_body":{"type":"string"},"slot_schema":{"type":"string"},"sample_content":{"type":"string"},"sample_html":{"type":"string"},"sort_order":{"type":"integer"},"is_active":{"type":"integer","minimum":0,"maximum":1}}}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IgTemplate"}}}}}},"delete":{"tags":["admin","instagram"],"summary":"テンプレート削除","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","enum":["0","1"]},"required":false,"name":"force","in":"query"}],"responses":{"204":{"description":"削除成功"},"409":{"description":"使用中のため削除不可","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"slide_count":{"type":"number"}},"required":["error","slide_count"]}}}}}}},"/v1/admin/instagram/posts":{"get":{"tags":["admin","instagram"],"summary":"キャンペーン一覧","parameters":[{"schema":{"type":"string"},"required":false,"name":"status","in":"query"},{"schema":{"type":"string"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"offset","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/IgCampaign"}},"total":{"type":"number"}},"required":["items","total"]}}}}}},"post":{"tags":["admin","instagram"],"summary":"キャンペーン作成","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","minLength":1,"maxLength":20},"title":{"type":"string","minLength":1,"maxLength":200},"theme":{"type":"string"},"area":{"type":"string"},"notes":{"type":"string"},"source_material":{"type":"string"},"post_category_code":{"type":"string"}},"required":["code","title"]}}}},"responses":{"200":{"description":"作成済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IgCampaign"}}}}}}},"/v1/admin/instagram/posts/{id}":{"get":{"tags":["admin","instagram"],"summary":"キャンペーン詳細（slides + caption 含む）","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"詳細","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/IgCampaign"},{"type":"object","properties":{"slides":{"type":"array","items":{"$ref":"#/components/schemas/IgSlide"}},"caption":{"$ref":"#/components/schemas/IgCaption"}},"required":["slides","caption"]}]}}}}}},"patch":{"tags":["admin","instagram"],"summary":"キャンペーン更新","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string"},"theme":{"type":"string","nullable":true},"area":{"type":"string","nullable":true},"status":{"type":"string","enum":["draft","review","scheduled","published","archived"]},"scheduled_at":{"type":"string","nullable":true},"notes":{"type":"string","nullable":true},"source_material":{"type":"string","nullable":true},"post_category_code":{"type":"string","nullable":true},"code":{"type":"string"}}}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IgCampaign"}}}}}},"delete":{"tags":["admin","instagram"],"summary":"キャンペーン削除（CASCADE で slides/caption も削除）","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"204":{"description":"削除成功"}}}},"/v1/admin/instagram/posts/{id}/slides":{"get":{"tags":["admin","instagram"],"summary":"スライド一覧","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IgSlide"}}}}}}},"post":{"tags":["admin","instagram"],"summary":"スライド追加","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"template_id":{"type":"string"},"slide_index":{"type":"integer","minimum":0},"content":{"type":"string","default":"{}"}},"required":["template_id","slide_index"]}}}},"responses":{"200":{"description":"作成済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IgSlide"}}}}}}},"/v1/admin/instagram/posts/{id}/slides/reorder":{"patch":{"tags":["admin","instagram"],"summary":"スライド並び替え","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"slide_index":{"type":"integer"}},"required":["id","slide_index"]}}},"required":["items"]}}}},"responses":{"204":{"description":"更新成功"}}}},"/v1/admin/instagram/slides/{id}":{"patch":{"tags":["admin","instagram"],"summary":"スライド内容更新","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"content":{"type":"string"},"html_override":{"type":"string","nullable":true},"png_r2_key":{"type":"string","nullable":true},"png_url":{"type":"string","nullable":true},"revision_notes":{"type":"string","nullable":true}}}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IgSlide"}}}}}},"delete":{"tags":["admin","instagram"],"summary":"スライド削除","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"204":{"description":"削除成功"}}}},"/v1/admin/instagram/slides/{id}/duplicate":{"post":{"tags":["admin","instagram"],"summary":"スライドを複製（直後に挿入）","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"複製後の新スライド","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IgSlide"}}}}}}},"/v1/admin/instagram/slides/{id}/upload-png":{"post":{"tags":["admin","instagram"],"summary":"スライド PNG を R2 にアップロード（multipart/form-data）","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"nullable":true}}}}}},"responses":{"200":{"description":"アップロード完了","content":{"application/json":{"schema":{"type":"object","properties":{"r2_key":{"type":"string"},"public_url":{"type":"string"}},"required":["r2_key","public_url"]}}}}}}},"/v1/admin/instagram/upload-image":{"post":{"tags":["admin","instagram"],"summary":"コンテンツ画像を R2 にアップロード（multipart/form-data）","requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"nullable":true}}}}}},"responses":{"200":{"description":"アップロード完了","content":{"application/json":{"schema":{"type":"object","properties":{"r2_key":{"type":"string"},"public_url":{"type":"string"}},"required":["r2_key","public_url"]}}}}}}},"/v1/admin/instagram/slides/{id}/confirm-png":{"patch":{"tags":["admin","instagram"],"summary":"PNG アップロード完了を記録","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"r2_key":{"type":"string"},"public_url":{"type":"string"}},"required":["r2_key","public_url"]}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IgSlide"}}}}}}},"/v1/admin/instagram/slides/{id}/generate-content":{"post":{"tags":["admin","instagram"],"summary":"LLM がスライドの slot_schema に沿って content を自動生成","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"source_material":{"type":"string"},"persist_source":{"type":"boolean"},"hint":{"type":"string"},"target_keys":{"type":"array","items":{"type":"string"}},"provider_id":{"type":"string"},"model":{"type":"string"}}}}}},"responses":{"200":{"description":"生成された content（対象キーのみ。既存値は保持してマージ）","content":{"application/json":{"schema":{"type":"object","properties":{"content":{"type":"object","additionalProperties":{"type":"string"}}},"required":["content"]}}}}}}},"/v1/admin/instagram/posts/{id}/generate-all":{"post":{"tags":["admin","instagram"],"summary":"テンプレ一式から投稿全体を AI が組み立てる","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"post_template_id":{"type":"string"},"template_ids":{"type":"array","items":{"type":"string"}},"spot_count":{"type":"integer","minimum":0,"maximum":10},"hint":{"type":"string"},"provider_id":{"type":"string"},"model":{"type":"string"}}}}}},"responses":{"200":{"description":"作成完了","content":{"application/json":{"schema":{"type":"object","properties":{"created_slides":{"type":"number"}},"required":["created_slides"]}}}}}}},"/v1/admin/instagram/posts/{id}/generate-from-parking-lots":{"post":{"tags":["admin","instagram"],"summary":"選択された駐車場から投稿を一括生成（決定論的マッピング）","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"parking_lot_ids":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1,"maxItems":10},"post_template_id":{"type":"string"},"cover_title":{"type":"string"},"cover_area":{"type":"string"},"hint":{"type":"string"},"provider_id":{"type":"string"},"model":{"type":"string"}},"required":["parking_lot_ids"]}}}},"responses":{"200":{"description":"作成完了","content":{"application/json":{"schema":{"type":"object","properties":{"created_slides":{"type":"number"},"slide_ids":{"type":"array","items":{"type":"string"}}},"required":["created_slides","slide_ids"]}}}}}}},"/v1/admin/instagram/slides/{id}/revise":{"post":{"tags":["admin","instagram"],"summary":"LLM によるスライド HTML 修正","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"instructions":{"type":"string","minLength":1},"provider_id":{"type":"string"},"model":{"type":"string"}},"required":["instructions"]}}}},"responses":{"200":{"description":"修正済みHTML","content":{"application/json":{"schema":{"type":"object","properties":{"html":{"type":"string"},"usage":{"type":"object","properties":{"input_tokens":{"type":"number"},"output_tokens":{"type":"number"}},"required":["input_tokens","output_tokens"]}},"required":["html","usage"]}}}}}}},"/v1/admin/instagram/templates/{id}/revise":{"post":{"tags":["admin","instagram"],"summary":"LLM によるテンプレート HTML 修正案（保存せずプレビュー返却）","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"instructions":{"type":"string","minLength":1},"target":{"type":"string","enum":["template","sample"],"default":"template"},"current_html":{"type":"string"},"provider_id":{"type":"string"},"model":{"type":"string"}},"required":["instructions"]}}}},"responses":{"200":{"description":"修正案 HTML","content":{"application/json":{"schema":{"type":"object","properties":{"html":{"type":"string"},"usage":{"type":"object","properties":{"input_tokens":{"type":"number"},"output_tokens":{"type":"number"}},"required":["input_tokens","output_tokens"]}},"required":["html","usage"]}}}}}}},"/v1/admin/instagram/posts/{id}/generate-caption":{"post":{"tags":["admin","instagram"],"summary":"LLM によるキャプション生成","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"hint":{"type":"string"},"provider_id":{"type":"string"},"model":{"type":"string"}}}}}},"responses":{"200":{"description":"生成されたキャプション","content":{"application/json":{"schema":{"type":"object","properties":{"caption":{"type":"string"},"hashtags":{"type":"array","items":{"type":"string"}}},"required":["caption","hashtags"]}}}}}}},"/v1/admin/instagram/posts/{id}/generate-ideas":{"post":{"tags":["admin","instagram"],"summary":"競合分析とコンテンツアイデア生成","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"notes":{"type":"string","minLength":1},"area":{"type":"string"},"source_url":{"type":"string"},"account_handle":{"type":"string"},"provider_id":{"type":"string"},"model":{"type":"string"}},"required":["notes"]}}}},"responses":{"200":{"description":"生成されたアイデア一覧","content":{"application/json":{"schema":{"type":"object","properties":{"ideas":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"concept":{"type":"string"},"hook":{"type":"string"}},"required":["title","concept","hook"]}}},"required":["ideas"]}}}}}}},"/v1/admin/instagram/posts/{id}/caption":{"patch":{"tags":["admin","instagram"],"summary":"キャプション手動更新","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string"},"hashtags":{"type":"string"}}}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IgCaption"}}}}}}},"/v1/admin/instagram/images/detect-sensitive":{"post":{"tags":["admin","instagram"],"summary":"画像から顔/ナンバープレート候補領域を検出","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"image_url":{"type":"string","format":"uri"},"image_width":{"type":"integer","minimum":0,"exclusiveMinimum":true},"image_height":{"type":"integer","minimum":0,"exclusiveMinimum":true},"min_score":{"type":"number","minimum":0,"maximum":1}},"required":["image_url"]}}}},"responses":{"200":{"description":"検出された候補領域（相対座標 0-1）","content":{"application/json":{"schema":{"type":"object","properties":{"boxes":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string","enum":["face","plate"]},"x":{"type":"number"},"y":{"type":"number"},"width":{"type":"number"},"height":{"type":"number"},"score":{"type":"number"},"source":{"type":"string"}},"required":["label","x","y","width","height","score","source"]}}},"required":["boxes"]}}}}}}},"/v1/admin/instagram/posts/{id}/snapshots":{"get":{"tags":["admin","instagram"],"summary":"競合分析スナップショット一覧","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IgCompetitorSnapshot"}}}}}}}},"/v1/admin/assets":{"get":{"tags":["admin","assets"],"summary":"アセット一覧（カテゴリフィルタ + ページング）","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"category","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AdminAsset"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}},"post":{"tags":["admin","assets"],"summary":"アセットを作成（メタデータのみ。ファイル本体は別途 R2 に上げる）","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"category":{"type":"string"},"s3_key":{"type":"string"},"file_name":{"type":"string"},"mime_type":{"type":"string"},"file_size":{"type":"integer"},"width":{"type":"integer"},"height":{"type":"integer"}},"required":["category","s3_key","file_name","mime_type","file_size"]}}}},"responses":{"200":{"description":"作成済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminAsset"}}}}}}},"/v1/admin/assets/{id}":{"get":{"tags":["admin","assets"],"summary":"アセット詳細","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"詳細","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminAsset"}}}}}},"patch":{"tags":["admin","assets"],"summary":"アセットを更新","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminAsset"}}}}}},"delete":{"tags":["admin","assets"],"summary":"アセットを削除","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"204":{"description":"成功"}}}},"/v1/admin/user-vehicles":{"get":{"tags":["admin","user-vehicles"],"summary":"全ユーザーの車両一覧（user / asset を LEFT JOIN）","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"q","in":"query"},{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":false,"name":"user_id","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AdminUserVehicle"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}},"post":{"tags":["admin","user-vehicles"],"summary":"車両を新規登録（管理者代理）","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"user_id":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"nickname":{"type":"string","nullable":true},"vehicle_type_code":{"type":"string","nullable":true},"maker_code":{"type":"string","nullable":true},"size_code":{"type":"string","nullable":true},"color_code":{"type":"string","nullable":true},"model_name":{"type":"string","nullable":true},"year":{"type":"integer","nullable":true},"asset_id":{"type":"string","nullable":true,"format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"is_primary":{"type":"boolean"},"notes":{"type":"string","nullable":true}},"required":["user_id"]}}}},"responses":{"200":{"description":"作成済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminUserVehicle"}}}}}}},"/v1/admin/user-vehicles/{id}":{"get":{"tags":["admin","user-vehicles"],"summary":"車両 1 件（user / asset join 付き）","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"1 件","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminUserVehicle"}}}}}},"patch":{"tags":["admin","user-vehicles"],"summary":"車両を部分更新（is_primary トグル時は他を解除）","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminUserVehicle"}}}}}},"delete":{"tags":["admin","user-vehicles"],"summary":"車両をソフトデリート（deleted_at=NOW()）","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"204":{"description":"成功"}}}},"/v1/admin/user-search-presets":{"get":{"tags":["admin","user-search-presets"],"summary":"ユーザーの検索プリセット一覧（user_id 必須時に閲覧ログ記録）","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":false,"name":"user_id","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AdminUserSearchPreset"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}}},"/v1/owner/parking-lots/mine":{"get":{"tags":["owner","parking-lots"],"summary":"自分がオーナー権限を持つ駐車場一覧","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","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}},"required":["items","page","limit","total"]}}}}}},"post":{"tags":["owner","parking-lots"],"summary":"駐車場を新規登録（status='pending' で admin 審査待ち）","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1},"address":{"type":"string","nullable":true}},"required":["name"]}}}},"responses":{"200":{"description":"作成済み","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"nullable":true}}}}}}}},"/v1/owner/parking-lots/mine/{id}":{"get":{"tags":["owner","parking-lots"],"summary":"自分の駐車場の詳細","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"詳細","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"nullable":true}}}}}}},"patch":{"tags":["owner","parking-lots"],"summary":"自分の駐車場を編集","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"nullable":true}}}}}}}},"/v1/owner/parking-lots/search":{"get":{"tags":["owner","parking-lots"],"summary":"全駐車場検索（オーナー申請の対象探し用、公開情報のみ）","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","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}},"required":["items","page","limit","total"]}}}}}}},"/v1/owner/applications/mine":{"get":{"tags":["owner","applications"],"summary":"自分が出したオーナー申請の一覧","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","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}},"required":["items","page","limit","total"]}}}}}}},"/v1/owner/applications":{"post":{"tags":["owner","applications"],"summary":"オーナー申請を作成（proof_asset_id 必須）","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"parking_lot_id":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"proof_asset_id":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"owner_name":{"type":"string","minLength":1},"owner_email":{"type":"string","format":"email"},"company_name":{"type":"string","nullable":true},"additional_notes":{"type":"string","nullable":true}},"required":["parking_lot_id","proof_asset_id","owner_name","owner_email"]}}}},"responses":{"200":{"description":"作成済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OwnerApplication"}}}}}}},"/v1/owner/reviews/mine":{"get":{"tags":["owner","reviews"],"summary":"自分の駐車場のレビュー一覧","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","format":"uuid","example":"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":["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}},"required":["items","page","limit","total"]}}}}}}},"/v1/owner/reviews/{reviewId}/reply":{"post":{"tags":["owner","reviews"],"summary":"レビューに返信（上書き / null で削除）","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"reviewId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"owner_reply":{"type":"string","nullable":true}},"required":["owner_reply"]}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OwnerReview"}}}}}}},"/v1/owner/boosts":{"get":{"tags":["owner","boosts"],"summary":"自分のブースト一覧","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":false,"name":"parking_lot_id","in":"query"},{"schema":{"type":"string"},"required":false,"name":"status","in":"query"}],"responses":{"200":{"description":"一覧","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/OwnerBoost"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"total":{"type":"integer","minimum":0}},"required":["items","page","limit","total"]}}}}}},"post":{"tags":["owner","boosts"],"summary":"ブーストを作成","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"parking_lot_id":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"name":{"type":"string","minLength":1}},"required":["parking_lot_id","name"]}}}},"responses":{"200":{"description":"作成済み","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OwnerBoost"}}}}}}},"/v1/owner/boosts/{id}":{"patch":{"tags":["owner","boosts"],"summary":"ブーストを更新","parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000000"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OwnerBoost"}}}}}}},"/v1/owner/boosts/{id}/stats":{"get":{"tags":["owner","boosts"],"summary":"ブーストの統計（インプレッション・クリック・セッション）","parameters":[{"schema":{"type":"string","format":"uuid","example":"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"]}}}}}}},"/v1/owner/credits/balance":{"get":{"tags":["owner","credits"],"summary":"クレジット残高","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"]}}}}}}},"/v1/owner/credits/transactions":{"get":{"tags":["owner","credits"],"summary":"クレジット取引履歴","parameters":[{"schema":{"type":"string","pattern":"^\\d+$","description":"1 はじまりのページ番号","example":"1"},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"1 ページあたりの件数（最大 2000）","example":"20"},"required":false,"name":"limit","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}},"required":["items","page","limit","total"]}}}}}}},"/v1/owner/credits/checkout-session":{"post":{"tags":["owner","credits"],"summary":"クレジット購入用 Stripe Checkout セッション URL（Phase 2 で実装、現状はスタブ）","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"credits":{"type":"integer","minimum":0,"exclusiveMinimum":true}},"required":["credits"]}}}},"responses":{"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"]}}}}}}},"/v1/owner/invitations/accept":{"post":{"tags":["owner","invitations"],"summary":"招待メールから初回パスワードを設定し、オーナーを active 化する","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"password":{"type":"string","minLength":8,"maxLength":128}},"required":["password"]}}}},"responses":{"200":{"description":"セットアップ完了","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"owner_id":{"type":"string","format":"uuid"}},"required":["ok","owner_id"]}}}}}}}}}