From 02a5ac07ed29ce1cca51b30853b4b90ed7636e47 Mon Sep 17 00:00:00 2001 From: Galindo97 Date: Fri, 29 May 2026 13:27:55 -0500 Subject: [PATCH] fix(invites): logging detallado cuando Hub invite creation falla MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Antes los fallos del Hub login y invite creation eran silenciosos o con warning genérico. Ahora loguea status code, body y nombre de campo para facilitar diagnóstico en producción. - Detecta HUB_ADMIN_EMAIL/PASSWORD vacíos con error explícito - Loguea status+body cuando login falla (401/403) - Loguea status+body+tenant/email cuando invite falla (404/403) Co-Authored-By: Claude Sonnet 4.6 --- .../api/v1/modules/core/invites/service.py | 59 +++++++++++++------ 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/backend/api/v1/modules/core/invites/service.py b/backend/api/v1/modules/core/invites/service.py index 447ad72d..04c6fd1a 100644 --- a/backend/api/v1/modules/core/invites/service.py +++ b/backend/api/v1/modules/core/invites/service.py @@ -78,25 +78,48 @@ class InviteService: # Crear invite en el Hub para que el usuario use el form del workspace hub_invite_token: Optional[str] = None invite_url: str = "" - try: - async with httpx.AsyncClient(timeout=10.0) as client: - login_resp = await client.post( - f"{settings.HUB_URL}api/v1/auth/login", - json={"username": settings.HUB_ADMIN_EMAIL, "password": settings.HUB_ADMIN_PASSWORD}, - ) - if login_resp.status_code == 200: - svc_token = login_resp.json().get("access_token", "") - hub_resp = await client.post( - f"{settings.HUB_URL}api/v1/hub/invites", - json={"email": str(data.email), "tenant_slug": tenant_slug}, - headers={"Authorization": f"Bearer {svc_token}"}, + if not settings.HUB_ADMIN_EMAIL or not settings.HUB_ADMIN_PASSWORD: + logger.error( + "[invite] HUB_ADMIN_EMAIL o HUB_ADMIN_PASSWORD no configurados — " + "el invite NO se creará en el Hub y se usará el fallback local. " + "Configura HUB_ADMIN_EMAIL y HUB_ADMIN_PASSWORD en .env" + ) + else: + try: + async with httpx.AsyncClient(timeout=10.0) as client: + login_resp = await client.post( + f"{settings.HUB_URL}api/v1/auth/login", + json={"username": settings.HUB_ADMIN_EMAIL, "password": settings.HUB_ADMIN_PASSWORD}, ) - if hub_resp.status_code in (200, 201): - hub_data = hub_resp.json() - hub_invite_token = hub_data.get("invite_token") or _extract_token_from_url(hub_data.get("invite_url", "")) - invite_url = hub_data.get("invite_url", "") - except Exception as exc: - logger.warning("Hub invite creation failed (non-blocking): %s", exc) + if login_resp.status_code != 200: + logger.error( + "[invite] Hub login falló: status=%s body=%s — " + "verifica HUB_ADMIN_EMAIL=%s y HUB_ADMIN_PASSWORD en .env", + login_resp.status_code, + login_resp.text[:200], + settings.HUB_ADMIN_EMAIL, + ) + else: + svc_token = login_resp.json().get("access_token", "") + hub_resp = await client.post( + f"{settings.HUB_URL}api/v1/hub/invites", + json={"email": str(data.email), "tenant_slug": tenant_slug}, + headers={"Authorization": f"Bearer {svc_token}"}, + ) + if hub_resp.status_code in (200, 201): + hub_data = hub_resp.json() + hub_invite_token = hub_data.get("invite_token") or _extract_token_from_url(hub_data.get("invite_url", "")) + invite_url = hub_data.get("invite_url", "") + else: + logger.error( + "[invite] Hub invite creation falló: status=%s body=%s tenant=%s email=%s", + hub_resp.status_code, + hub_resp.text[:300], + tenant_slug, + data.email, + ) + except Exception as exc: + logger.error("[invite] Hub invite creation excepción (non-blocking): %s", exc) # Fallback: URL del workspace (Hub) si la creación de invitación en Hub falló if not invite_url: