{"openapi":"3.1.0","info":{"title":"Hub Service API","description":"\nHub Service de Blueorange: automatiza el alta y la gestión del ciclo de\nvida de instancias Odoo (estilo odoo.sh) — proyectos, instancias por etapa,\nbuilds y aprovisionamiento en segundo plano.\n","contact":{"name":"Blueorange","url":"https://www.blueorange.com.ar/","email":"odoo@blueorange.com.ar"},"version":"0.1.0"},"paths":{"/metrics":{"get":{"tags":["metrics"],"summary":"Prometheus Metrics","description":"Métricas en formato Prometheus (scrapeadas por el Prometheus interno).","operationId":"prometheus_metrics_metrics_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/health":{"get":{"tags":["health"],"summary":"Health","description":"Healthcheck liviano para docker-compose y monitoreo.\n\nSolo verifica la conectividad con la base (sin exponer datos). Responde 503\nsi la base no está disponible.","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/instances":{"post":{"tags":["api"],"summary":"Create Instance","description":"Aprovisiona una nueva instancia y la encola para su despliegue.","operationId":"create_instance_api_v1_instances_post","security":[{"HTTPBasic":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstanceCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstanceOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["api"],"summary":"List Instances","description":"Lista instancias (filtros opcionales por etapa y estado).","operationId":"list_instances_api_v1_instances_get","security":[{"HTTPBasic":[]}],"parameters":[{"name":"stage","in":"query","required":false,"schema":{"type":"string","default":"","title":"Stage"}},{"name":"status_filter","in":"query","required":false,"schema":{"type":"string","default":"","title":"Status Filter"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/InstanceOut"},"title":"Response List Instances Api V1 Instances Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/instances/{slug}":{"get":{"tags":["api"],"summary":"Get Instance","description":"Devuelve el detalle de una instancia por slug.","operationId":"get_instance_api_v1_instances__slug__get","security":[{"HTTPBasic":[]}],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstanceOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/instances/{slug}/action":{"post":{"tags":["api"],"summary":"Instance Action","description":"Ejecuta una acción (start | restart | stop | rebuild | destroy) sobre la instancia.\n\nTodas las acciones —incluida ``destroy``— exigen rol de escritura, en paridad\ncon la web, donde un developer puede operar (y destruir) instancias.","operationId":"instance_action_api_v1_instances__slug__action_post","security":[{"HTTPBasic":[]}],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstanceAction"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstanceOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/migrations":{"post":{"tags":["api"],"summary":"Create Migration","description":"Crea una migración (queda en ``draft``; la corrida se dispara aparte).\n\nLa entrada por upload requiere subir el dump por la web; vía API solo se\nadmite ``pull_url`` (o registrar el ``draft`` y cargar el dump luego).","operationId":"create_migration_api_v1_migrations_post","security":[{"HTTPBasic":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MigrationCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MigrationOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["api"],"summary":"List Migrations","description":"Lista migraciones (filtros opcionales por estado y búsqueda por nombre).","operationId":"list_migrations_api_v1_migrations_get","security":[{"HTTPBasic":[]}],"parameters":[{"name":"status_filter","in":"query","required":false,"schema":{"type":"string","default":"","title":"Status Filter"}},{"name":"search","in":"query","required":false,"schema":{"type":"string","default":"","title":"Search"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MigrationOut"},"title":"Response List Migrations Api V1 Migrations Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/migrations/{slug}":{"get":{"tags":["api"],"summary":"Get Migration","description":"Devuelve el detalle de una migración por slug.","operationId":"get_migration_api_v1_migrations__slug__get","security":[{"HTTPBasic":[]}],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MigrationOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/migrations/{slug}/run":{"post":{"tags":["api"],"summary":"Run Migration","description":"Crea una corrida, marca la migración en cola y la encola en el worker.","operationId":"run_migration_api_v1_migrations__slug__run_post","security":[{"HTTPBasic":[]}],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/migrations/{slug}/runs":{"get":{"tags":["api"],"summary":"List Migration Runs","description":"Lista las corridas de una migración (más reciente primero).","operationId":"list_migration_runs_api_v1_migrations__slug__runs_get","security":[{"HTTPBasic":[]}],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RunOut"},"title":"Response List Migration Runs Api V1 Migrations  Slug  Runs Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/migrations/{slug}/runs/{number}":{"get":{"tags":["api"],"summary":"Get Migration Run","description":"Devuelve una corrida puntual con sus pasos.","operationId":"get_migration_run_api_v1_migrations__slug__runs__number__get","security":[{"HTTPBasic":[]}],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}},{"name":"number","in":"path","required":true,"schema":{"type":"integer","title":"Number"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/migrations":{"get":{"tags":["migrations"],"summary":"Migrations List","description":"Listado de migraciones con filtro por estado y búsqueda por nombre.","operationId":"migrations_list_migrations_get","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","default":1,"title":"Page"}},{"name":"search","in":"query","required":false,"schema":{"type":"string","default":"","title":"Search"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","default":"","title":"Status"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/migrations/new":{"get":{"tags":["migrations"],"summary":"Migration New Form","description":"Formulario de alta de una migración.","operationId":"migration_new_form_migrations_new_get","parameters":[{"name":"error","in":"query","required":false,"schema":{"type":"string","default":"","title":"Error"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["migrations"],"summary":"Migration Create","description":"Crea una migración y (si es upload) guarda el dump y su filestore.\n\nValida contra los catálogos de ``constants``, deriva un slug único, resuelve\nla receta para la ruta y arma la base de trabajo con ``naming.db_name_for``.\nQueda en estado ``draft``: la corrida se dispara aparte desde el detalle.","operationId":"migration_create_migrations_new_post","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_migration_create_migrations_new_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/migrations/{slug}":{"get":{"tags":["migrations"],"summary":"Migration Detail","description":"Detalle: migración, corridas, pasos de la última corrida y artefactos.","operationId":"migration_detail_migrations__slug__get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/migrations/{slug}/edit":{"post":{"tags":["migrations"],"summary":"Migration Edit","description":"Edita datos de la migración. Qué se puede tocar depende del estado:\n\n- Borrador (nunca corrió): ruta (origen/destino/flavor) — que RE-DERIVA la\n  receta —, motor, propósito, contrato y notificar-a.\n- Ya corrió (cualquier otro estado): solo lo inofensivo — contrato y\n  notificar-a. Los campos que definieron cómo corrió se ignoran del lado del\n  servidor aunque lleguen en el POST.","operationId":"migration_edit_migrations__slug__edit_post","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_migration_edit_migrations__slug__edit_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/migrations/{slug}/runs/{number}":{"get":{"tags":["migrations"],"summary":"Run Detail","description":"Detalle de una corrida puntual con sus pasos.","operationId":"run_detail_migrations__slug__runs__number__get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}},{"name":"number","in":"path","required":true,"schema":{"type":"integer","title":"Number"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/migrations/{slug}/runs/{number}/report":{"post":{"tags":["migrations"],"summary":"Run Report Generate","description":"Genera (sincrónico) el reporte PDF de una corrida y lo registra como artefacto.","operationId":"run_report_generate_migrations__slug__runs__number__report_post","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}},{"name":"number","in":"path","required":true,"schema":{"type":"integer","title":"Number"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/migrations/{slug}/artifacts/{artifact_id}/download":{"get":{"tags":["migrations"],"summary":"Artifact Download","description":"Descarga un artefacto (backup, dump, filestore, log o reporte) de la migración.","operationId":"artifact_download_migrations__slug__artifacts__artifact_id__download_get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}},{"name":"artifact_id","in":"path","required":true,"schema":{"type":"integer","title":"Artifact Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/migrations/{slug}/run":{"post":{"tags":["migrations"],"summary":"Migration Run","description":"Corre la migración. Si la última corrida FALLÓ y tiene checkpoint, la\nREANUDA desde el paso que falló (no re-ejecuta los pasos ya completados: no\nre-descarga ni re-restaura). Si no, crea una corrida nueva desde cero.\n\nPara volver a arrancar de cero, usar «Detener / volver al inicio» (borra las\ncorridas y deja la migración en borrador).","operationId":"migration_run_migrations__slug__run_post","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/migrations/{slug}/run-anyway":{"post":{"tags":["migrations"],"summary":"Migration Run Anyway","description":"Reintenta saltando el pre-flight (override auditado). Solo tiene sentido\ncuando la última corrida falló EN el pre-flight.","operationId":"migration_run_anyway_migrations__slug__run_anyway_post","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/migrations/{slug}/resync":{"get":{"tags":["migrations"],"summary":"Migration Resync Confirm","description":"Confirmación de re-sync: muestra el diff snapshot ↔ receta actual.","operationId":"migration_resync_confirm_migrations__slug__resync_get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["migrations"],"summary":"Migration Resync Apply","description":"Aplica la decisión: ``adopt`` re-materializa; ``keep`` reanuda como está.","operationId":"migration_resync_apply_migrations__slug__resync_post","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_migration_resync_apply_migrations__slug__resync_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/migrations/{slug}/pause":{"post":{"tags":["migrations"],"summary":"Migration Pause","description":"Pausa: mata el paso en curso y vuelve al último checkpoint (resumible).","operationId":"migration_pause_migrations__slug__pause_post","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/migrations/{slug}/stop":{"post":{"tags":["migrations"],"summary":"Migration Stop","description":"Vuelve al punto de partida: destruye las instancias de trabajo, borra las\ncorridas y deja la migración en borrador. Disponible en CUALQUIER estado con\ntrabajo (en ejecución, pausada, con error, migrada). Si hay una corrida viva,\nseñaliza al worker (mata el paso en curso); si no, resetea directo.","operationId":"migration_stop_migrations__slug__stop_post","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/migrations/{slug}/resume":{"post":{"tags":["migrations"],"summary":"Migration Resume","description":"Reanuda una migración pausada: re-encola desde el último checkpoint.","operationId":"migration_resume_migrations__slug__resume_post","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/migrations/{slug}/runs/{number}/resume":{"post":{"tags":["migrations"],"summary":"Run Resume","description":"Resuelve una puerta manual y reanuda la corrida desde ese paso.","operationId":"run_resume_migrations__slug__runs__number__resume_post","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}},{"name":"number","in":"path","required":true,"schema":{"type":"integer","title":"Number"}}],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_run_resume_migrations__slug__runs__number__resume_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/migrations/{slug}/delete":{"post":{"tags":["migrations"],"summary":"Migration Delete","description":"Elimina la migración (corridas, pasos y artefactos). Type-to-confirm.","operationId":"migration_delete_migrations__slug__delete_post","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_migration_delete_migrations__slug__delete_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/migrations/{slug}/runs/{number}/logs":{"get":{"tags":["migrations"],"summary":"Run Logs Page","description":"Visor de logs en vivo de una corrida.","operationId":"run_logs_page_migrations__slug__runs__number__logs_get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}},{"name":"number","in":"path","required":true,"schema":{"type":"integer","title":"Number"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/migrations/{slug}/runs/{number}/logs/download":{"get":{"tags":["migrations"],"summary":"Run Logs Download","description":"Descarga el log acumulado de la corrida como texto plano.","operationId":"run_logs_download_migrations__slug__runs__number__logs_download_get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}},{"name":"number","in":"path","required":true,"schema":{"type":"integer","title":"Number"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/recipes":{"get":{"tags":["migrations"],"summary":"Recipes List","description":"Listado de recetas de migración (todas, incluso rotas) con su lint.","operationId":"recipes_list_admin_recipes_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/admin/recipes/new":{"get":{"tags":["migrations"],"summary":"Recipe New Form","description":"Formulario de alta de una receta nueva, con la plantilla como punto de partida.","operationId":"recipe_new_form_admin_recipes_new_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/admin/recipes/{flavor}/{stem}/edit":{"get":{"tags":["migrations"],"summary":"Recipe Edit Form","description":"Formulario de edición del YAML crudo de una receta existente.","operationId":"recipe_edit_form_admin_recipes__flavor___stem__edit_get","parameters":[{"name":"flavor","in":"path","required":true,"schema":{"type":"string","title":"Flavor"}},{"name":"stem","in":"path","required":true,"schema":{"type":"string","title":"Stem"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/recipes/save":{"post":{"tags":["migrations"],"summary":"Recipe Save","description":"Un solo endpoint para «Validar» y «Guardar», alta o edición.\n\n``key`` viene en la edición (input oculto); ``flavor``+``stem`` en el alta\n(con ellos se arma la key). El texto del usuario NUNCA se pierde: cualquier\nerror re-renderiza el editor con lo que escribió, nunca redirige a ciegas.","operationId":"recipe_save_admin_recipes_save_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_recipe_save_admin_recipes_save_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/instances/{slug}/shell":{"get":{"tags":["shell"],"summary":"Shell Page","description":"Página con la terminal web de la instancia.","operationId":"shell_page_instances__slug__shell_get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/instances/{slug}/logs":{"get":{"tags":["logs"],"summary":"Logs Page","description":"Página del visor de logs.","operationId":"logs_page_instances__slug__logs_get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/instances/{slug}/logs/download":{"get":{"tags":["logs"],"summary":"Logs Download","description":"Descarga los logs (odoo|db) como archivo de texto.","operationId":"logs_download_instances__slug__logs_download_get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}},{"name":"source","in":"query","required":false,"schema":{"type":"string","default":"odoo","title":"Source"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/webhooks/git/{project_slug}/{token}":{"post":{"tags":["webhooks"],"summary":"Git Webhook","description":"Dispara auto-deploy ante un push (Bitbucket/GitHub), a nivel proyecto.\n\nEl webhook se configura una sola vez por proyecto. Se valida con el token\ndeterminístico del proyecto. En cada push se extrae la rama y se rebuildean\ntodas las instancias del proyecto cuya rama coincide; las demás se ignoran.","operationId":"git_webhook_webhooks_git__project_slug___token__post","parameters":[{"name":"project_slug","in":"path","required":true,"schema":{"type":"string","title":"Project Slug"}},{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/instances/{slug}/editor/proxy/{path}":{"put":{"tags":["editor"],"summary":"Editor Http Proxy","description":"Proxya una request HTTP al JupyterLab interno, inyectando el token.","operationId":"editor_http_proxy_instances__slug__editor_proxy__path__put","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}},{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["editor"],"summary":"Editor Http Proxy","description":"Proxya una request HTTP al JupyterLab interno, inyectando el token.","operationId":"editor_http_proxy_instances__slug__editor_proxy__path__put","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}},{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"head":{"tags":["editor"],"summary":"Editor Http Proxy","description":"Proxya una request HTTP al JupyterLab interno, inyectando el token.","operationId":"editor_http_proxy_instances__slug__editor_proxy__path__put","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}},{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["editor"],"summary":"Editor Http Proxy","description":"Proxya una request HTTP al JupyterLab interno, inyectando el token.","operationId":"editor_http_proxy_instances__slug__editor_proxy__path__put","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}},{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"options":{"tags":["editor"],"summary":"Editor Http Proxy","description":"Proxya una request HTTP al JupyterLab interno, inyectando el token.","operationId":"editor_http_proxy_instances__slug__editor_proxy__path__put","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}},{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["editor"],"summary":"Editor Http Proxy","description":"Proxya una request HTTP al JupyterLab interno, inyectando el token.","operationId":"editor_http_proxy_instances__slug__editor_proxy__path__put","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}},{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["editor"],"summary":"Editor Http Proxy","description":"Proxya una request HTTP al JupyterLab interno, inyectando el token.","operationId":"editor_http_proxy_instances__slug__editor_proxy__path__put","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}},{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/instances/{slug}/code/proxy/{path}":{"put":{"tags":["code"],"summary":"Code Http Proxy","description":"Proxya una request HTTP al VS Code web interno.","operationId":"code_http_proxy_instances__slug__code_proxy__path__put","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}},{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["code"],"summary":"Code Http Proxy","description":"Proxya una request HTTP al VS Code web interno.","operationId":"code_http_proxy_instances__slug__code_proxy__path__put","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}},{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"head":{"tags":["code"],"summary":"Code Http Proxy","description":"Proxya una request HTTP al VS Code web interno.","operationId":"code_http_proxy_instances__slug__code_proxy__path__put","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}},{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["code"],"summary":"Code Http Proxy","description":"Proxya una request HTTP al VS Code web interno.","operationId":"code_http_proxy_instances__slug__code_proxy__path__put","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}},{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"options":{"tags":["code"],"summary":"Code Http Proxy","description":"Proxya una request HTTP al VS Code web interno.","operationId":"code_http_proxy_instances__slug__code_proxy__path__put","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}},{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["code"],"summary":"Code Http Proxy","description":"Proxya una request HTTP al VS Code web interno.","operationId":"code_http_proxy_instances__slug__code_proxy__path__put","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}},{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["code"],"summary":"Code Http Proxy","description":"Proxya una request HTTP al VS Code web interno.","operationId":"code_http_proxy_instances__slug__code_proxy__path__put","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}},{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/grafana/{path}":{"put":{"tags":["infra"],"summary":"Grafana Http Proxy","description":"Proxya Grafana (cualquier usuario autenticado puede ver el monitoreo).","operationId":"grafana_http_proxy_grafana__path__put","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["infra"],"summary":"Grafana Http Proxy","description":"Proxya Grafana (cualquier usuario autenticado puede ver el monitoreo).","operationId":"grafana_http_proxy_grafana__path__put","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"head":{"tags":["infra"],"summary":"Grafana Http Proxy","description":"Proxya Grafana (cualquier usuario autenticado puede ver el monitoreo).","operationId":"grafana_http_proxy_grafana__path__put","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["infra"],"summary":"Grafana Http Proxy","description":"Proxya Grafana (cualquier usuario autenticado puede ver el monitoreo).","operationId":"grafana_http_proxy_grafana__path__put","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"options":{"tags":["infra"],"summary":"Grafana Http Proxy","description":"Proxya Grafana (cualquier usuario autenticado puede ver el monitoreo).","operationId":"grafana_http_proxy_grafana__path__put","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["infra"],"summary":"Grafana Http Proxy","description":"Proxya Grafana (cualquier usuario autenticado puede ver el monitoreo).","operationId":"grafana_http_proxy_grafana__path__put","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["infra"],"summary":"Grafana Http Proxy","description":"Proxya Grafana (cualquier usuario autenticado puede ver el monitoreo).","operationId":"grafana_http_proxy_grafana__path__put","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/mails/{path}":{"put":{"tags":["infra"],"summary":"Mailpit Http Proxy","description":"Proxya Mailpit (cualquier usuario autenticado puede ver los mails).","operationId":"mailpit_http_proxy_mails__path__put","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["infra"],"summary":"Mailpit Http Proxy","description":"Proxya Mailpit (cualquier usuario autenticado puede ver los mails).","operationId":"mailpit_http_proxy_mails__path__put","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"head":{"tags":["infra"],"summary":"Mailpit Http Proxy","description":"Proxya Mailpit (cualquier usuario autenticado puede ver los mails).","operationId":"mailpit_http_proxy_mails__path__put","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["infra"],"summary":"Mailpit Http Proxy","description":"Proxya Mailpit (cualquier usuario autenticado puede ver los mails).","operationId":"mailpit_http_proxy_mails__path__put","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"options":{"tags":["infra"],"summary":"Mailpit Http Proxy","description":"Proxya Mailpit (cualquier usuario autenticado puede ver los mails).","operationId":"mailpit_http_proxy_mails__path__put","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["infra"],"summary":"Mailpit Http Proxy","description":"Proxya Mailpit (cualquier usuario autenticado puede ver los mails).","operationId":"mailpit_http_proxy_mails__path__put","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["infra"],"summary":"Mailpit Http Proxy","description":"Proxya Mailpit (cualquier usuario autenticado puede ver los mails).","operationId":"mailpit_http_proxy_mails__path__put","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/pgadmin/{path}":{"put":{"tags":["infra"],"summary":"Pgadmin Http Proxy","description":"Proxya pgAdmin (solo roles de escritura: acceso crudo a las bases).\n\npgAdmin mantiene su sesión/CSRF por cookie, así que se reenvían las cookies\n(a diferencia de Grafana/Jupyter). Sirve bajo /pgadmin vía X-Script-Name.","operationId":"pgadmin_http_proxy_pgadmin__path__put","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["infra"],"summary":"Pgadmin Http Proxy","description":"Proxya pgAdmin (solo roles de escritura: acceso crudo a las bases).\n\npgAdmin mantiene su sesión/CSRF por cookie, así que se reenvían las cookies\n(a diferencia de Grafana/Jupyter). Sirve bajo /pgadmin vía X-Script-Name.","operationId":"pgadmin_http_proxy_pgadmin__path__put","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"head":{"tags":["infra"],"summary":"Pgadmin Http Proxy","description":"Proxya pgAdmin (solo roles de escritura: acceso crudo a las bases).\n\npgAdmin mantiene su sesión/CSRF por cookie, así que se reenvían las cookies\n(a diferencia de Grafana/Jupyter). Sirve bajo /pgadmin vía X-Script-Name.","operationId":"pgadmin_http_proxy_pgadmin__path__put","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["infra"],"summary":"Pgadmin Http Proxy","description":"Proxya pgAdmin (solo roles de escritura: acceso crudo a las bases).\n\npgAdmin mantiene su sesión/CSRF por cookie, así que se reenvían las cookies\n(a diferencia de Grafana/Jupyter). Sirve bajo /pgadmin vía X-Script-Name.","operationId":"pgadmin_http_proxy_pgadmin__path__put","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"options":{"tags":["infra"],"summary":"Pgadmin Http Proxy","description":"Proxya pgAdmin (solo roles de escritura: acceso crudo a las bases).\n\npgAdmin mantiene su sesión/CSRF por cookie, así que se reenvían las cookies\n(a diferencia de Grafana/Jupyter). Sirve bajo /pgadmin vía X-Script-Name.","operationId":"pgadmin_http_proxy_pgadmin__path__put","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["infra"],"summary":"Pgadmin Http Proxy","description":"Proxya pgAdmin (solo roles de escritura: acceso crudo a las bases).\n\npgAdmin mantiene su sesión/CSRF por cookie, así que se reenvían las cookies\n(a diferencia de Grafana/Jupyter). Sirve bajo /pgadmin vía X-Script-Name.","operationId":"pgadmin_http_proxy_pgadmin__path__put","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["infra"],"summary":"Pgadmin Http Proxy","description":"Proxya pgAdmin (solo roles de escritura: acceso crudo a las bases).\n\npgAdmin mantiene su sesión/CSRF por cookie, así que se reenvían las cookies\n(a diferencia de Grafana/Jupyter). Sirve bajo /pgadmin vía X-Script-Name.","operationId":"pgadmin_http_proxy_pgadmin__path__put","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/login":{"get":{"tags":["web"],"summary":"Login Form","operationId":"login_form_login_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}},"post":{"tags":["web"],"summary":"Login Submit","operationId":"login_submit_login_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_login_submit_login_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/google/login":{"get":{"tags":["web"],"summary":"Google Login","description":"Inicia el flujo OAuth: guarda el state y redirige a Google.","operationId":"google_login_auth_google_login_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/auth/google/callback":{"get":{"tags":["web"],"summary":"Google Callback","description":"Callback de Google: valida, restringe por dominio y abre sesión.\n\nUsuarios nuevos se crean con rol viewer (lector). Usuarios existentes\nconservan su rol; los inactivos quedan rechazados.","operationId":"google_callback_auth_google_callback_get","parameters":[{"name":"code","in":"query","required":false,"schema":{"type":"string","default":"","title":"Code"}},{"name":"state","in":"query","required":false,"schema":{"type":"string","default":"","title":"State"}},{"name":"error","in":"query","required":false,"schema":{"type":"string","default":"","title":"Error"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/logout":{"get":{"tags":["web"],"summary":"Logout","operationId":"logout_logout_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/":{"get":{"tags":["web"],"summary":"Home","description":"La vista principal es el listado de proyectos.","operationId":"home__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/projects":{"get":{"tags":["web"],"summary":"Projects List","operationId":"projects_list_projects_get","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","default":1,"title":"Page"}},{"name":"q","in":"query","required":false,"schema":{"type":"string","default":"","title":"Q"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["web"],"summary":"Projects Create","description":"Crea un proyecto. Solo pide el nombre; la config técnica (versión,\nedición, repo, módulos) se define en cada instancia.","operationId":"projects_create_projects_post","requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_projects_create_projects_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/projects/{slug}":{"get":{"tags":["web"],"summary":"Project Detail","operationId":"project_detail_projects__slug__get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/projects/{slug}/delete":{"post":{"tags":["web"],"summary":"Project Delete","description":"Elimina un proyecto y todas sus instancias (con sus stacks y builds).\n\nRequiere que ``confirm_name`` coincida con el nombre del proyecto.","operationId":"project_delete_projects__slug__delete_post","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_project_delete_projects__slug__delete_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/projects/{slug}/repo":{"post":{"tags":["web"],"summary":"Project Set Repo","description":"Configura el repositorio Git del proyecto (lo heredan sus instancias).","operationId":"project_set_repo_projects__slug__repo_post","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_project_set_repo_projects__slug__repo_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/projects/{slug}/repo/verify":{"post":{"tags":["web"],"summary":"Project Verify Repo","description":"Verifica el acceso al repo principal del proyecto (y sus submódulos) con sus claves SSH.","operationId":"project_verify_repo_projects__slug__repo_verify_post","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/projects/{slug}/ssh-keys/add":{"post":{"tags":["web"],"summary":"Project Add Ssh Key","description":"Adiciona al proyecto una clave del llavero (seleccionada de las disponibles).","operationId":"project_add_ssh_key_projects__slug__ssh_keys_add_post","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_project_add_ssh_key_projects__slug__ssh_keys_add_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/projects/{slug}/ssh-keys/{key_id}/remove":{"post":{"tags":["web"],"summary":"Project Remove Ssh Key","description":"Quita del proyecto una clave del conjunto (no la elimina del llavero).","operationId":"project_remove_ssh_key_projects__slug__ssh_keys__key_id__remove_post","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}},{"name":"key_id","in":"path","required":true,"schema":{"type":"integer","title":"Key Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/ssh-keys":{"get":{"tags":["web"],"summary":"Ssh Keys List","description":"Listado y gestión del conjunto compartido de claves SSH.","operationId":"ssh_keys_list_ssh_keys_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}},"post":{"tags":["web"],"summary":"Ssh Keys Create","description":"Crea una clave en el conjunto: pegando una privada existente o generando una nueva.","operationId":"ssh_keys_create_ssh_keys_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_ssh_keys_create_ssh_keys_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/ssh-keys/{key_id}/delete":{"post":{"tags":["web"],"summary":"Ssh Keys Delete","description":"Elimina una clave del conjunto. Los proyectos que la usaban quedan sin clave.","operationId":"ssh_keys_delete_ssh_keys__key_id__delete_post","parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"integer","title":"Key Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/instances":{"get":{"tags":["web"],"summary":"Instances List","operationId":"instances_list_instances_get","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","default":1,"title":"Page"}},{"name":"q","in":"query","required":false,"schema":{"type":"string","default":"","title":"Q"}},{"name":"stage","in":"query","required":false,"schema":{"type":"string","default":"","title":"Stage"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","default":"","title":"Status"}},{"name":"version","in":"query","required":false,"schema":{"type":"string","default":"","title":"Version"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["web"],"summary":"Instances Create","operationId":"instances_create_instances_post","requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_instances_create_instances_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/instances/purge":{"post":{"tags":["web"],"summary":"Instances Purge","description":"Purga (borra del todo) las instancias dadas de baja: registros + archivos.","operationId":"instances_purge_instances_purge_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/instances/new":{"get":{"tags":["web"],"summary":"Instance New","description":"Formulario de alta de una instancia.\n\nSoporta sembrar la base desde otra instancia (``clone_from``) o desde un\nbackup (``from_backup``); en esos casos precarga los datos de la fuente.","operationId":"instance_new_instances_new_get","parameters":[{"name":"project","in":"query","required":false,"schema":{"type":"string","default":"","title":"Project"}},{"name":"clone_from","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Clone From"}},{"name":"from_backup","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"From Backup"}},{"name":"error","in":"query","required":false,"schema":{"type":"string","default":"","title":"Error"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/instances/upload":{"get":{"tags":["web"],"summary":"Instance Upload Form","description":"Formulario para crear una instancia a partir de un backup externo subido.","operationId":"instance_upload_form_instances_upload_get","parameters":[{"name":"project","in":"query","required":false,"schema":{"type":"string","default":"","title":"Project"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["web"],"summary":"Instance Upload Create","description":"Crea una instancia sembrando la base desde el backup subido por el usuario.","operationId":"instance_upload_create_instances_upload_post","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_instance_upload_create_instances_upload_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/instances/{slug}":{"get":{"tags":["web"],"summary":"Instance Detail","operationId":"instance_detail_instances__slug__get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/builds/{build_id}/log":{"get":{"tags":["web"],"summary":"Build Log","description":"Muestra la salida de consola de un build puntual.","operationId":"build_log_builds__build_id__log_get","parameters":[{"name":"build_id","in":"path","required":true,"schema":{"type":"integer","title":"Build Id"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/builds/{build_id}/log.json":{"get":{"tags":["web"],"summary":"Build Log Json","description":"Devuelve el delta del log y el estado del build en JSON, para el tailing en vivo.\n\n``offset`` son los caracteres que el cliente ya recibió: devolvemos solo\n``log[offset:]`` más el nuevo offset, en vez de reenviar el log entero en\ncada poll de 2s (el log solo crece por append). Si el offset viene\ndesincronizado (mayor al largo actual, p. ej. tras un rebuild), reenviamos\ndesde el arranque.","operationId":"build_log_json_builds__build_id__log_json_get","parameters":[{"name":"build_id","in":"path","required":true,"schema":{"type":"integer","title":"Build Id"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/capacity":{"get":{"tags":["web"],"summary":"Admin Capacity","description":"Shell del capacity planning. Los datos los traen los endpoints /data (JS).","operationId":"admin_capacity_admin_capacity_get","parameters":[{"name":"message","in":"query","required":false,"schema":{"type":"string","default":"","title":"Message"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/capacity/data":{"get":{"tags":["web"],"summary":"Admin Capacity Data","description":"Datos del capacity en JSON. ``part=fast`` (sin Docker) o ``part=usage`` (Docker).","operationId":"admin_capacity_data_admin_capacity_data_get","parameters":[{"name":"part","in":"query","required":false,"schema":{"type":"string","default":"fast","title":"Part"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/capacity/prune":{"post":{"tags":["web"],"summary":"Admin Capacity Prune","description":"Libera disco de Docker (build cache + imágenes colgadas), en segundo plano.\n\nEl prune puede tardar; se dispara en segundo plano para no trabar el request.","operationId":"admin_capacity_prune_admin_capacity_prune_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/admin/builds":{"get":{"tags":["web"],"summary":"Admin Builds","description":"Panel admin: todos los builds del sistema, con estado en vivo y corte.","operationId":"admin_builds_admin_builds_get","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","default":1,"title":"Page"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","default":"","title":"Status"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/builds/rows":{"get":{"tags":["web"],"summary":"Admin Builds Rows","description":"Devuelve solo el ``<tbody>`` de la tabla, para el refresco en vivo.","operationId":"admin_builds_rows_admin_builds_rows_get","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","default":1,"title":"Page"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","default":"","title":"Status"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/builds/{build_id}/cancel":{"post":{"tags":["web"],"summary":"Admin Build Cancel","description":"Cancela (corte cooperativo) un build en cola o en ejecución.","operationId":"admin_build_cancel_admin_builds__build_id__cancel_post","parameters":[{"name":"build_id","in":"path","required":true,"schema":{"type":"integer","title":"Build Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/instances/{slug}/backup":{"post":{"tags":["web"],"summary":"Backup Create","description":"Genera un backup (pg_dump, opcionalmente con filestore) de la instancia.\n\nEl pg_dump de una base grande tarda minutos: se corre en segundo plano para\nno trabar el request. El backup aparece en la lista al terminar (la página\npollea) y queda registrado en la actividad.","operationId":"backup_create_instances__slug__backup_post","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_backup_create_instances__slug__backup_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/instances/{instance_id}/backup-schedule":{"post":{"tags":["web"],"summary":"Backup Set Schedule","description":"Configura el backup programado de la instancia.","operationId":"backup_set_schedule_instances__instance_id__backup_schedule_post","parameters":[{"name":"instance_id","in":"path","required":true,"schema":{"type":"integer","title":"Instance Id"}}],"requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_backup_set_schedule_instances__instance_id__backup_schedule_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/instances/{slug}/odoo-conf":{"post":{"tags":["web"],"summary":"Instance Set Odoo Conf","description":"Guarda el odoo.conf editable de la instancia (aplica en el próximo rebuild).\n\nSi ``generate`` viene seteado, ignora el textarea y genera el conf por\ndefecto con los valores del cluster compartido. Si viene ``reset``, descarta\nel conf y la instancia vuelve al modo flags inline.","operationId":"instance_set_odoo_conf_instances__slug__odoo_conf_post","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_instance_set_odoo_conf_instances__slug__odoo_conf_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/instances/{slug}/requirements":{"post":{"tags":["web"],"summary":"Instance Set Requirements","description":"Guarda el requirements.txt extra de la instancia (aplica en el próximo rebuild).","operationId":"instance_set_requirements_instances__slug__requirements_post","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_instance_set_requirements_instances__slug__requirements_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/instances/{slug}/resources":{"post":{"tags":["web"],"summary":"Instance Set Resources","description":"Actualiza los recursos (workers/memoria/disco) de la instancia.\n\nLa memoria y el CPU aplican al recrear el contenedor (próximo rebuild); el\ndisco es una reserva contable que el capacity planning considera enseguida.","operationId":"instance_set_resources_instances__slug__resources_post","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_instance_set_resources_instances__slug__resources_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/instances/{slug}/auto-sleep":{"post":{"tags":["web"],"summary":"Instance Set Auto Sleep","description":"Activa/desactiva el reposo por inactividad y su timeout (minutos).","operationId":"instance_set_auto_sleep_instances__slug__auto_sleep_post","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_instance_set_auto_sleep_instances__slug__auto_sleep_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/backups/{backup_id}/restore":{"post":{"tags":["web"],"summary":"Backup Restore","description":"Restaura un backup en la MISMA instancia (destructivo).\n\nEl restore corre en el worker (no inline en el request): un backup grande\ntarda minutos y bloquearía la respuesta. Se encola y se responde al toque;\nel progreso se ve en vivo en la página de la instancia.","operationId":"backup_restore_backups__backup_id__restore_post","parameters":[{"name":"backup_id","in":"path","required":true,"schema":{"type":"integer","title":"Backup Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/backups/{backup_id}/download":{"get":{"tags":["web"],"summary":"Backup Download","description":"Descarga el archivo del backup.","operationId":"backup_download_backups__backup_id__download_get","parameters":[{"name":"backup_id","in":"path","required":true,"schema":{"type":"integer","title":"Backup Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/backups/{backup_id}/delete":{"post":{"tags":["web"],"summary":"Backup Delete","description":"Borra un backup (archivo + registro).","operationId":"backup_delete_backups__backup_id__delete_post","parameters":[{"name":"backup_id","in":"path","required":true,"schema":{"type":"integer","title":"Backup Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/instances/{slug}/editor":{"get":{"tags":["web"],"summary":"Instance Editor","description":"Levanta el editor (JupyterLab) de la instancia y muestra el acceso.","operationId":"instance_editor_instances__slug__editor_get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/instances/{slug}/code":{"get":{"tags":["web"],"summary":"Instance Code","description":"Levanta el VS Code web (con Claude Code) de la instancia y muestra el acceso.","operationId":"instance_code_instances__slug__code_get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/instances/{slug}/connect":{"get":{"tags":["web"],"summary":"Connect Page","description":"Página para elegir con qué usuario conectarse a la instancia.","operationId":"connect_page_instances__slug__connect_get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["web"],"summary":"Connect Submit","description":"Mintea la sesión y redirige al landing en el ORIGEN de la instancia.\n\nLa cookie NO se setea acá (origen del panel): setearla con ``Domain`` base la\nhacía COMPARTIDA entre todas las instancias (un subdominio pisaba la sesión de\notro → «me pide login»). En su lugar redirige a ``/_bo/connect`` en el origen\nde la instancia, que setea la cookie HOST-ONLY (propia de ese subdominio).","operationId":"connect_submit_instances__slug__connect_post","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_connect_submit_instances__slug__connect_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/_bo/connect":{"get":{"tags":["web"],"summary":"Connect Landing","description":"Landing del \"Conectar\", servido en el ORIGEN de la instancia (vía Traefik).\n\nEs PÚBLICO (sin auth de panel: el token de un solo uso es la credencial). Canjea\nel token por el sid minteado y setea ``session_id`` HOST-ONLY (sin ``Domain``):\nasí la sesión es propia de ESTE subdominio, no se comparte entre instancias, y\npisa cualquier cookie vieja del subdominio. Después redirige a ``/web``.","operationId":"connect_landing__bo_connect_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/instances/{instance_id}/action":{"post":{"tags":["web"],"summary":"Instance Action","operationId":"instance_action_instances__instance_id__action_post","parameters":[{"name":"instance_id","in":"path","required":true,"schema":{"type":"integer","title":"Instance Id"}}],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_instance_action_instances__instance_id__action_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/instances/{instance_id}/resync":{"post":{"tags":["web"],"summary":"Instance Resync","description":"Reconcilia el estado de la instancia con el contenedor real.","operationId":"instance_resync_instances__instance_id__resync_post","parameters":[{"name":"instance_id","in":"path","required":true,"schema":{"type":"integer","title":"Instance Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/instances/{slug}/stats":{"get":{"tags":["web"],"summary":"Instance Stats","description":"Uso de recursos del contenedor (para refresco por AJAX).\n\nSirve del cache de ``metrics`` (que un hilo refresca cada ~15s) en vez de\ndisparar ``docker stats`` en vivo: esa llamada bloqueante tardaba ~2s dentro\ndel ``async def`` y congelaba TODO el panel en cada poll. Si el slug todavía\nno está en el cache (instancia recién arrancada), devolvemos un payload vacío\ny el template muestra \"—\" sin romper el JS.","operationId":"instance_stats_instances__slug__stats_get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/instances/{slug}/status.json":{"get":{"tags":["web"],"summary":"Instance Status Json","description":"Estado de la instancia (para refresco en vivo del detalle mientras aprovisiona).","operationId":"instance_status_json_instances__slug__status_json_get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/instances/{slug}/monitor":{"get":{"tags":["web"],"summary":"Instance Monitor","description":"Tab de monitoreo: Grafana embebido, filtrado por la instancia.","operationId":"instance_monitor_instances__slug__monitor_get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/instances/{instance_id}/delete":{"post":{"tags":["web"],"summary":"Instance Delete","description":"Elimina una instancia: baja su stack y borra el registro y sus builds.\n\nRequiere que ``confirm_name`` coincida exactamente con el nombre de la\ninstancia (confirmación tipo \"escribir el nombre para borrar\").","operationId":"instance_delete_instances__instance_id__delete_post","parameters":[{"name":"instance_id","in":"path","required":true,"schema":{"type":"integer","title":"Instance Id"}}],"requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_instance_delete_instances__instance_id__delete_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/activity":{"get":{"tags":["web"],"summary":"Activity List","operationId":"activity_list_activity_get","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","default":1,"title":"Page"}},{"name":"instance","in":"query","required":false,"schema":{"type":"string","title":"Instance"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/account":{"get":{"tags":["web"],"summary":"Account","operationId":"account_admin_account_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/admin/account/password":{"post":{"tags":["web"],"summary":"Change Password","operationId":"change_password_admin_account_password_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_change_password_admin_account_password_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/users/{user_id}/avatar":{"get":{"tags":["web"],"summary":"User Avatar","description":"Sirve la foto de avatar de un usuario desde el volumen (autenticada).","operationId":"user_avatar_users__user_id__avatar_get","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"}}}}}}},"/admin/account/avatar":{"post":{"tags":["web"],"summary":"Account Avatar Upload","operationId":"account_avatar_upload_admin_account_avatar_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_account_avatar_upload_admin_account_avatar_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/account/avatar/delete":{"post":{"tags":["web"],"summary":"Account Avatar Delete","operationId":"account_avatar_delete_admin_account_avatar_delete_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/admin/users/{user_id}/avatar":{"post":{"tags":["web"],"summary":"Admin Avatar Upload","operationId":"admin_avatar_upload_admin_users__user_id__avatar_post","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","title":"User Id"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_admin_avatar_upload_admin_users__user_id__avatar_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/users/{user_id}/avatar/delete":{"post":{"tags":["web"],"summary":"Admin Avatar Delete","operationId":"admin_avatar_delete_admin_users__user_id__avatar_delete_post","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"}}}}}}},"/admin/users":{"get":{"tags":["web"],"summary":"Users List","operationId":"users_list_admin_users_get","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","default":1,"title":"Page"}},{"name":"q","in":"query","required":false,"schema":{"type":"string","default":"","title":"Q"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["web"],"summary":"Users Create","operationId":"users_create_admin_users_post","requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_users_create_admin_users_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/users/{user_id}/role":{"post":{"tags":["web"],"summary":"Users Set Role","operationId":"users_set_role_admin_users__user_id__role_post","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","title":"User Id"}}],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_users_set_role_admin_users__user_id__role_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/users/{user_id}/active":{"post":{"tags":["web"],"summary":"Users Set Active","description":"Activa o desactiva un usuario. Desactivar invalida sus sesiones activas.","operationId":"users_set_active_admin_users__user_id__active_post","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","title":"User Id"}}],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_users_set_active_admin_users__user_id__active_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/users/{user_id}/delete":{"post":{"tags":["web"],"summary":"Users Delete","description":"Elimina definitivamente un usuario.","operationId":"users_delete_admin_users__user_id__delete_post","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"}}}}}}},"/admin/settings":{"get":{"tags":["web"],"summary":"Settings View","operationId":"settings_view_admin_settings_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/admin/settings/editor-image":{"post":{"tags":["web"],"summary":"Settings Rebuild Editor Image","description":"Reconstruye (forzado, en segundo plano) la imagen del editor de una\nversión/edición. Acción global: la imagen es compartida por todas las\ninstancias de esa combinación. Solo se permiten combinaciones en uso.","operationId":"settings_rebuild_editor_image_admin_settings_editor_image_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_settings_rebuild_editor_image_admin_settings_editor_image_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/settings/rebuild-base-image":{"post":{"tags":["web"],"summary":"Settings Rebuild Base Image","description":"Reconstruye (forzado, en segundo plano) la imagen base ``bo-odoo:<ver>``:\nrefresca Community y hornea el Enterprise (al tip o al commit dado). Solo\nversiones en uso. No recrea instancias.","operationId":"settings_rebuild_base_image_admin_settings_rebuild_base_image_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_settings_rebuild_base_image_admin_settings_rebuild_base_image_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/settings/google":{"post":{"tags":["web"],"summary":"Settings Save Google","description":"Guarda la config de login con Google (el secret solo si viene uno nuevo).","operationId":"settings_save_google_admin_settings_google_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_settings_save_google_admin_settings_google_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/settings/enterprise":{"post":{"tags":["web"],"summary":"Settings Save Enterprise","operationId":"settings_save_enterprise_admin_settings_enterprise_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_settings_save_enterprise_admin_settings_enterprise_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/settings/enterprise/test":{"post":{"tags":["web"],"summary":"Settings Test Enterprise","description":"Prueba el acceso (``git ls-remote``) a la fuente Enterprise configurada.","operationId":"settings_test_enterprise_admin_settings_enterprise_test_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/admin/settings/migration-scripts":{"post":{"tags":["web"],"summary":"Settings Save Migration Scripts","description":"Guarda el repo de scripts de migración (repo + rama + deploy key).","operationId":"settings_save_migration_scripts_admin_settings_migration_scripts_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_settings_save_migration_scripts_admin_settings_migration_scripts_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/settings/migration-scripts/test":{"post":{"tags":["web"],"summary":"Settings Test Migration Scripts","description":"Prueba el acceso (``git ls-remote``) al repo de scripts configurado.","operationId":"settings_test_migration_scripts_admin_settings_migration_scripts_test_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/admin/settings/migration-scripts/sync":{"post":{"tags":["web"],"summary":"Settings Sync Migration Scripts","description":"Ejecuta el pull del repo de scripts al bind-mount del host y guarda el estado.\n\n``next``: adónde volver tras el sync. Allowlist cerrada (defensa contra open\nredirect): solo el listado de recetas; cualquier otro valor cae al default\n(la página de configuración, comportamiento histórico).","operationId":"settings_sync_migration_scripts_admin_settings_migration_scripts_sync_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_settings_sync_migration_scripts_admin_settings_migration_scripts_sync_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/settings/alerts":{"post":{"tags":["web"],"summary":"Settings Save Alert Smtp","description":"Guarda el SMTP de alertas (a nivel app). El password solo si viene uno nuevo.","operationId":"settings_save_alert_smtp_admin_settings_alerts_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_settings_save_alert_smtp_admin_settings_alerts_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/settings/alerts/test":{"post":{"tags":["web"],"summary":"Settings Test Alert Smtp","description":"Manda un mail de prueba con el SMTP de alertas al email del admin actual.","operationId":"settings_test_alert_smtp_admin_settings_alerts_test_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/admin/settings/tuning":{"post":{"tags":["web"],"summary":"Settings Apply Tuning","description":"Aplica la reparametrización recomendada según las dimensiones del server.\n\nEn caliente: válvula de PgBouncer + reservas de capacity. Lo que requiere\nrecrear el cluster (max_connections) queda indicado en el panel.","operationId":"settings_apply_tuning_admin_settings_tuning_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api":{"get":{"tags":["web"],"summary":"Api Docs","operationId":"api_docs_api_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}}},"components":{"schemas":{"Body_account_avatar_upload_admin_account_avatar_post":{"properties":{"avatar":{"type":"string","contentMediaType":"application/octet-stream","title":"Avatar"}},"type":"object","required":["avatar"],"title":"Body_account_avatar_upload_admin_account_avatar_post"},"Body_admin_avatar_upload_admin_users__user_id__avatar_post":{"properties":{"avatar":{"type":"string","contentMediaType":"application/octet-stream","title":"Avatar"}},"type":"object","required":["avatar"],"title":"Body_admin_avatar_upload_admin_users__user_id__avatar_post"},"Body_backup_create_instances__slug__backup_post":{"properties":{"filestore":{"type":"string","title":"Filestore","default":""}},"type":"object","title":"Body_backup_create_instances__slug__backup_post"},"Body_backup_set_schedule_instances__instance_id__backup_schedule_post":{"properties":{"schedule":{"type":"string","title":"Schedule","default":"off"},"retention":{"type":"integer","title":"Retention","default":7},"hour":{"type":"integer","title":"Hour","default":3}},"type":"object","title":"Body_backup_set_schedule_instances__instance_id__backup_schedule_post"},"Body_change_password_admin_account_password_post":{"properties":{"current_password":{"type":"string","title":"Current Password"},"new_password":{"type":"string","title":"New Password"},"confirm_password":{"type":"string","title":"Confirm Password"}},"type":"object","required":["current_password","new_password","confirm_password"],"title":"Body_change_password_admin_account_password_post"},"Body_connect_submit_instances__slug__connect_post":{"properties":{"uid":{"type":"integer","title":"Uid"}},"type":"object","required":["uid"],"title":"Body_connect_submit_instances__slug__connect_post"},"Body_instance_action_instances__instance_id__action_post":{"properties":{"action":{"type":"string","title":"Action"}},"type":"object","required":["action"],"title":"Body_instance_action_instances__instance_id__action_post"},"Body_instance_delete_instances__instance_id__delete_post":{"properties":{"confirm_name":{"type":"string","title":"Confirm Name","default":""}},"type":"object","title":"Body_instance_delete_instances__instance_id__delete_post"},"Body_instance_set_auto_sleep_instances__slug__auto_sleep_post":{"properties":{"auto_sleep":{"type":"boolean","title":"Auto Sleep","default":false},"auto_sleep_idle_minutes":{"type":"integer","title":"Auto Sleep Idle Minutes","default":30}},"type":"object","title":"Body_instance_set_auto_sleep_instances__slug__auto_sleep_post"},"Body_instance_set_odoo_conf_instances__slug__odoo_conf_post":{"properties":{"odoo_conf":{"type":"string","title":"Odoo Conf","default":""},"generate":{"type":"string","title":"Generate","default":""},"reset":{"type":"string","title":"Reset","default":""}},"type":"object","title":"Body_instance_set_odoo_conf_instances__slug__odoo_conf_post"},"Body_instance_set_requirements_instances__slug__requirements_post":{"properties":{"extra_requirements":{"type":"string","title":"Extra Requirements","default":""}},"type":"object","title":"Body_instance_set_requirements_instances__slug__requirements_post"},"Body_instance_set_resources_instances__slug__resources_post":{"properties":{"cpu_workers":{"type":"integer","title":"Cpu Workers","default":2},"mem_limit_mb":{"type":"integer","title":"Mem Limit Mb","default":2048},"disk_limit_gb":{"type":"integer","title":"Disk Limit Gb","default":10}},"type":"object","title":"Body_instance_set_resources_instances__slug__resources_post"},"Body_instance_upload_create_instances_upload_post":{"properties":{"project_id":{"type":"integer","title":"Project Id"},"name":{"type":"string","title":"Name"},"stage":{"type":"string","title":"Stage","default":"staging"},"odoo_version":{"type":"string","title":"Odoo Version","default":""},"edition":{"type":"string","title":"Edition","default":""},"modules":{"type":"string","title":"Modules","default":""},"branch":{"type":"string","title":"Branch","default":""},"neutralize":{"type":"string","title":"Neutralize","default":""},"mailcatcher":{"type":"string","title":"Mailcatcher","default":""},"backup_file":{"type":"string","contentMediaType":"application/octet-stream","title":"Backup File"}},"type":"object","required":["project_id","name","backup_file"],"title":"Body_instance_upload_create_instances_upload_post"},"Body_instances_create_instances_post":{"properties":{"project_id":{"type":"integer","title":"Project Id"},"name":{"type":"string","title":"Name"},"stage":{"type":"string","title":"Stage","default":"development"},"odoo_version":{"type":"string","title":"Odoo Version","default":""},"edition":{"type":"string","title":"Edition","default":""},"modules":{"type":"string","title":"Modules","default":""},"branch":{"type":"string","title":"Branch","default":""},"clone_from":{"type":"integer","title":"Clone From","default":0},"from_backup":{"type":"integer","title":"From Backup","default":0},"neutralize":{"type":"string","title":"Neutralize","default":""},"clone_filestore":{"type":"string","title":"Clone Filestore","default":""},"mailcatcher":{"type":"string","title":"Mailcatcher","default":""},"with_demo":{"type":"string","title":"With Demo","default":""},"cpu_workers":{"type":"integer","title":"Cpu Workers","default":2},"mem_limit_mb":{"type":"integer","title":"Mem Limit Mb","default":2048},"disk_limit_gb":{"type":"integer","title":"Disk Limit Gb","default":10},"auto_sleep":{"type":"boolean","title":"Auto Sleep","default":false},"auto_sleep_idle_minutes":{"type":"integer","title":"Auto Sleep Idle Minutes","default":30}},"type":"object","required":["project_id","name"],"title":"Body_instances_create_instances_post"},"Body_login_submit_login_post":{"properties":{"email":{"type":"string","title":"Email"},"password":{"type":"string","title":"Password"}},"type":"object","required":["email","password"],"title":"Body_login_submit_login_post"},"Body_migration_create_migrations_new_post":{"properties":{"name":{"type":"string","title":"Name"},"source_version":{"type":"string","title":"Source Version"},"target_version":{"type":"string","title":"Target Version","default":"19.0"},"flavor":{"type":"string","title":"Flavor","default":"ARG"},"edition":{"type":"string","title":"Edition","default":"enterprise"},"engine":{"type":"string","title":"Engine","default":"odoo_platform"},"purpose":{"type":"string","title":"Purpose","default":"test"},"contract":{"type":"string","title":"Contract","default":""},"reset_custom_views":{"type":"string","title":"Reset Custom Views","default":""},"input_type":{"type":"string","title":"Input Type","default":"upload"},"source_url":{"type":"string","title":"Source Url","default":""},"source_db_name":{"type":"string","title":"Source Db Name","default":""},"source_master_pwd":{"type":"string","title":"Source Master Pwd","default":""},"notify_emails":{"type":"string","title":"Notify Emails","default":""},"addons_repo":{"type":"string","title":"Addons Repo","default":""},"addons_branch_source":{"type":"string","title":"Addons Branch Source","default":""},"addons_branch_target":{"type":"string","title":"Addons Branch Target","default":""},"addons_ssh_key_id":{"type":"string","title":"Addons Ssh Key Id","default":""},"dump_file":{"type":"string","contentMediaType":"application/octet-stream","title":"Dump File"}},"type":"object","required":["name","source_version"],"title":"Body_migration_create_migrations_new_post"},"Body_migration_delete_migrations__slug__delete_post":{"properties":{"confirm_name":{"type":"string","title":"Confirm Name","default":""}},"type":"object","title":"Body_migration_delete_migrations__slug__delete_post"},"Body_migration_edit_migrations__slug__edit_post":{"properties":{"source_version":{"type":"string","title":"Source Version"},"target_version":{"type":"string","title":"Target Version"},"flavor":{"type":"string","title":"Flavor"},"engine":{"type":"string","title":"Engine"},"purpose":{"type":"string","title":"Purpose"},"contract":{"type":"string","title":"Contract","default":""},"notify_emails":{"type":"string","title":"Notify Emails","default":""},"addons_repo":{"type":"string","title":"Addons Repo","default":""},"addons_branch_source":{"type":"string","title":"Addons Branch Source","default":""},"addons_branch_target":{"type":"string","title":"Addons Branch Target","default":""},"addons_ssh_key_id":{"type":"string","title":"Addons Ssh Key Id","default":""}},"type":"object","title":"Body_migration_edit_migrations__slug__edit_post"},"Body_migration_resync_apply_migrations__slug__resync_post":{"properties":{"action":{"type":"string","title":"Action"}},"type":"object","required":["action"],"title":"Body_migration_resync_apply_migrations__slug__resync_post"},"Body_project_add_ssh_key_projects__slug__ssh_keys_add_post":{"properties":{"ssh_key_id":{"type":"string","title":"Ssh Key Id","default":""}},"type":"object","title":"Body_project_add_ssh_key_projects__slug__ssh_keys_add_post"},"Body_project_delete_projects__slug__delete_post":{"properties":{"confirm_name":{"type":"string","title":"Confirm Name","default":""}},"type":"object","title":"Body_project_delete_projects__slug__delete_post"},"Body_project_set_repo_projects__slug__repo_post":{"properties":{"git_repo":{"type":"string","title":"Git Repo","default":""}},"type":"object","title":"Body_project_set_repo_projects__slug__repo_post"},"Body_projects_create_projects_post":{"properties":{"name":{"type":"string","title":"Name"}},"type":"object","required":["name"],"title":"Body_projects_create_projects_post"},"Body_recipe_save_admin_recipes_save_post":{"properties":{"action":{"type":"string","title":"Action"},"text":{"type":"string","title":"Text"},"key":{"type":"string","title":"Key","default":""},"flavor":{"type":"string","title":"Flavor","default":""},"stem":{"type":"string","title":"Stem","default":""}},"type":"object","required":["action","text"],"title":"Body_recipe_save_admin_recipes_save_post"},"Body_run_resume_migrations__slug__runs__number__resume_post":{"properties":{"step_id":{"type":"string","title":"Step Id"}},"type":"object","required":["step_id"],"title":"Body_run_resume_migrations__slug__runs__number__resume_post"},"Body_settings_rebuild_base_image_admin_settings_rebuild_base_image_post":{"properties":{"version":{"type":"string","title":"Version","default":""},"enterprise_ref":{"type":"string","title":"Enterprise Ref","default":""}},"type":"object","title":"Body_settings_rebuild_base_image_admin_settings_rebuild_base_image_post"},"Body_settings_rebuild_editor_image_admin_settings_editor_image_post":{"properties":{"version":{"type":"string","title":"Version","default":""},"edition":{"type":"string","title":"Edition","default":""}},"type":"object","title":"Body_settings_rebuild_editor_image_admin_settings_editor_image_post"},"Body_settings_save_alert_smtp_admin_settings_alerts_post":{"properties":{"host":{"type":"string","title":"Host","default":""},"port":{"type":"string","title":"Port","default":"587"},"smtp_user":{"type":"string","title":"Smtp User","default":""},"smtp_password":{"type":"string","title":"Smtp Password","default":""},"smtp_from":{"type":"string","title":"Smtp From","default":""},"tls":{"type":"string","title":"Tls","default":""}},"type":"object","title":"Body_settings_save_alert_smtp_admin_settings_alerts_post"},"Body_settings_save_enterprise_admin_settings_enterprise_post":{"properties":{"repo":{"type":"string","title":"Repo","default":""},"ssh_key":{"type":"string","title":"Ssh Key","default":""}},"type":"object","title":"Body_settings_save_enterprise_admin_settings_enterprise_post"},"Body_settings_save_google_admin_settings_google_post":{"properties":{"client_id":{"type":"string","title":"Client Id","default":""},"client_secret":{"type":"string","title":"Client Secret","default":""},"allowed_domains":{"type":"string","title":"Allowed Domains","default":""}},"type":"object","title":"Body_settings_save_google_admin_settings_google_post"},"Body_settings_save_migration_scripts_admin_settings_migration_scripts_post":{"properties":{"repo":{"type":"string","title":"Repo","default":""},"branch":{"type":"string","title":"Branch","default":""},"ssh_key":{"type":"string","title":"Ssh Key","default":""}},"type":"object","title":"Body_settings_save_migration_scripts_admin_settings_migration_scripts_post"},"Body_settings_sync_migration_scripts_admin_settings_migration_scripts_sync_post":{"properties":{"next":{"type":"string","title":"Next","default":""}},"type":"object","title":"Body_settings_sync_migration_scripts_admin_settings_migration_scripts_sync_post"},"Body_ssh_keys_create_ssh_keys_post":{"properties":{"name":{"type":"string","title":"Name"},"source":{"type":"string","title":"Source","default":"paste"},"private_key":{"type":"string","title":"Private Key","default":""},"host":{"type":"string","title":"Host","default":""},"repo_url":{"type":"string","title":"Repo Url","default":""},"writable":{"type":"string","title":"Writable","default":""}},"type":"object","required":["name"],"title":"Body_ssh_keys_create_ssh_keys_post"},"Body_users_create_admin_users_post":{"properties":{"email":{"type":"string","title":"Email"},"password":{"type":"string","title":"Password"},"role":{"type":"string","title":"Role","default":"developer"}},"type":"object","required":["email","password"],"title":"Body_users_create_admin_users_post"},"Body_users_set_active_admin_users__user_id__active_post":{"properties":{"active":{"type":"string","title":"Active"}},"type":"object","required":["active"],"title":"Body_users_set_active_admin_users__user_id__active_post"},"Body_users_set_role_admin_users__user_id__role_post":{"properties":{"role":{"type":"string","title":"Role"}},"type":"object","required":["role"],"title":"Body_users_set_role_admin_users__user_id__role_post"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"InstanceAction":{"properties":{"action":{"type":"string","title":"Action","description":"start | restart | stop | rebuild | destroy."}},"type":"object","required":["action"],"title":"InstanceAction","description":"Cuerpo para ejecutar una acción sobre una instancia."},"InstanceCreate":{"properties":{"name":{"type":"string","maxLength":63,"minLength":2,"title":"Name","description":"Nombre de la instancia."},"project":{"type":"string","maxLength":63,"minLength":2,"title":"Project","description":"Nombre del proyecto/cliente."},"stage":{"type":"string","title":"Stage","description":"development | staging | production.","default":"development"},"odoo_version":{"type":"string","title":"Odoo Version","description":"Versión de Odoo.","default":"19.0"},"edition":{"type":"string","title":"Edition","description":"enterprise | community.","default":"enterprise"},"modules":{"items":{"type":"string"},"type":"array","title":"Modules","description":"Módulos a instalar al crear la base."},"git_repo":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Git Repo","description":"URL del repositorio de addons custom."},"branch":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Branch","description":"Rama del repositorio a desplegar."}},"type":"object","required":["name","project"],"title":"InstanceCreate","description":"Cuerpo para aprovisionar una nueva instancia vía API."},"InstanceOut":{"properties":{"id":{"type":"integer","title":"Id"},"name":{"type":"string","title":"Name"},"slug":{"type":"string","title":"Slug"},"project":{"type":"string","title":"Project"},"stage":{"type":"string","title":"Stage"},"status":{"type":"string","title":"Status"},"odoo_version":{"type":"string","title":"Odoo Version"},"edition":{"type":"string","title":"Edition"},"subdomain":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subdomain"},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url"},"db_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Db Name"},"host_port":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Host Port"},"modules":{"items":{"type":"string"},"type":"array","title":"Modules"},"git_repo":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Git Repo"},"branch":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Branch"},"auto_sleep":{"type":"boolean","title":"Auto Sleep","default":false},"auto_sleep_idle_minutes":{"type":"integer","title":"Auto Sleep Idle Minutes","default":30},"created_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By"},"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","slug","project","stage","status","odoo_version","edition","subdomain","url","db_name","host_port","modules","git_repo","branch","created_by","created_at","updated_at"],"title":"InstanceOut","description":"Representación de una instancia devuelta por la API."},"MigrationCreate":{"properties":{"name":{"type":"string","title":"Name"},"source_version":{"type":"string","title":"Source Version"},"target_version":{"type":"string","title":"Target Version","default":"19.0"},"flavor":{"type":"string","title":"Flavor","default":"ARG"},"edition":{"type":"string","title":"Edition","default":"enterprise"},"engine":{"type":"string","title":"Engine","default":"odoo_platform"},"purpose":{"type":"string","title":"Purpose","default":"test"},"contract":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Contract"},"input_type":{"type":"string","title":"Input Type","default":"upload"},"source_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Url"},"source_master_pwd":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Master Pwd"},"source_db_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Db Name"},"recipe_key":{"anyOf":[{"type":"string","pattern":"^[A-Za-z0-9_]+/[A-Za-z0-9_]+$"},{"type":"null"}],"title":"Recipe Key"},"notify_emails":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notify Emails"}},"type":"object","required":["name","source_version"],"title":"MigrationCreate","description":"Alta de una migración vía API."},"MigrationOut":{"properties":{"id":{"type":"integer","title":"Id"},"slug":{"type":"string","title":"Slug"},"name":{"type":"string","title":"Name"},"source_version":{"type":"string","title":"Source Version"},"target_version":{"type":"string","title":"Target Version"},"flavor":{"type":"string","title":"Flavor"},"engine":{"type":"string","title":"Engine"},"status":{"type":"string","title":"Status"},"test_instance_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Test Instance Url"}},"type":"object","required":["id","slug","name","source_version","target_version","flavor","engine","status"],"title":"MigrationOut"},"RunOut":{"properties":{"id":{"type":"integer","title":"Id"},"number":{"type":"integer","title":"Number"},"status":{"type":"string","title":"Status"},"engine":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Engine"},"checkpoint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Checkpoint"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"},"warnings":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}],"title":"Warnings"},"steps":{"items":{"$ref":"#/components/schemas/StepOut"},"type":"array","title":"Steps","default":[]}},"type":"object","required":["id","number","status"],"title":"RunOut"},"StepOut":{"properties":{"id":{"type":"integer","title":"Id"},"seq":{"type":"integer","title":"Seq"},"step_id":{"type":"string","title":"Step Id"},"step_type":{"type":"string","title":"Step Type"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"status":{"type":"string","title":"Status"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"}},"type":"object","required":["id","seq","step_id","step_type","status"],"title":"StepOut"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}},"securitySchemes":{"HTTPBasic":{"type":"http","scheme":"basic"}}}}