{"openapi":"3.1.0","info":{"title":"GetPlace Insights API","description":"API for managing review insights and synchronization","version":"1.0.0"},"paths":{"/health":{"get":{"tags":["Health"],"summary":"Health Check","description":"Check API and database health.","operationId":"health_check_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/auth/check":{"get":{"tags":["Health"],"summary":"Auth Check","description":"Check if admin credentials are valid (legacy Basic Auth).","operationId":"auth_check_auth_check_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBasic":[]}]}},"/auth/check-public":{"get":{"tags":["Health"],"summary":"Auth Check Public","description":"Check if user is authenticated (JWT or anonymous access allowed).","operationId":"auth_check_public_auth_check_public_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/countries":{"get":{"tags":["Countries"],"summary":"List Countries","description":"List all countries with optional filters. Uses cached reviews_count for speed.\n\nClient users only see countries they have access to (based on menu_access_items).\nAdmin users see all countries.","operationId":"list_countries_api_countries_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"is_active","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Active"}},{"name":"has_reviews","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Has Reviews"}},{"name":"has_menu","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Has Menu"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CountryResponse"},"title":"Response List Countries Api Countries Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/countries/{country_id}":{"get":{"tags":["Countries"],"summary":"Get Country","description":"Get a country by ID. Client users can only access their allowed country.","operationId":"get_country_api_countries__country_id__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"country_id","in":"path","required":true,"schema":{"type":"integer","title":"Country Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CountryResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/countries/platform-currencies":{"get":{"tags":["Countries"],"summary":"List Platform Currencies","description":"List platform currency overrides. Defaults to EUR when no override exists.","operationId":"list_platform_currencies_api_countries_platform_currencies_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"country_code","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country Code"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PlatformCurrencyResponse"},"title":"Response List Platform Currencies Api Countries Platform Currencies Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/countries/{country_id}/chain-matching":{"patch":{"tags":["Countries"],"summary":"Toggle Chain Matching","description":"Toggle chain_matching_enabled for a country (admin only).","operationId":"toggle_chain_matching_api_countries__country_id__chain_matching_patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"country_id","in":"path","required":true,"schema":{"type":"integer","title":"Country Id"}},{"name":"enabled","in":"query","required":true,"schema":{"type":"boolean","title":"Enabled"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/countries/{country_id}/sync-enabled":{"patch":{"tags":["Countries"],"summary":"Toggle Sync Enabled","description":"Toggle sync_enabled for a country (admin only). Also sets last_sync to 2025-01-01 when enabling.","operationId":"toggle_sync_enabled_api_countries__country_id__sync_enabled_patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"country_id","in":"path","required":true,"schema":{"type":"integer","title":"Country Id"}},{"name":"enabled","in":"query","required":true,"schema":{"type":"boolean","title":"Enabled"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/cities/{city_id}":{"patch":{"tags":["Cities"],"summary":"Update City","description":"Update city settings.","operationId":"update_city_api_cities__city_id__patch","parameters":[{"name":"city_id","in":"path","required":true,"schema":{"type":"integer","title":"City Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CityUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CityResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/cities/{city_id}/enable":{"post":{"tags":["Cities"],"summary":"Enable Sync","description":"Enable synchronization for a city.","operationId":"enable_sync_api_cities__city_id__enable_post","parameters":[{"name":"city_id","in":"path","required":true,"schema":{"type":"integer","title":"City Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/cities/{city_id}/disable":{"post":{"tags":["Cities"],"summary":"Disable Sync","description":"Disable synchronization for a city.","operationId":"disable_sync_api_cities__city_id__disable_post","parameters":[{"name":"city_id","in":"path","required":true,"schema":{"type":"integer","title":"City Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/cities/enable-country/{country_code}":{"post":{"tags":["Cities"],"summary":"Enable Country Cities","description":"Enable synchronization for all cities in a country that have geo_json.","operationId":"enable_country_cities_api_cities_enable_country__country_code__post","parameters":[{"name":"country_code","in":"path","required":true,"schema":{"type":"string","title":"Country Code"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/chains":{"get":{"tags":["Chains"],"summary":"List Chains","description":"List chains from pois_chain table with optional country and search filters.\n\nReturns top chains by POI count (max 100). Use search parameter to find specific chains.\nIf user has chain_ids restrictions, only returns those chains.","operationId":"list_chains_api_chains_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"country_code","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country Code"}},{"name":"has_menu","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Has Menu"}},{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Search"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ChainResponse"},"title":"Response List Chains Api Chains Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/chains/pois":{"get":{"tags":["Chains"],"summary":"List Pois By Chains","description":"List POIs (outlets) for specified chain IDs from all POI tables.\n\nReturns POIs from: pois_deliveroo, pois_google, pois_talabat, pois_trendiol, pois_yemeksepeti\nOptionally filtered by country_code (via pois_chain.country) or city_id (via city polygon).","operationId":"list_pois_by_chains_api_chains_pois_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"chain_ids","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"integer"}},{"type":"null"}],"title":"Chain Ids"}},{"name":"source","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source"}},{"name":"country_code","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country Code"}},{"name":"city_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"City Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/POIResponse"},"title":"Response List Pois By Chains Api Chains Pois Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/chains/{chain_id}":{"get":{"tags":["Chains"],"summary":"Get Chain By Id","description":"Get a chain by its ID.","operationId":"get_chain_by_id_api_chains__chain_id__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"chain_id","in":"path","required":true,"schema":{"type":"integer","title":"Chain Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ChainResponse"},{"type":"null"}],"title":"Response Get Chain By Id Api Chains  Chain Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/chains/poi/{poi_id}":{"get":{"tags":["Chains"],"summary":"Get Poi By Id","description":"Get a POI by its ID.","operationId":"get_poi_by_id_api_chains_poi__poi_id__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"poi_id","in":"path","required":true,"schema":{"type":"string","title":"Poi Id"}},{"name":"poi_name","in":"query","required":false,"schema":{"type":"string","default":"","title":"Poi Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/POIResponse"},{"type":"null"}],"title":"Response Get Poi By Id Api Chains Poi  Poi Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/chains/match/{country_code}":{"post":{"tags":["Chains"],"summary":"Match Google Chains","description":"Trigger chain matching for Google POIs in a country.\n\nMatches unprocessed POIs (chain_id=0) to chains using RAG + Fuzzy + Gemini,\nthen writes results to GetPlace2 pois_google table.","operationId":"match_google_chains_api_chains_match__country_code__post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"country_code","in":"path","required":true,"schema":{"type":"string","title":"Country Code"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/reviews/chains":{"get":{"tags":["Reviews"],"summary":"List Chains","description":"List unique chains.","operationId":"list_chains_api_reviews_chains_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"city_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"City Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/reviews/platforms":{"get":{"tags":["Reviews"],"summary":"List Platforms","description":"List unique platforms filtered by city, country, and/or chain.","operationId":"list_platforms_api_reviews_platforms_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"city_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"City Id"}},{"name":"country_code","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country Code"}},{"name":"chain_ids","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"integer"}},{"type":"null"}],"title":"Chain Ids"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/insights":{"get":{"tags":["Insights"],"summary":"List Insights","description":"List generated insights. Requires authentication.","operationId":"list_insights_api_insights_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"city_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"City Id"}},{"name":"chain_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Chain Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"default":20,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/InsightResponse"},"title":"Response List Insights Api Insights Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/insights/{insight_id}":{"get":{"tags":["Insights"],"summary":"Get Insight","description":"Get a specific insight by ID. Requires authentication.","operationId":"get_insight_api_insights__insight_id__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"insight_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Insight Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/sync/tasks":{"get":{"tags":["Sync"],"summary":"List Sync Tasks","description":"List sync tasks with filters.","operationId":"list_sync_tasks_api_sync_tasks_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"city_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"City Id"}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"}},{"name":"task_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Task Type"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SyncTaskResponse"},"title":"Response List Sync Tasks Api Sync Tasks Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/sync/tasks/{task_id}":{"get":{"tags":["Sync"],"summary":"Get Sync Task","description":"Get a specific sync task.","operationId":"get_sync_task_api_sync_tasks__task_id__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyncTaskResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/sync/menu":{"post":{"tags":["Sync"],"summary":"Sync Menu","description":"Menu sync moved to Go worker (insights-sync service).","operationId":"sync_menu_api_sync_menu_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","default":7,"title":"Days"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/analyze":{"post":{"tags":["Analyze"],"summary":"Analyze Endpoint","description":"Analyze review data and answer questions using AI. Requires admin.\n\n- **question**: The question to answer about the data\n- **city_id**: City to analyze\n- **chain_id**: Optional chain filter (by ID)\n- **days**: Number of days to analyze (default 30)\n- **async_mode**: If true, returns task_id and runs in background","operationId":"analyze_endpoint_api_analyze_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"async_mode","in":"query","required":false,"schema":{"type":"boolean","description":"Run asynchronously via Celery","default":false,"title":"Async Mode"},"description":"Run asynchronously via Celery"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyzeRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyzeResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/analyze/quick":{"get":{"tags":["Analyze"],"summary":"Quick Analyze","description":"Quick synchronous analysis endpoint. Requires admin.\n\nUse for simple questions that need immediate response.","operationId":"quick_analyze_api_analyze_quick_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"city_id","in":"query","required":true,"schema":{"type":"integer","title":"City Id"}},{"name":"question","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":500,"title":"Question"}},{"name":"chain_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Chain Id"}},{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":365,"minimum":1,"default":30,"title":"Days"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/categories":{"get":{"tags":["Categories"],"summary":"List Categories","description":"List all master categories.","operationId":"list_categories_api_categories_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/CategoryResponse"},"type":"array","title":"Response List Categories Api Categories Get"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/categories/stats":{"get":{"tags":["Categories"],"summary":"Get Category Stats","description":"Get categories with POI counts (from mappings).","operationId":"get_category_stats_api_categories_stats_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"platform","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Platform"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CategoryWithStatsResponse"},"title":"Response Get Category Stats Api Categories Stats Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/categories/platforms":{"get":{"tags":["Categories"],"summary":"Get Platform Stats","description":"Get mapping statistics per platform.","operationId":"get_platform_stats_api_categories_platforms_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/PlatformStatsResponse"},"type":"array","title":"Response Get Platform Stats Api Categories Platforms Get"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/categories/mappings":{"get":{"tags":["Categories"],"summary":"List Mappings","description":"List category mappings with optional filters.","operationId":"list_mappings_api_categories_mappings_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"platform","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Platform"}},{"name":"target_slug","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target Slug"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CategoryMappingResponse"},"title":"Response List Mappings Api Categories Mappings Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/categories/{slug}":{"get":{"tags":["Categories"],"summary":"Get Category","description":"Get a specific category by slug.","operationId":"get_category_api_categories__slug__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoryResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/categories/unmapped/{platform}":{"get":{"tags":["Categories"],"summary":"List Unmapped","description":"List unmapped categories for a platform.","operationId":"list_unmapped_api_categories_unmapped__platform__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"platform","in":"path","required":true,"schema":{"type":"string","title":"Platform"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/prompts":{"get":{"tags":["Prompts"],"summary":"List Prompts","description":"List all prompts with summary info.","operationId":"list_prompts_api_admin_prompts_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/PromptListResponse"},"type":"array","title":"Response List Prompts Api Admin Prompts Get"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/admin/prompts/{prompt_id}":{"get":{"tags":["Prompts"],"summary":"Get Prompt","description":"Get a prompt with all its versions.","operationId":"get_prompt_api_admin_prompts__prompt_id__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"prompt_id","in":"path","required":true,"schema":{"type":"integer","title":"Prompt Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromptResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/prompts/{prompt_id}/versions":{"post":{"tags":["Prompts"],"summary":"Create Version","description":"Create a new version of a prompt.","operationId":"create_version_api_admin_prompts__prompt_id__versions_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"prompt_id","in":"path","required":true,"schema":{"type":"integer","title":"Prompt Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateVersionRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromptVersionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/prompts/{prompt_id}/versions/{version_id}":{"put":{"tags":["Prompts"],"summary":"Update Version","description":"Update an existing version.","operationId":"update_version_api_admin_prompts__prompt_id__versions__version_id__put","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"prompt_id","in":"path","required":true,"schema":{"type":"integer","title":"Prompt Id"}},{"name":"version_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Version Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateVersionRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromptVersionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/prompts/{prompt_id}/versions/{version_id}/activate":{"put":{"tags":["Prompts"],"summary":"Activate Version","description":"Set a version as the current active version.","operationId":"activate_version_api_admin_prompts__prompt_id__versions__version_id__activate_put","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"prompt_id","in":"path","required":true,"schema":{"type":"integer","title":"Prompt Id"}},{"name":"version_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Version Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/prompts/{prompt_id}/test":{"post":{"tags":["Prompts"],"summary":"Test Prompt","description":"Test a prompt with sample input.","operationId":"test_prompt_api_admin_prompts__prompt_id__test_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"prompt_id","in":"path","required":true,"schema":{"type":"integer","title":"Prompt Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestPromptRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestPromptResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/auth/login":{"post":{"tags":["Auth"],"summary":"Login","description":"Authenticate and get JWT token (tries GetPlace2 first, then local).","operationId":"login_api_auth_login_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/auth/login/form":{"post":{"tags":["Auth"],"summary":"Login Form","description":"OAuth2 compatible login endpoint (for Swagger UI).","operationId":"login_form_api_auth_login_form_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_login_form_api_auth_login_form_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/auth/me":{"get":{"tags":["Auth"],"summary":"Get Me","description":"Get current authenticated user info.","operationId":"get_me_api_auth_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__api__auth_api__UserResponse"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/auth/logout":{"post":{"tags":["Auth"],"summary":"Logout","description":"Logout current user (client should discard token).","operationId":"logout_api_auth_logout_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/auth/token-login":{"post":{"tags":["Auth"],"summary":"Token Login","description":"Authenticate using a GetPlace2 JWT token.\nDecodes the token, fetches user from GetPlace2 remote DB,\nchecks allow_reviews_access, and returns a new JWT token.","operationId":"token_login_api_auth_token_login_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenLoginRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/auth/check":{"get":{"tags":["Auth"],"summary":"Auth Check Legacy","description":"Legacy: Check if admin credentials are valid (Basic Auth).","operationId":"auth_check_legacy_api_auth_check_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/users":{"get":{"tags":["Users"],"summary":"List Users","description":"List all users (admin only).","operationId":"list_users_api_users_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"skip","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Skip"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":100,"title":"Limit"}},{"name":"role","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Role"}},{"name":"is_active","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Active"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsersListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Users"],"summary":"Create User","description":"Create a new user (admin only).","operationId":"create_user_api_users_post","security":[{"OAuth2PasswordBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__api__users__UserResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/users/{user_id}":{"get":{"tags":["Users"],"summary":"Get User","description":"Get a specific user (admin only).","operationId":"get_user_api_users__user_id__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","title":"User Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__api__users__UserResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["Users"],"summary":"Update User","description":"Update a user (admin only).","operationId":"update_user_api_users__user_id__put","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","title":"User Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__api__users__UserResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Users"],"summary":"Delete User","description":"Delete a user (admin only).","operationId":"delete_user_api_users__user_id__delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","title":"User Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/comparisons":{"get":{"tags":["Comparisons"],"summary":"List Comparisons","description":"List all chains in user's comparison list.","operationId":"list_comparisons_api_comparisons_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"entity_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Entity Type"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ComparisonResponse"},"title":"Response List Comparisons Api Comparisons Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Comparisons"],"summary":"Add Comparison","description":"Add a chain to comparison list.","operationId":"add_comparison_api_comparisons_post","security":[{"OAuth2PasswordBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ComparisonCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ComparisonResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Comparisons"],"summary":"Clear Comparisons","description":"Clear all comparisons for user.","operationId":"clear_comparisons_api_comparisons_delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"entity_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Entity Type"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/comparisons/outlet-cities":{"get":{"tags":["Comparisons"],"summary":"Get Outlet Cities","description":"Resolve city names (and optionally store_ids) for a list of outlet poi_ids.\n\nResponse shape:\n  - ``include_store_id=false`` (default): ``{poi_id: city_name}`` — plain string\n    for backward compatibility and zero JOIN overhead when the caller does not\n    need store_ids.\n  - ``include_store_id=true``: ``{poi_id: {city_name, store_id}}`` — ``store_id``\n    is ``null`` when the outlet has no uploaded mapping.","operationId":"get_outlet_cities_api_comparisons_outlet_cities_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"poi_ids","in":"query","required":true,"schema":{"type":"string","title":"Poi Ids"}},{"name":"country_code","in":"query","required":true,"schema":{"type":"string","title":"Country Code"}},{"name":"include_store_id","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Include Store Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/comparisons/{comparison_id}":{"patch":{"tags":["Comparisons"],"summary":"Update Comparison","description":"Update franchisee scope for a comparison entry.","operationId":"update_comparison_api_comparisons__comparison_id__patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"comparison_id","in":"path","required":true,"schema":{"type":"integer","title":"Comparison Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ComparisonUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ComparisonResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Comparisons"],"summary":"Remove Comparison","description":"Remove a chain from comparison list.","operationId":"remove_comparison_api_comparisons__comparison_id__delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"comparison_id","in":"path","required":true,"schema":{"type":"integer","title":"Comparison Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/price-compare/sets":{"get":{"tags":["Price Compare"],"summary":"List Sets","description":"Every benchmark this user owns, most recently changed first.\n\n`include_deleted` adds the ones deleted recently, each carrying its\n`deleted_at` — that is how a browser still holding a copy learns it is gone\ninstead of pushing it back up. It is opt-in so that anything not expecting\nthe field (an older frontend) can never show a deleted benchmark as live.","operationId":"list_sets_api_price_compare_sets_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"include_deleted","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Include Deleted"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SetResponse"},"title":"Response List Sets Api Price Compare Sets Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/price-compare/sets/{set_id}":{"put":{"tags":["Price Compare"],"summary":"Upsert Set","description":"Create or replace one benchmark.\n\nUpsert rather than POST+PUT because the client already owns the id: it\ngenerates one when the user creates a set, and saves the whole set on every\nedit. Last write wins — two devices editing one benchmark is not something\nthis product needs to merge.","operationId":"upsert_set_api_price_compare_sets__set_id__put","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"set_id","in":"path","required":true,"schema":{"type":"string","title":"Set Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetUpsert"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Price Compare"],"summary":"Delete Set","description":"Mark one benchmark deleted. The row stays so other browsers can see the\ndeletion; deleting something that isn't there is fine — the client may be\nretrying after a dropped connection.","operationId":"delete_set_api_price_compare_sets__set_id__delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"set_id","in":"path","required":true,"schema":{"type":"string","title":"Set Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/price-compare/sets/migrate":{"post":{"tags":["Price Compare"],"summary":"Migrate Sets","description":"One-time lift of whatever is still in the browser.\n\nDeliberately additive and idempotent: it only writes ids this user does not\nhave yet, so a second run (or two tabs racing) cannot overwrite work already\non the server. The client keeps its copy until this returns.","operationId":"migrate_sets_api_price_compare_sets_migrate_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MigrateRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/SetResponse"},"type":"array","title":"Response Migrate Sets Api Price Compare Sets Migrate Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/price-compare/admin/sets":{"get":{"tags":["Price Compare"],"summary":"Admin List Sets","description":"Every benchmark in the database, newest first; the payloads are read but\nnot returned — the summary is computed from them here.\n\n`q` is applied after the owners are resolved so that searching by e-mail\nworks — the owner lives in another database and cannot be joined against.\nThat is also why `limit` caps the RESULT rather than the read: limiting the\nread first would hide a client's older benchmarks from their own e-mail\nsearch and answer \"none found\", which is the one answer this endpoint must\nnever give wrongly. `MAX_ADMIN_SCAN` bounds the read instead.","operationId":"admin_list_sets_api_price_compare_admin_sets_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Match the benchmark name or the owner's e-mail","title":"Q"},"description":"Match the benchmark name or the owner's e-mail"},{"name":"include_deleted","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Include Deleted"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":2000,"minimum":1,"default":500,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AdminSetRow"},"title":"Response Admin List Sets Api Price Compare Admin Sets Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/price-compare/admin/sets/{set_id}":{"get":{"tags":["Price Compare"],"summary":"Admin Get Set","description":"One benchmark in full — so what a client is looking at can be read\nwithout logging in as them.","operationId":"admin_get_set_api_price_compare_admin_sets__set_id__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"set_id","in":"path","required":true,"schema":{"type":"string","title":"Set Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminSetDetail"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["Price Compare"],"summary":"Admin Rename Set","description":"Rename one benchmark in any account.\n\nOnly the name: the payload is the client's work, and the place to change\nthat is the benchmark screen, not an operator panel. The name inside the\npayload is kept in step, because setsSync.fromRow prefers the row's name but\nthe editor reads the payload's.","operationId":"admin_rename_set_api_price_compare_admin_sets__set_id__patch","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"set_id","in":"path","required":true,"schema":{"type":"string","title":"Set Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenameRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminSetRow"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Price Compare"],"summary":"Admin Delete Set","description":"Remove one benchmark from whatever account holds it.\n\nSoft, like the owner's own deletion — a hard delete would vanish from the\n`/sets` response, and a browser still holding the set would decide it never\nreached the server and upload it again.","operationId":"admin_delete_set_api_price_compare_admin_sets__set_id__delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"set_id","in":"path","required":true,"schema":{"type":"string","title":"Set Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/price-compare/admin/resolve-user":{"get":{"tags":["Price Compare"],"summary":"Admin Resolve User","description":"Find the account to copy into, by e-mail.\n\nGetPlace2 first, local second — the same order authenticate_user uses, so\nthe account resolved here is the one that e-mail actually logs in as.","operationId":"admin_resolve_user_api_price_compare_admin_resolve_user_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"email","in":"query","required":true,"schema":{"type":"string","minLength":3,"title":"Email"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolvedUser"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/price-compare/admin/sets/{set_id}/copy":{"post":{"tags":["Price Compare"],"summary":"Admin Copy Set","description":"Seed one account's benchmark into another account.\n\nTwo calls by design. The first (`mode=\"ask\"`, the default) writes nothing\nand answers the two questions worth asking before a write: does the target\nalready hold a copy of this benchmark, and will it show any data once it\nlands. The second names what to do about it.\n\nThe copy always gets a fresh server-generated id — `price_compare_sets.id`\nis a global primary key, so reusing the source's would collide with it.","operationId":"admin_copy_set_api_price_compare_admin_sets__set_id__copy_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"set_id","in":"path","required":true,"schema":{"type":"string","title":"Set Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CopyRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CopyResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/price-compare/admin/sets/{set_id}/restore":{"post":{"tags":["Price Compare"],"summary":"Admin Restore Set","description":"Undo a deletion — the operator's own, or the owner's.\n\nThe owner has no undo in the product, so this is the only way back for a\nbenchmark somebody deleted by accident. Clearing both columns puts the row\nback exactly as it was; the client picks it up on its next pull.","operationId":"admin_restore_set_api_price_compare_admin_sets__set_id__restore_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"set_id","in":"path","required":true,"schema":{"type":"string","title":"Set Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminSetRow"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/price-compare/admin/sets/{set_id}/move":{"post":{"tags":["Price Compare"],"summary":"Admin Move Set","description":"Hand a benchmark to a different account.\n\nImplemented as a copy plus a deletion, NOT as an UPDATE of user_id, and the\ndifference matters: changing the owner in place makes the row disappear from\nthe old owner's `/sets`, their browser finds its cached copy among neither\nthe live rows nor the deleted ones, concludes it never reached the server,\nand uploads it again. Leaving a tombstone behind is what tells them it left.","operationId":"admin_move_set_api_price_compare_admin_sets__set_id__move_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"set_id","in":"path","required":true,"schema":{"type":"string","title":"Set Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MoveRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MoveResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/price-compare/admin/sets/bulk":{"post":{"tags":["Price Compare"],"summary":"Admin Bulk","description":"Delete or restore many benchmarks at once.\n\nCopying in bulk is deliberately NOT here: every copy has its own question\nabout an existing copy in the target account, and answering all of them with\none flag is how work gets overwritten. The client loops the single-copy\nendpoint instead, and sees each answer.","operationId":"admin_bulk_api_price_compare_admin_sets_bulk_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/price-compare/admin/sets/preview":{"post":{"tags":["Price Compare"],"summary":"Admin Preview Transfer","description":"What copying these benchmarks into that account would do. Writes nothing.\n\nOne endpoint for many sets rather than one call each, because the expensive\npart is resolving the target: every single-set dry run opened its own\nconnection to the GetPlace2 production database and looked up the SAME\naccount again. Selecting fifty rows meant fifty connections to somebody\nelse's production. Here the account is resolved once and the answer is\ncomputed per set — the access report genuinely differs, because the brands\ndiffer, but the account does not.","operationId":"admin_preview_transfer_api_price_compare_admin_sets_preview_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/price-compare/admin/search-accounts":{"get":{"tags":["Price Compare"],"summary":"Admin Search Accounts","description":"Accounts to copy a benchmark into, matched on e-mail.\n\nThe limit is a guard against a one-letter query, not a feature of ordinary\nuse: 83 accounts can sign in at all, \"dodopizza\" matches 16 and \"pizza\" 21,\nso a page of 50 shows a real search whole. It exists because this reads\nanother company's production users table and a stray keystroke should not\npull all of it — and because eighty rows is a second list, not a picker. Only accounts that can\nactually SIGN IN come back — offering a blocked one would walk the operator\ninto a refusal — and that condition lives in the WHERE clause, not in a pass\nover the results afterwards: filtering after the LIMIT returned the first\ntwenty matches and then threw most of them away, so a search for a company\ndomain showed four of its people and hid the rest.\n\nEach row carries the account's grants, which is the point of the picker\nrather than a decoration: it answers \"will the copy show any data\" while the\noperator is still choosing, instead of after.","operationId":"admin_search_accounts_api_price_compare_admin_search_accounts_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string","minLength":2,"maxLength":255,"title":"Q"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountSearchResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/product-sizes":{"get":{"tags":["Product Sizes"],"summary":"List Sizes","description":"Every stated size, or one chain's.\n\nThe client loads this once and holds it in memory: the badge resolver runs\nsynchronously during render — inside a memo, on every cell of a grid — and\ncannot await anything.\n\n`normalized_name` is re-derived on the way out — see the module docstring.\nThe browser keys its dictionary on whatever this returns and looks it up\nwith normName(), the twin of norm_name(), so the server owning the key is\nwhat keeps a row written under an older rule reachable.","operationId":"list_sizes_api_product_sizes_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"chain_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":2147483647,"exclusiveMinimum":0},{"type":"null"}],"title":"Chain Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SizeEntryResponse"},"title":"Response List Sizes Api Product Sizes Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/product-sizes/{chain_id}":{"put":{"tags":["Product Sizes"],"summary":"Upsert Size","description":"State a product's size, or state that it has none.","operationId":"upsert_size_api_product_sizes__chain_id__put","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"chain_id","in":"path","required":true,"schema":{"type":"integer","maximum":2147483647,"exclusiveMinimum":0,"title":"Chain Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SizeUpsert"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SizeEntryResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Product Sizes"],"summary":"Delete Size","description":"Withdraw a stated size — the badge falls back to the listing name or its\ndescription. Deleting something that is not there is fine; the client may\nbe retrying after a dropped connection.","operationId":"delete_size_api_product_sizes__chain_id__delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"chain_id","in":"path","required":true,"schema":{"type":"integer","maximum":2147483647,"exclusiveMinimum":0,"title":"Chain Id"}},{"name":"name","in":"query","required":true,"schema":{"type":"string","minLength":1,"title":"Name"}},{"name":"platform","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":50},{"type":"null"}],"title":"Platform"}},{"name":"shelf","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Shelf"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/franchisees":{"get":{"tags":["Franchisees"],"summary":"List Franchisees","description":"List franchisees filtered by country code.","operationId":"list_franchisees_api_franchisees_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"country_code","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country Code"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/FranchiseeResponse"},"title":"Response List Franchisees Api Franchisees Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/franchisees/breakdown":{"get":{"tags":["Franchisees"],"summary":"Get Franchisee Breakdown","description":"Return outlet counts grouped by franchisee for each requested chain.\n\nResult shape: { \"chain_id\": [{fr_id, name, count}, ...] }\nAn entry with fr_id=null represents outlets not assigned to any franchisee.","operationId":"get_franchisee_breakdown_api_franchisees_breakdown_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"chain_ids","in":"query","required":true,"schema":{"type":"array","items":{"type":"integer"},"title":"Chain Ids"}},{"name":"country_code","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country Code"}},{"name":"date_from","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Date From"}},{"name":"date_to","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Date To"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/FranchiseeBreakdownItem"}},"title":"Response Get Franchisee Breakdown Api Franchisees Breakdown Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/menu/sync":{"post":{"tags":["Menu","menu"],"summary":"Trigger Menu Sync","description":"Menu sync moved to Go worker (insights-sync service).","operationId":"trigger_menu_sync_api_menu_sync_post","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":30,"minimum":1,"default":7,"title":"Days"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"type":"array","items":{"type":"integer"}},{"type":"null"}],"title":"Chain Ids"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/exports":{"get":{"tags":["Exports"],"summary":"List Exports","description":"List all exports, newest first. Admin only.","operationId":"list_exports_api_exports_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/ExportResponse"},"type":"array","title":"Response List Exports Api Exports Get"}}}}},"security":[{"OAuth2PasswordBearer":[]}]},"post":{"tags":["Exports"],"summary":"Create Export","description":"Create a new CSV export task. Admin only.","operationId":"create_export_api_exports_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateExportRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExportResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/exports/{export_id}/download":{"get":{"tags":["Exports"],"summary":"Download Export","description":"Download a completed export CSV. Admin only.","operationId":"download_export_api_exports__export_id__download_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"export_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Export Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/exports/{export_id}":{"delete":{"tags":["Exports"],"summary":"Delete Export","description":"Delete an export and its file. Admin only.","operationId":"delete_export_api_exports__export_id__delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"export_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Export Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/menu-compare/runs":{"get":{"tags":["Menu Compare"],"summary":"List Runs","description":"List comparison runs, optionally filtered by city.","operationId":"list_runs_api_admin_menu_compare_runs_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"city_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"City Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/menu-compare/cities":{"get":{"tags":["Menu Compare"],"summary":"List Cities With Runs","description":"Cities that have at least one comparison run.","operationId":"list_cities_with_runs_api_admin_menu_compare_cities_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/admin/menu-compare/runs/{run_id}/stats":{"get":{"tags":["Menu Compare"],"summary":"Run Stats","description":"Aggregate stats for a run.","operationId":"run_stats_api_admin_menu_compare_runs__run_id__stats_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Run Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/menu-compare/runs/{run_id}/pois":{"get":{"tags":["Menu Compare"],"summary":"List Poi Matches","description":"List POI matches with category/product counts.","operationId":"list_poi_matches_api_admin_menu_compare_runs__run_id__pois_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Run Id"}},{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Search"}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Page Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/menu-compare/runs/{run_id}/pois/{wolt_bid}":{"get":{"tags":["Menu Compare"],"summary":"Poi Detail","description":"Full detail: POI info + matched/unmatched categories + products.","operationId":"poi_detail_api_admin_menu_compare_runs__run_id__pois__wolt_bid__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Run Id"}},{"name":"wolt_bid","in":"path","required":true,"schema":{"type":"string","title":"Wolt Bid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/menu-compare/runs/{run_id}/products":{"get":{"tags":["Menu Compare"],"summary":"List Products","description":"Matched products for a specific POI pair, optionally filtered by category.","operationId":"list_products_api_admin_menu_compare_runs__run_id__products_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Run Id"}},{"name":"wolt_bid","in":"query","required":true,"schema":{"type":"string","title":"Wolt Bid"}},{"name":"bolt_bid","in":"query","required":true,"schema":{"type":"string","title":"Bolt Bid"}},{"name":"wolt_cat","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Wolt Cat"}},{"name":"bolt_cat","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bolt Cat"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/menu-compare/runs/{run_id}/unmatched":{"get":{"tags":["Menu Compare"],"summary":"List Unmatched","description":"List unmatched POIs.","operationId":"list_unmatched_api_admin_menu_compare_runs__run_id__unmatched_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Run Id"}},{"name":"platform","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Platform"}},{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Search"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":100,"title":"Page Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/menu-compare/runs/{run_id}/unmatched/{platform}/{bid}":{"get":{"tags":["Menu Compare"],"summary":"Unmatched Poi Detail","description":"Categories and products for an unmatched POI.","operationId":"unmatched_poi_detail_api_admin_menu_compare_runs__run_id__unmatched__platform___bid__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Run Id"}},{"name":"platform","in":"path","required":true,"schema":{"type":"string","title":"Platform"}},{"name":"bid","in":"path","required":true,"schema":{"type":"string","title":"Bid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/menu-compare/runs/{run_id}/unmatched-products/{platform}/{bid}/{category_id}":{"get":{"tags":["Menu Compare"],"summary":"Unmatched Products","description":"Products in a specific category of an unmatched POI.","operationId":"unmatched_products_api_admin_menu_compare_runs__run_id__unmatched_products__platform___bid___category_id__get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Run Id"}},{"name":"platform","in":"path","required":true,"schema":{"type":"string","title":"Platform"}},{"name":"bid","in":"path","required":true,"schema":{"type":"string","title":"Bid"}},{"name":"category_id","in":"path","required":true,"schema":{"type":"string","title":"Category Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/menu-compare/runs/{run_id}/weak-matches":{"get":{"tags":["Menu Compare"],"summary":"List Weak Matches","description":"POI pairs with weak match status.","operationId":"list_weak_matches_api_admin_menu_compare_runs__run_id__weak_matches_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Run Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/menu-compare/runs/{run_id}/export/products":{"get":{"tags":["Menu Compare"],"summary":"Export Products Csv","description":"Export all matched products as CSV.","operationId":"export_products_csv_api_admin_menu_compare_runs__run_id__export_products_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Run Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/menu-compare/runs/{run_id}/export/stores":{"get":{"tags":["Menu Compare"],"summary":"Export Stores Csv","description":"Export store-level matching overview as CSV.","operationId":"export_stores_csv_api_admin_menu_compare_runs__run_id__export_stores_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Run Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/pulse/subscribe":{"post":{"tags":["Pulse"],"summary":"Subscribe","description":"Subscribe an email to the Pulse weekly digest.","operationId":"subscribe_api_pulse_subscribe_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscribeRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/pulse/request-access":{"post":{"tags":["Pulse"],"summary":"Request Access","description":"Record an access request: add to audience, notify team, confirm to requester.","operationId":"request_access_api_pulse_request_access_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestAccessRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/":{"get":{"summary":"Root","operationId":"root__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"AccessReport":{"properties":{"ok":{"type":"boolean","title":"Ok"},"unrestricted":{"type":"boolean","title":"Unrestricted","default":false},"allow_menu_access":{"type":"boolean","title":"Allow Menu Access","default":true},"required":{"$ref":"#/components/schemas/RequiredAccess"},"missing_chain_ids":{"items":{"type":"integer"},"type":"array","title":"Missing Chain Ids"},"city_blocked":{"type":"boolean","title":"City Blocked","default":false},"note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Note"}},"type":"object","required":["ok","required"],"title":"AccessReport","description":"Whether an account would actually see data in a benchmark.\n\nCopying a set is not enough on its own: the Go API filters menu data by the\naccount's grants, so a benchmark whose brands are not granted opens empty —\nwhich reads as a broken screen rather than as missing permissions. This\nreport is what turns that into a sentence before anything is written."},"AccountOption":{"properties":{"user_id":{"type":"string","title":"User Id"},"email":{"type":"string","title":"Email"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"source":{"type":"string","enum":["local","getplace"],"title":"Source"},"allow_menu_access":{"type":"boolean","title":"Allow Menu Access","default":false},"grants":{"items":{"$ref":"#/components/schemas/GrantSummary"},"type":"array","title":"Grants"},"set_count":{"type":"integer","title":"Set Count","default":0}},"type":"object","required":["user_id","email","source"],"title":"AccountOption","description":"One candidate in the admin's \"copy to…\" picker."},"AccountSearchResponse":{"properties":{"items":{"items":{"$ref":"#/components/schemas/AccountOption"},"type":"array","title":"Items"},"total":{"type":"integer","title":"Total","default":0}},"type":"object","title":"AccountSearchResponse"},"AdminSetDetail":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"user_id":{"type":"string","title":"User Id"},"owner":{"anyOf":[{"$ref":"#/components/schemas/Owner"},{"type":"null"}]},"summary":{"$ref":"#/components/schemas/SetSummary"},"payload_bytes":{"type":"integer","title":"Payload Bytes"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"deleted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Deleted At"},"deleted_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Deleted By"},"payload":{"type":"object","title":"Payload"}},"type":"object","required":["id","name","user_id","summary","payload_bytes","created_at","updated_at","payload"],"title":"AdminSetDetail"},"AdminSetRow":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"user_id":{"type":"string","title":"User Id"},"owner":{"anyOf":[{"$ref":"#/components/schemas/Owner"},{"type":"null"}]},"summary":{"$ref":"#/components/schemas/SetSummary"},"payload_bytes":{"type":"integer","title":"Payload Bytes"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"deleted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Deleted At"},"deleted_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Deleted By"}},"type":"object","required":["id","name","user_id","summary","payload_bytes","created_at","updated_at"],"title":"AdminSetRow"},"AnalyzeRequest":{"properties":{"question":{"type":"string","title":"Question"},"city_id":{"type":"integer","title":"City Id"},"chain_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Chain Id"},"days":{"type":"integer","title":"Days","default":30}},"type":"object","required":["question","city_id"],"title":"AnalyzeRequest","description":"Request model for analyze endpoint."},"AnalyzeResponse":{"properties":{"status":{"type":"string","title":"Status"},"answer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Answer"},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"context":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Context"},"task_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Task Id"}},"type":"object","required":["status"],"title":"AnalyzeResponse","description":"Response model for analyze endpoint."},"Body_login_form_api_auth_login_form_post":{"properties":{"grant_type":{"anyOf":[{"type":"string","pattern":"password"},{"type":"null"}],"title":"Grant Type"},"username":{"type":"string","title":"Username"},"password":{"type":"string","title":"Password"},"scope":{"type":"string","title":"Scope","default":""},"client_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Id"},"client_secret":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Secret"}},"type":"object","required":["username","password"],"title":"Body_login_form_api_auth_login_form_post"},"BulkRequest":{"properties":{"ids":{"items":{"type":"string","maxLength":64},"type":"array","maxItems":200,"minItems":1,"title":"Ids"},"action":{"type":"string","enum":["delete","restore"],"title":"Action"}},"type":"object","required":["ids","action"],"title":"BulkRequest"},"BulkResponse":{"properties":{"affected":{"type":"integer","title":"Affected"},"requested":{"type":"integer","title":"Requested"}},"type":"object","required":["affected","requested"],"title":"BulkResponse"},"CategoryMappingResponse":{"properties":{"id":{"type":"integer","title":"Id"},"platform":{"type":"string","title":"Platform"},"source_category":{"type":"string","title":"Source Category"},"target_slug":{"type":"string","title":"Target Slug"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"}},"type":"object","required":["id","platform","source_category","target_slug"],"title":"CategoryMappingResponse"},"CategoryResponse":{"properties":{"id":{"type":"integer","title":"Id"},"slug":{"type":"string","title":"Slug"},"name":{"type":"string","title":"Name"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"}},"type":"object","required":["id","slug","name"],"title":"CategoryResponse"},"CategoryWithStatsResponse":{"properties":{"slug":{"type":"string","title":"Slug"},"name":{"type":"string","title":"Name"},"poi_count":{"type":"integer","title":"Poi Count"}},"type":"object","required":["slug","name","poi_count"],"title":"CategoryWithStatsResponse"},"ChainResponse":{"properties":{"id":{"type":"integer","title":"Id"},"name":{"type":"string","title":"Name"},"country_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country Code"},"country_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country Name"},"poi_count":{"type":"integer","title":"Poi Count"}},"type":"object","required":["id","name","poi_count"],"title":"ChainResponse"},"CityResponse":{"properties":{"id":{"type":"integer","title":"Id"},"name":{"type":"string","title":"Name"},"country":{"type":"string","title":"Country"},"country_name":{"type":"string","title":"Country Name"},"sync_enabled":{"type":"boolean","title":"Sync Enabled","default":false},"retention_months":{"type":"integer","title":"Retention Months","default":12},"last_sync":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Sync"},"reviews_count":{"type":"integer","title":"Reviews Count","default":0},"has_geo_json":{"type":"boolean","title":"Has Geo Json","default":false}},"type":"object","required":["id","name","country","country_name"],"title":"CityResponse"},"CityUpdate":{"properties":{"sync_enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Sync Enabled"},"retention_months":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Retention Months"}},"type":"object","title":"CityUpdate"},"ComparisonCreate":{"properties":{"chain_id":{"type":"integer","title":"Chain Id"},"chain_name":{"type":"string","title":"Chain Name"},"country_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country Code"},"entity_type":{"type":"string","title":"Entity Type","default":"brands"},"fr_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Fr Id"}},"type":"object","required":["chain_id","chain_name"],"title":"ComparisonCreate"},"ComparisonResponse":{"properties":{"id":{"type":"integer","title":"Id"},"chain_id":{"type":"integer","title":"Chain Id"},"chain_name":{"type":"string","title":"Chain Name"},"country_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country Code"},"entity_type":{"type":"string","title":"Entity Type"},"fr_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Fr Id"},"city_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City Name"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","chain_id","chain_name","entity_type","created_at"],"title":"ComparisonResponse"},"ComparisonUpdate":{"properties":{"fr_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Fr Id"}},"type":"object","title":"ComparisonUpdate"},"CopyRequest":{"properties":{"target_user_id":{"type":"string","maxLength":64,"minLength":1,"title":"Target User Id"},"new_name":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"New Name"},"mode":{"type":"string","enum":["ask","overwrite","duplicate"],"title":"Mode","default":"ask"}},"type":"object","required":["target_user_id"],"title":"CopyRequest"},"CopyResponse":{"properties":{"outcome":{"type":"string","enum":["ask","created","overwritten"],"title":"Outcome"},"source_id":{"type":"string","title":"Source Id"},"target":{"$ref":"#/components/schemas/Owner"},"access":{"$ref":"#/components/schemas/AccessReport"},"existing_copies":{"items":{"$ref":"#/components/schemas/ExistingCopy"},"type":"array","title":"Existing Copies"},"set_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Set Id"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}},"type":"object","required":["outcome","source_id","target","access"],"title":"CopyResponse"},"CountryResponse":{"properties":{"id":{"type":"integer","title":"Id"},"name":{"type":"string","title":"Name"},"code":{"type":"string","title":"Code"},"status":{"type":"integer","title":"Status"},"updated":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated"},"cities_count":{"type":"integer","title":"Cities Count","default":0},"reviews_count":{"type":"integer","title":"Reviews Count","default":0},"chain_matching_enabled":{"type":"boolean","title":"Chain Matching Enabled","default":false},"sync_enabled":{"type":"boolean","title":"Sync Enabled","default":false},"last_sync":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Sync"}},"type":"object","required":["id","name","code","status"],"title":"CountryResponse"},"CreateExportRequest":{"properties":{"filters":{"$ref":"#/components/schemas/ExportFilters"},"fields":{"items":{"type":"string"},"type":"array","title":"Fields"}},"type":"object","required":["filters","fields"],"title":"CreateExportRequest"},"CreateVersionRequest":{"properties":{"system_prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"System Prompt"},"user_prompt":{"type":"string","title":"User Prompt"},"model":{"type":"string","title":"Model","default":"gemini-2.5-flash-lite"},"temperature":{"type":"number","title":"Temperature","default":0.1},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"set_as_current":{"type":"boolean","title":"Set As Current","default":true}},"type":"object","required":["user_prompt"],"title":"CreateVersionRequest"},"ExistingCopy":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"copied_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Copied At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"edited_since_copy":{"type":"boolean","title":"Edited Since Copy","default":false}},"type":"object","required":["id","name","updated_at"],"title":"ExistingCopy"},"ExportFilters":{"properties":{"country_codes":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Country Codes"},"city_ids":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"City Ids"},"chain_ids":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"Chain Ids"},"date_from":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Date From"},"date_to":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Date To"},"sentiment":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sentiment"},"platform":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Platform"},"ratings":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"Ratings"},"search":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Search"},"include_empty":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Empty"},"complaint_category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Complaint Category"},"praise_category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Praise Category"},"country_names":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Country Names"},"city_names":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"City Names"},"chain_names":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Chain Names"}},"type":"object","title":"ExportFilters"},"ExportResponse":{"properties":{"id":{"type":"string","title":"Id"},"filters":{"type":"object","title":"Filters"},"fields":{"items":{},"type":"array","title":"Fields"},"status":{"type":"string","title":"Status"},"progress_current":{"type":"integer","title":"Progress Current"},"progress_total":{"type":"integer","title":"Progress Total"},"error_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Message"},"file_size":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"File Size"},"row_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Row Count"},"created_at":{"type":"string","title":"Created At"},"started_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Started At"},"completed_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Completed At"}},"type":"object","required":["id","filters","fields","status","progress_current","progress_total","error_message","file_size","row_count","created_at","started_at","completed_at"],"title":"ExportResponse"},"FranchiseeBreakdownItem":{"properties":{"fr_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Fr Id"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"count":{"type":"integer","title":"Count"}},"type":"object","required":["count"],"title":"FranchiseeBreakdownItem"},"FranchiseeResponse":{"properties":{"id":{"type":"integer","title":"Id"},"name":{"type":"string","title":"Name"},"country":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"}},"type":"object","required":["id","name"],"title":"FranchiseeResponse"},"GrantSummary":{"properties":{"country_code":{"type":"string","title":"Country Code"},"chain_count":{"type":"integer","title":"Chain Count","default":0},"cities":{"items":{"type":"string"},"type":"array","title":"Cities"}},"type":"object","required":["country_code"],"title":"GrantSummary","description":"One entry of users.menu_access_items, in words rather than in ids.\n\nThe list groups benchmarks by account, and what decides whether a copy will\nshow anything is the ACCOUNT's grants, not the benchmark. So the answer\nbelongs in the group header, where it is read before a set is even picked —\nnot only inside the copy dialog, after the choice is made."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"InsightResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"city_id":{"type":"integer","title":"City Id"},"chain":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chain"},"period_start":{"type":"string","format":"date","title":"Period Start"},"period_end":{"type":"string","format":"date","title":"Period End"},"summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Summary"},"insights_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}],"title":"Insights Data"},"reviews_analyzed":{"type":"integer","title":"Reviews Analyzed"},"generated_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Generated At"}},"type":"object","required":["id","city_id","chain","period_start","period_end","summary","insights_data","reviews_analyzed","generated_at"],"title":"InsightResponse"},"LoginRequest":{"properties":{"email":{"type":"string","title":"Email"},"password":{"type":"string","title":"Password"}},"type":"object","required":["email","password"],"title":"LoginRequest"},"MenuAccessItemSchema":{"properties":{"country_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country Code"},"chain_ids":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"Chain Ids"},"city_ids":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"City Ids"}},"additionalProperties":true,"type":"object","title":"MenuAccessItemSchema","description":"One entry in the users.menu_access_items JSONB array.\n\nThe column is free-form JSONB, so this schema documents the keys the app\nactually reads rather than locking the shape down. Unknown keys are kept\n(extra=\"allow\") because PUT replaces the whole value, and every field is\noptional: a missing chain_ids or city_ids means \"no restriction on that\ndimension\" to both the frontend (MenuFilterContext.restrictCities) and the\nGo API (UserAccess.AllowedMenuChainIDs / UserAccess.MenuCityRestriction in\ninternal/models/user_access.go)."},"MigrateRequest":{"properties":{"sets":{"items":{"$ref":"#/components/schemas/SetUpsert"},"type":"array","title":"Sets"},"ids":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Ids"}},"type":"object","title":"MigrateRequest"},"MoveRequest":{"properties":{"target_user_id":{"type":"string","maxLength":64,"minLength":1,"title":"Target User Id"},"new_name":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"New Name"}},"type":"object","required":["target_user_id"],"title":"MoveRequest"},"MoveResponse":{"properties":{"source_id":{"type":"string","title":"Source Id"},"set_id":{"type":"string","title":"Set Id"},"name":{"type":"string","title":"Name"},"target":{"$ref":"#/components/schemas/Owner"},"access":{"$ref":"#/components/schemas/AccessReport"}},"type":"object","required":["source_id","set_id","name","target","access"],"title":"MoveResponse"},"Owner":{"properties":{"user_id":{"type":"string","title":"User Id"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"source":{"type":"string","enum":["local","getplace"],"title":"Source","default":"getplace"},"allow_menu_access":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Allow Menu Access"},"can_sign_in":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Can Sign In"},"grants":{"items":{"$ref":"#/components/schemas/GrantSummary"},"type":"array","title":"Grants"}},"type":"object","required":["user_id"],"title":"Owner"},"POIResponse":{"properties":{"poi_id":{"type":"string","title":"Poi Id"},"name":{"type":"string","title":"Name"},"address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address"},"bid":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bid"},"source":{"type":"string","title":"Source"},"chain_id":{"type":"integer","title":"Chain Id"},"chain_name":{"type":"string","title":"Chain Name"},"store_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Store Id"}},"type":"object","required":["poi_id","name","source","chain_id","chain_name"],"title":"POIResponse"},"PlatformCurrencyResponse":{"properties":{"id":{"type":"integer","title":"Id"},"country_code":{"type":"string","title":"Country Code"},"platform":{"type":"string","title":"Platform"},"currency":{"type":"string","title":"Currency"}},"type":"object","required":["id","country_code","platform","currency"],"title":"PlatformCurrencyResponse"},"PlatformStatsResponse":{"properties":{"platform":{"type":"string","title":"Platform"},"total_mappings":{"type":"integer","title":"Total Mappings"},"unique_categories":{"type":"integer","title":"Unique Categories"}},"type":"object","required":["platform","total_mappings","unique_categories"],"title":"PlatformStatsResponse"},"PreviewItem":{"properties":{"set_id":{"type":"string","title":"Set Id"},"name":{"type":"string","title":"Name"},"access":{"$ref":"#/components/schemas/AccessReport"},"existing_copies":{"items":{"$ref":"#/components/schemas/ExistingCopy"},"type":"array","title":"Existing Copies"}},"type":"object","required":["set_id","name","access"],"title":"PreviewItem"},"PreviewRequest":{"properties":{"ids":{"items":{"type":"string","maxLength":64},"type":"array","maxItems":200,"minItems":1,"title":"Ids"},"target_user_id":{"type":"string","maxLength":64,"minLength":1,"title":"Target User Id"}},"type":"object","required":["ids","target_user_id"],"title":"PreviewRequest"},"PreviewResponse":{"properties":{"target":{"$ref":"#/components/schemas/Owner"},"items":{"items":{"$ref":"#/components/schemas/PreviewItem"},"type":"array","title":"Items"}},"type":"object","required":["target"],"title":"PreviewResponse"},"PromptListResponse":{"properties":{"id":{"type":"integer","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"current_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Current Version"},"versions_count":{"type":"integer","title":"Versions Count"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"}},"type":"object","required":["id","name","description","current_version","versions_count","updated_at"],"title":"PromptListResponse"},"PromptResponse":{"properties":{"id":{"type":"integer","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"},"versions":{"items":{"$ref":"#/components/schemas/PromptVersionResponse"},"type":"array","title":"Versions","default":[]},"current_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Current Version"}},"type":"object","required":["id","name","description","created_at","updated_at"],"title":"PromptResponse"},"PromptVersionResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"version":{"type":"integer","title":"Version"},"system_prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"System Prompt"},"user_prompt":{"type":"string","title":"User Prompt"},"model":{"type":"string","title":"Model"},"temperature":{"type":"number","title":"Temperature"},"is_current":{"type":"boolean","title":"Is Current"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"}},"type":"object","required":["id","version","system_prompt","user_prompt","model","temperature","is_current","notes","created_at","updated_at"],"title":"PromptVersionResponse"},"RenameRequest":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name"}},"type":"object","required":["name"],"title":"RenameRequest"},"RequestAccessRequest":{"properties":{"name":{"type":"string","title":"Name"},"email":{"type":"string","title":"Email"},"brand":{"type":"string","title":"Brand","default":""},"role":{"type":"string","title":"Role","default":"subscriber"}},"type":"object","required":["name","email"],"title":"RequestAccessRequest"},"RequiredAccess":{"properties":{"chain_ids":{"items":{"type":"integer"},"type":"array","title":"Chain Ids"},"city_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"City Id"},"country":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country"}},"type":"object","title":"RequiredAccess","description":"The data a benchmark needs its owner to be allowed to see."},"ResolvedUser":{"properties":{"user_id":{"type":"string","title":"User Id"},"email":{"type":"string","title":"Email"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"source":{"type":"string","enum":["local","getplace"],"title":"Source"},"allow_menu_access":{"type":"boolean","title":"Allow Menu Access","default":false},"menu_access_items":{"items":{"type":"object"},"type":"array","title":"Menu Access Items"},"set_count":{"type":"integer","title":"Set Count","default":0},"can_sign_in":{"type":"boolean","title":"Can Sign In","default":true}},"type":"object","required":["user_id","email","source"],"title":"ResolvedUser"},"SetResponse":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"payload":{"type":"object","title":"Payload"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"deleted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Deleted At"}},"type":"object","required":["id","name","payload","created_at","updated_at"],"title":"SetResponse"},"SetSummary":{"properties":{"my_chain":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"My Chain"},"my_chain_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"My Chain Id"},"competitors":{"items":{"type":"string"},"type":"array","title":"Competitors"},"rows_count":{"type":"integer","title":"Rows Count","default":0},"country":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country"},"city_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City Id"},"platform":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Platform"},"copied_from":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Copied From"}},"type":"object","title":"SetSummary","description":"What a benchmark is, read off its payload so the list can skip the blob.\n\nA payload is tens of kilobytes; fifty of them in one response is megabytes\nof store links and per-store overrides that the list would not render."},"SetUpsert":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name"},"payload":{"type":"object","title":"Payload"},"base_updated_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Base Updated At"}},"type":"object","required":["name","payload"],"title":"SetUpsert"},"SizeEntryResponse":{"properties":{"chain_id":{"type":"integer","title":"Chain Id"},"product_name":{"type":"string","title":"Product Name"},"normalized_name":{"type":"string","title":"Normalized Name"},"platform":{"type":"string","title":"Platform","default":""},"shelf":{"type":"string","title":"Shelf","default":""},"amount":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Amount"},"unit":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Unit"},"no_size":{"type":"boolean","title":"No Size"},"source_note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Note"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["chain_id","product_name","normalized_name","no_size","updated_at"],"title":"SizeEntryResponse"},"SizeUpsert":{"properties":{"product_name":{"type":"string","maxLength":500,"minLength":1,"title":"Product Name"},"platform":{"anyOf":[{"type":"string","maxLength":50},{"type":"null"}],"title":"Platform"},"shelf":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Shelf"},"amount":{"anyOf":[{"type":"number","maximum":9999999.999,"minimum":0.001},{"type":"string"},{"type":"null"}],"title":"Amount"},"unit":{"anyOf":[{"type":"string","enum":["ml","cl","l","floz","g","kg","cm","mm","pcs"]},{"type":"null"}],"title":"Unit"},"no_size":{"type":"boolean","title":"No Size","default":false},"source_note":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Source Note"}},"type":"object","required":["product_name"],"title":"SizeUpsert"},"SubscribeRequest":{"properties":{"email":{"type":"string","title":"Email"}},"type":"object","required":["email"],"title":"SubscribeRequest"},"SyncTaskResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"city_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"City Id"},"task_type":{"type":"string","title":"Task Type"},"status":{"type":"string","title":"Status"},"params":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Params"},"result":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Result"},"error_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Message"},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At"},"completed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Completed At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"progress_current":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Progress Current","default":0},"progress_total":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Progress Total","default":0},"progress_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Progress Message"}},"type":"object","required":["id","task_type","status","params","result","error_message","started_at","completed_at","created_at"],"title":"SyncTaskResponse"},"TestPromptRequest":{"properties":{"version_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Version Id"},"test_input":{"type":"string","title":"Test Input"}},"type":"object","required":["test_input"],"title":"TestPromptRequest"},"TestPromptResponse":{"properties":{"success":{"type":"boolean","title":"Success"},"result":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Result"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"},"model_used":{"type":"string","title":"Model Used"},"prompt_version":{"type":"integer","title":"Prompt Version"}},"type":"object","required":["success","model_used","prompt_version"],"title":"TestPromptResponse"},"TokenLoginRequest":{"properties":{"token":{"type":"string","title":"Token"}},"type":"object","required":["token"],"title":"TokenLoginRequest"},"TokenResponse":{"properties":{"access_token":{"type":"string","title":"Access Token"},"token_type":{"type":"string","title":"Token Type","default":"bearer"},"user":{"$ref":"#/components/schemas/app__api__auth_api__UserResponse"}},"type":"object","required":["access_token","user"],"title":"TokenResponse"},"UpdateVersionRequest":{"properties":{"system_prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"System Prompt"},"user_prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Prompt"},"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model"},"temperature":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Temperature"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"}},"type":"object","title":"UpdateVersionRequest"},"UserCreate":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"password":{"type":"string","title":"Password"},"name":{"type":"string","title":"Name"},"role":{"type":"string","title":"Role","default":"client"},"allow_menu_access":{"type":"boolean","title":"Allow Menu Access","default":false},"menu_access_items":{"anyOf":[{"items":{"$ref":"#/components/schemas/MenuAccessItemSchema"},"type":"array"},{"type":"null"}],"title":"Menu Access Items"}},"type":"object","required":["email","password","name"],"title":"UserCreate"},"UserUpdate":{"properties":{"email":{"anyOf":[{"type":"string","format":"email"},{"type":"null"}],"title":"Email"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"role":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Role"},"is_active":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Active"},"password":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Password"},"allow_menu_access":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Allow Menu Access"},"menu_access_items":{"anyOf":[{"items":{"$ref":"#/components/schemas/MenuAccessItemSchema"},"type":"array"},{"type":"null"}],"title":"Menu Access Items"}},"type":"object","title":"UserUpdate"},"UsersListResponse":{"properties":{"users":{"items":{"$ref":"#/components/schemas/app__api__users__UserResponse"},"type":"array","title":"Users"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["users","total"],"title":"UsersListResponse"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"app__api__auth_api__UserResponse":{"properties":{"id":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Id"},"email":{"type":"string","title":"Email"},"name":{"type":"string","title":"Name"},"role":{"type":"string","title":"Role"},"is_active":{"type":"boolean","title":"Is Active"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"last_login":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Login"},"allow_reviews_access":{"type":"boolean","title":"Allow Reviews Access","default":false},"allow_menu_access":{"type":"boolean","title":"Allow Menu Access","default":false},"menu_access_items":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}],"title":"Menu Access Items"},"enable_city_explore":{"type":"boolean","title":"Enable City Explore","default":false},"enable_visibility":{"type":"boolean","title":"Enable Visibility","default":false},"enable_delivery_zone":{"type":"boolean","title":"Enable Delivery Zone","default":false},"is_master_bk":{"type":"boolean","title":"Is Master Bk","default":false},"enable_client_reviews_access":{"type":"boolean","title":"Enable Client Reviews Access","default":false},"enable_country_explorer":{"type":"boolean","title":"Enable Country Explorer","default":false},"enable_store_ranking":{"type":"boolean","title":"Enable Store Ranking","default":false},"allow_promo_access":{"type":"boolean","title":"Allow Promo Access","default":false}},"type":"object","required":["id","email","name","role","is_active"],"title":"UserResponse"},"app__api__users__UserResponse":{"properties":{"id":{"type":"integer","title":"Id"},"email":{"type":"string","title":"Email"},"name":{"type":"string","title":"Name"},"role":{"type":"string","title":"Role"},"is_active":{"type":"boolean","title":"Is Active"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"},"last_login":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Login"},"allow_menu_access":{"type":"boolean","title":"Allow Menu Access","default":false},"menu_access_items":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}],"title":"Menu Access Items"}},"type":"object","required":["id","email","name","role","is_active","created_at","updated_at","last_login"],"title":"UserResponse"}},"securitySchemes":{"HTTPBasic":{"type":"http","scheme":"basic"},"OAuth2PasswordBearer":{"type":"oauth2","flows":{"password":{"scopes":{},"tokenUrl":"/api/auth/login"}}}}}}