Solverive · Front Lab

Repaso Front Sr
con tu código real

Airtalk Chat (Experts / agent_poc), Data Boards y Value Capture (DataHub). Ejemplos citados de los repos en Gitlab — listo para Chapter Lead Humand.

Cómo trabajo (pitch 90s)

Resumen para la entrevista

Soy front senior en el ecosistema LATAM Data / Datadem. Trabajo el día a día en tres frentes que se complementan:

  1. Airtalk Chat — conversación NL→datos (lo que históricamente se asocia a Arcwise / core-api /agent_poc). Hoy vive en Experts: UI React + BFF Next + agente.
  2. Data Boards — dashboards HTML/React generados desde el análisis: canvas, chat de edición vía MCP, share ACL owner/editor/viewer.
  3. Value Capture (DataHub) — módulo de gobierno de datos: catálogo de data products, wizards multi-step, tablas pesadas, roles Azure AD, BFF a Cloud Run.
Cómo laburo: ownership de features end-to-end (UI → BFF → contrato con core/MCP/VC-service), lógica de dominio en módulos puros testeables, fail-closed en auth/permisos, y UX accionable (nunca un error sin CTA). Code review con foco en races, tokens y verdad de permisos entre UI y API.

Día a día concreto

  • Next.js App Router + TypeScript + NextAuth (Google / Azure AD).
  • i18n (es/en/pt) en Airtalk; Hangar + Ant Design en DataHub.
  • Deploy Cloud Run; secrets vía Secret Manager; ambientes local/dev/prod.
  • Selftests de lógica pura en Data Boards (~450 asserts en accesos) cuando el dominio lo merece.

Mapa de productos ↔ repos

Gitlab

Soporte: airtalk-data-mcp (tools reportes + ACL), airtalk-core-api / agent (/agent_poc), data-governance-platform-value-capture-service.

Arquitectura · Airtalk Chat

Experts + agent_poc (ex conversación / Arcwise)

Qué es en la práctica

El usuario escribe en lenguaje natural; el front arma un historial tipado, el BFF llama a core-api POST /agent_poc (o knowledge layer en poc-2), y la UI renderiza respuestas con tablas, SQL, costos y estados de carga. La ruta vieja /talk/conversacion redirige a Experts cuando el flag está on.

Composición técnica

Landing / talk (ChatInput) ──redirect──► /[locale]/experts
ExpertChat (estado + localStorage + ?thread=)
  → POST /api/experts/ask          (BFF, maxDuration ~1200s, JWT NextAuth)
  → lib/experts/core-api.ts
  → Cloud Run core-api /agent_poc  (agente + tools SQL / datos)
  ← mensajes tipados + conversation[]
  → ExpertMessagesList (markdown, tools, SQL)
  → opcional: POST /api/experts/share → GCS → /share/[id]

Shell y auth

  • MainSection: full-bleed en Experts/Reports (sin ChatInput global); en /talk muestra sugerencias + input que redirige a /experts al enviar.
  • SessionWrapper: NextAuth (Google + Azure), dominios @latam*, autologin, banner si Akamai Edge Access Denied (lib/edge-access.ts).
  • Middleware solo i18n; el gate de producto es sesión en cliente + JWT en cada BFF.

Piezas clave (repos reales)

  • components/experts/ExpertChat.tsx — hilo, restore, share, thinking_mode, edge errors.
  • app/api/experts/ask/route.ts + ask-knowledge (POC knowledge layer).
  • lib/experts/core-api.ts — agent_poc; reintento con nuevo conversation_id si cache devolvió {}.
  • Legacy paralelo: useChat (Vercel AI) + /api/chat streaming + /api/stream (Pub/Sub SQL). /talk/conversacion → redirect Experts.
  • “Arcwise” en FAQ son links externos a sql.arcwise.app; el chat productivo que mantenemos es Experts → agent_poc.

Ejemplo de decisión Sr

El agente cachea fallos por conversation_id. En core-api.ts detectamos body vacío y reintentamos con UUID nuevo. Ownership del contrato FE↔agente, no solo pintar bubbles.

Arquitectura · Data Boards

airtalk-data-frontend-service

Composición

/reportes                 ReportsList ← GET /api/reports + /shared
/reportes/[id]            ReportViewer
  GET  …/meta             permissions + metadata.json + probe MCP
  POST …/chat             modify_suggestions → write GCS (canvas)
  POST …/refresh-data     read_only_sql + update_data
  GET/POST/DELETE …/access  ACL MCP (solo owner)
  POST …/publish          publish_report + bake HTML opcional
  PUT  …/layout|instructions

MCP: JSON-RPC /mcp (identity token IAM + access-token Google user)
GCS: reports/{email}/{id}/metadata.json + _idx/{id}

Capas

  • UI: ReportViewer, ShareReportDialog, Canvas/ReportCanvas, useReportRefresh.
  • Dominio puro: shareAccessLogic, authorizeAccessLogic, reportAccess, permissions.buildReportPermissions — selftests (~450 asserts) sin React.
  • Adapters: gcs.ts (owner vía _idx, origin snapshot), mcpChat.callMcpTool, googleAccessToken.
  • Gate BFF: apiAuth — allowPublished / requireEditor / requireOwner; fallback GCS si MCP report_not_found o caído.

Ejemplo ACL (feature que lideraste)

canShare solo si rol owner y (accessSource === "mcp" o fallback GCS con gcsFallbackReason === "report_not_found"). Si MCP cae (mcp_unavailable) → acl_unconfirmed: editás el canvas pero no Compartir (fail-closed). Chip “Solo lectura” debía ser !canEdit, no !isOwner (editores podían editar con label mentiroso).

Chat sobre el reporte

Mismo patrón que Experts pero tools de render: useGoogleSession + probe MCP; mcpChat.ts encadena modify_suggestions → persist metadata (React canvas) o modify_report (HTML bake). Filtros locales en chatFilters.ts cuando el pedido es “filtrá por región” sin ir al LLM.

Arquitectura · Value Capture (DataHub)

data-governance-platform-frontend

Stack

Next.js (App Router) + React, TS strict, Hangar + Ant Design + Tailwind, TanStack Query, NextAuth Azure AD, i18n es/en/pt. App en data_governance_platform_frontend/src/ dentro del monorepo DATAHUB (~20 módulos; VC es uno).

BFF (patrón oficial del repo)

Client + React Query
  → src/services/value-capture/        (Axios → /api/value-capture-service)
  → app/api/value-capture-service/**   (BFF Route Handlers)
       X-Serverless-Authorization      (GCP ID token → Cloud Run IAM)
       Azure-User-Authorization        (token usuario NextAuth)
  → FastAPI value-capture-service api/v1/*

Features que el FE posee

  • Catálogo Data Products — tabla server-side, vistas custom, deep-link al wizard.
  • Wizard create/edit — steps ↔ POST …/step/{n} + complete (multisquad, WAVE 409).
  • Registro valor manual / automático + historial ejecuciones.
  • Change requests (mis solicitudes / approvals) + users-settings por rol.

Archivos para citar

  • DataProductsTable/index.tsx, DataProductWizard/DPWizard.tsx + steps.tsx.
  • services/value-capture/index.ts, shared/lib/axios (dual token).
  • useValueCaptureSiderItems, VCViewerRestrictedRoute, RoleProtectedRoute.

Ejemplo Sr en VC

Doble capa de auth: plataforma (Azure roles) + dominio VC (user_profile → VC_ADMIN / VIEWER / editor). El sider no pega APIs hasta conocer el rol (evita 403 en cascada). Fetches dedupeados; filtros UI→API con helpers puros. Escala de gobierno, no landing.

React — con ejemplos del repo

Mental model aplicado

Estado derivado (Data Boards)

// ReportViewer — no guardamos canShare en un useState paralelo
const canEdit = Boolean(perms?.canEdit) && !isPreviewView
const canShare = Boolean(perms?.canShare) && !isPreviewView
const isReadOnlyView = !canEdit

Bug real: chip “Solo lectura” usaba !isOwner → un editor veía solo lectura pero podía chatear. Fix: !canEdit.

Effects + Strict Mode (Experts / Boards)

En share, fetchAccessList usa mapa accessListInflight porque Strict Mode monta dos veces y abortar el único fetch rompía la carga. Mismo espíritu que inflightKeys en Value Capture.

Keys estables

Lista de accesos ACL: key = email normalizado (emailKey en shareAccessLogic.ts), no index — si no, al revocar/reordenar el switch “puede editar” salta de fila.

useMemo / useCallback

En DataProductsPage hay useMemo/useCallback donde la tabla y los filtros son caros. En Boards, no memoizo el dialog entero “por las dudas”: memoizo reglas en módulos puros y dejo React renderizar UI barata.

Estado & data fetching — ejemplos

BFF, races, optimistic, tokens

BFF en los tres productos

  • Chat: browser nunca llama agent_poc con secrets; pasa por /api/experts/ask.
  • Boards: browser → /api/reports/... → GCS SA + MCP con identity token + user access-token.
  • VC: React Query → /api/value-capture-service/... → GCP + Azure headers.

Optimistic grant (Boards)

setAccessList(list => applyOptimisticGrant(list, entry))
const res = await fetch(.../access, { method: 'POST', body })
if (!res.ok) {
  setAccessList(list => rollbackOptimisticGrant(list, email))
  setError(mapAccessMutationError(...)) // 401 → CTA renew
}

Sesión Google vencida (Boards)

Chat ya tenía banner + renewSession (useGoogleSession → signIn('google')). Share alineado: al click Compartir, resolveShareOpenAction → renew si expired; si 401 en /access, banner con el mismo CTA (no mensaje muerto).

Server state en VC

React Query + services Axios. Invalidación al registrar valor o guardar wizard. Filtros de tabla se traducen a query params del service — una sola fuente de verdad en el servidor, UI como proyección.

Performance — ejemplos

Qué tocamos en prod

  • Boards: skeleton medido (ReportSkeleton / writeSkeletonMeasured para no layout-shift al abrir un reporte; canvas React vs iframe según capabilities.
  • Chat: maxDuration alto en route; UI con loading/thinking modes; no bloquear scroll del hilo (useLayoutEffect en ExpertChat).
  • VC: paginación + filtros server-side; evitar refetch duplicado; columnas visibles configurables (menos DOM).
  • Landing Airtalk: recovery script si chunks no hidratan (extensiones corporativas) — resiliencia percibida como perf.
Frase: “En DataHub/Boards el cuello suele ser red + payload, no el virtual DOM. Primero contrato/BFF, después memo.”

Calidad — ejemplos

Tests y contratos

  • lib/reports/reportAccess.integration.selftest.ts — matriz roles, gates, optimistic, session_expired, resolveShareOpenAction.
  • Selftests chicos: chatFilters, refreshAll, shareDialog.
  • VC: lint/prettier estrictos (Hangar); permisos de ruta como config revisable en PR (routesPermissions/items/value-capture.ts).
  • Types discriminados: resultados { ok: true } | { ok: false, code } en MCP/access.

Comportamiento Sr — cómo se ve en PRs

Historias cortas

  • Verdad de permisos: escondí Compartir si /access dice not_acl_owner; bajé flags en cliente (onShareAccessDenied.
  • Seguridad FE: cleanup de endpoints legacy peligrosos (MR seguridad) + no exponer tokens al browser.
  • Producto: modal Compartir alineado al share de hilos Airtalk (misma gramática mental para el usuario).
  • Cross-squad: coordinar con MCP (grant_report_access / publish_report cuando el FE solo no alcanza.

Problema → solución (casos reales)

Para “contame un feature donde hubo un problema y propusiste la solución” · formato STAR corto

Plantilla verbal (90–120 s): Contexto → síntoma → causa → opción que descarté → solución → cómo lo validé.

1. Data Boards — Compartir / ACL

Problema: GCS decía “el reporte es tuyo” (carpeta / metadata) pero MCP tenía otro owner o rol editor. La UI ofrecía Compartir y fallaba / confundía (editores con chip “Solo lectura” pero podían editar).

Solución propuesta: una sola verdad de permisos — buildReportPermissions: canShare solo con owner MCP confirmado, o report_not_found (not_migrated). Si MCP cae → acl_unconfirmed, no Compartir. Chip = !canEdit. Si /access niega ownership → cerrar modal y bajar flags (onShareAccessDenied). Lógica pura + ~450 selftests.

Citar: permissions.ts, apiAuth.ts, ShareReportDialog, shareAccessLogic.

2. Data Boards — Token Google vencido en Compartir

Problema: chat ya pedía renew de sesión; el modal Compartir abría con error 401 / mensaje sin acción (“sesión vencida”) y el usuario no sabía qué hacer.

Solución: mismo contrato que el chat — useGoogleSession también para share; al click Compartir, resolveShareOpenAction → si expired, signIn directo; si 401 en vuelo, banner con CTA “Renovar sesión de Google”.

3. Data Boards / MCP — owner degradado al self-grant

Problema (backend MCP): on_conflict_do_update en grant podía pisar el rol del owner si alguien se auto-agregaba; lista de accesos inconsistente.

Solución: en report_access.py — rechazar grant al owner_id; autocura del rol owner en list_report_access; owner_id manda sobre filas degradadas en user_management. FE alinea: no te agregues a vos mismo (invalid_target / shareSelfTarget).

4. Data Boards — Akamai rompe PATCH / bodies con SQL

Problema: edge Akamai delante de *.appslatam.com respondía 501 a PATCH y WAF en POSTs con SQL/markdown en claro (share de hilos / layout).

Solución: APIs de layout/instructions pasan a POST (no PATCH). Share Experts: encodeShareRequestBody (payload base64) para que el WAF no inspeccione SQL; límites de tamaño en route; UX de edge-access (no martillar login si Access Denied).

Citar: layout/route.ts, share-payload.ts, lib/edge-access.ts.

5. Landing Airtalk — la app “no carga” (extensiones)

Problema: en corporativo, extensiones (p. ej. LATAM Meet Tools) rompen MIME/chunks de Next: pantalla en blanco, soporte inundado, usuario cree que Airtalk está caído.

Solución: script inline en app/layout.tsx (no depende de chunks) + AppLoadMarker que setea __AIRTALK_LOADED__. Si a los 15s no hidrató → overlay con diagnóstico (incógnito / desactivar extensiones) y recargar. Resiliencia percibida > culpar al usuario.

6. Landing / auth — Akamai Access Denied en login

Problema: autologin Google + retries empeoraban el handshake Bot Manager → Access Denied en loop.

Solución: SessionWrapper intercepta fetch, marca edge-denied, frena autologin/reintentos, banner con bypass App Engine (Cloud Run sin hostname Akamai). No “reintentá login” a ciegas.

7. Airtalk POCs / Experts — agent_poc responde {}

Problema: core-api /agent_poc tiene @cache(); un fallo previo quedaba cacheado por conversation_id → UI “sin respuesta” en Experts y POCs (/poc, /poc-2 knowledge layer).

Solución: en lib/experts/core-api.ts detectar body vacío y reintentar con nuevo UUID; mensaje accionable (“Nueva conversación” / Quick). POC-2 usa /api/experts/ask-knowledge → agent_poc_knowledge_layer (variante sin forzar email en local ADC cuando rompe).

8. Plugin ChatGPT / Custom GPT + MCP

Problema: exponer Airtalk MCP a Custom GPT vía Cosmos Bridge (OAuth GPT Actions). Los scopes GCP/BQ/Drive que pide MCP no se pueden imponer bien desde la UI de GPT Actions → integración frágil / pausada; usuarios esperaban “plugin = mismo poder que la web”.

Solución / postura Sr: documentar el flujo real (docs/mcp_setup_custom_gpt.md: authorize/token Bridge, schema GPT Action, scopes). Separar expectativas: Custom GPT como cliente OAuth del bridge, no como reemplazo del BFF web. Guía en landing (UserGuide: chatgpt/plugin). Mientras scopes no cierren, no vender feature a medias; priorizar Experts web + MCP tools con auth Cloud Run + user token.

Citar: gpt_actions_schema.py, profiles gpt_actions.bridge_server, doc Custom GPT.

9. Tools MCP — edición de reportes desde el chat

Problema: el LLM pedía cambios al dashboard pero el FE no podía confiar solo en el model: filtros ambiguos, sesión vencida, tools faltantes, o re-bake HTML lento.

Solución: pipeline en mcpChat.ts: probe MCP → dual auth (IAM + access-token) → modify_suggestions; en React canvas metadataOnly + persist GCS en BFF (sin bake). Filtros locales en chatFilters.ts cuando el intent es claro (“filtrá por región”) sin round-trip. UX: session_expired / tools_missing / checking con CTAs distintos.

10. Tools MCP — Strict Mode / doble fetch de ACL

Problema: al abrir Compartir, Strict Mode abortaba el único GET /access en vuelo → lista vacía o error intermitente.

Solución: mapa accessListInflight + cache corta (sin AbortSignal compartido que mate el fetch único). Misma idea que inflightKeys en Value Capture.

Cómo elegir cuál contar

  • Permisos / seguridad de producto: casos 1, 3, 4.
  • Resiliencia / plataforma LATAM: 5, 6, 4.
  • IA / agente / MCP: 7, 8, 9.
  • Detalle de ingeniería FE: 2, 10.

Puente a Humand

Misma clase de problemas

Humand: mobile-first HR + Sammy AI. Nosotros: chat NL→acción (Experts/agent_poc), permisos finos (ACL Boards / roles VC), wizards y tablas densas (Value Capture). El Sr une confianza del usuario, contratos con backend y estados honestos (loading / token / forbidden).

Banco Q&A (respuestas con repos)

90–120 s · practicar en voz alta

Q1 — Feature complejo

Data Boards share ACL. Modal ShareReportDialog + MCP grant/revoke/publish. permissions.ts define canShare; apiAuth autoriza; selftests. Tradeoff: GCS owner ≠ ACL owner → fail-closed (acl_unconfirmed).

Q2 — Chat / agente

Experts. ExpertChat → /api/experts/ask → agent_poc. Manejo de conversation_id cacheado, thinking_mode, share de hilo, persistencia local. El valor está en el BFF y el contrato de mensajes, no solo en el bubble UI.

Q3 — Tabla / wizard enterprise

Value Capture. DataProductsPage + wizard multi-step + React Query + BFF Azure/GCP. Dedupe de fetches, vistas personalizadas, RoleProtectedRoute. Escala de gobierno de datos, no landing marketing.

Q4 — useMemo

Casi nunca default. En VC sí aparece alrededor de tabla/filtros. En Boards priorizo lógica pura testeada y can* derivados. Si el Chapter Lead aprieta: “mido con profiler antes de memoizar el árbol”.

Q5 — Sesión vencida

useGoogleSession + renew en chat Boards; mismo patrón en Compartir (resolveShareOpenAction). En Experts, NextAuth JWT en el BFF; sin email no llamamos agent_poc a ciegas.

Q6 — Cómo estructurás un módulo nuevo

Como VC: modules/x/{components,pages,hooks,types} + services/x + app/api/x + permisos en constants. En Boards: UI en components/Reports, dominio en lib/reports, API en app/api/reports. Misma idea: bordes claros.

Q7 — Conflicto UI vs API de permisos

Historia del chip Solo lectura / canShare. Regla: la UI no puede prometer más que el authorize del BFF. Si /access 403 → cerrar modal y bajar canShare en estado.

Q8 — Feature con problema y solución que propusiste

Elegí de Problema → solución: ACL canShare (fail-closed), landing load-recovery/Akamai, o agent_poc cache {}. Contá tradeoff descartado (ej. “confiar solo en GCS”) y cómo lo validaste (selftests / repro en edge).

Q9 — Cómo te sumás a un squad nuevo

Leo CLAUDE/README + un flujo crítico (en DataHub el BFF auth; en Airtalk un ask Experts). Uno PR chico de bug/UX. Después ownership de un slice (ej. share o un step del wizard). Pregunto métricas a 90 días.

Checklist del día

  • Pitch 90s: Chat (agent_poc) + Boards (MCP/ACL) + VC (DataHub BFF).
  • 3 STAR listos: share ACL · landing/Akamai o load recovery · agent_poc {} / MCP chat.
  • Sección Problema → solución: elegí 2 según la pregunta (permisos vs IA vs plataforma).
  • Dibujá de memoria el diagrama BFF de al menos un producto.
  • Preguntas: ¿web o RN? ¿dolor FE? ¿éxito a 90 días?