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.

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 — 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: share ACL · Experts conversation_id · VC tabla/wizard.
  • Dibujá de memoria el diagrama BFF de al menos un producto.
  • Preguntas: ¿web o RN? ¿dolor FE? ¿éxito a 90 días?