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:
-
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.
-
Data Boards — dashboards HTML/React generados
desde el análisis: canvas, chat de edición vía MCP, share ACL
owner/editor/viewer.
-
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?