Saltar al contenido
nvíame

Ingeniería

TRD · Documento de requisitos técnicos

Stack, arquitectura del playground, persistencia y despliegue.

Stack

  • React con TypeScript y TanStack Start (enrutamiento por archivos, render en servidor para SEO).
  • Tailwind CSS v4 con tokens semánticos y componentes shadcn/ui.
  • CodeMirror 6 vía @uiw/react-codemirror con lenguaje JavaScript.
  • framer-motion para diff, celebración y transiciones.
  • lucide-react para iconografía.
  • Fuentes Source Serif 4, Inter y JetBrains Mono desde Google Fonts.

Arquitectura del playground

El editor se carga solo en el cliente. Cada ejecución crea un Web Worker desde un Blob con el SDK mx congelado; el código del usuario se envuelve en una función asíncrona y recibe mx y un console redirigido. fetch, XMLHttpRequest, WebSocket e importScripts se anulan. Un vigilante de 6 s termina el worker si no responde.

page ──postMessage{run, code}──▶ worker
worker ──{kind:'out'|'status'|'bot'|'system'|'log'|'error'|'done'}──▶ page
  • mx.sms.send y mx.chat.send: emiten burbuja sent y 800 ms después delivered.
  • mx.otp.issue/verify: aleatoriedad criptográfica, un solo uso, 5 min de validez.
  • mx.bot.onMessage/reply: habilita el campo de entrada en el teléfono.
  • mx.webhook.sign: HMAC-SHA256 real con WebCrypto.

Estado y sincronización

Progreso y comentarios usan un store sobre localStorage expuesto con useSyncExternalStore, de modo que anillos, barras y checklists se actualizan a la vez. Un evento nvi:celebrate dispara la celebración global.

Despliegue

Se publica desde Lovable y se conecta el dominio personalizado nviame.cl. No hay backend ni llamadas de red externas en tiempo de ejecución, salvo la carga de fuentes.

Arquitectura general

nvíame es una aplicación React con TypeScript, renderizada en el servidor en la primera carga e hidratada en el cliente. El enrutamiento usa rutas basadas en archivos: inicio, biblioteca, serie, capítulo y documentos. Todo el contenido se compila dentro del bundle como datos tipados, de modo que no existe servidor de contenidos ni base de datos.

El estado del aprendiz —progreso, comentarios y tema— vive en localStorage y se expone mediante un store pequeño basado en useSyncExternalStore. Cada vista se suscribe al mismo store, por lo que completar un capítulo actualiza al instante los anillos de la biblioteca, la barra de la serie y el grafo.

Aislamiento del playground

El código del aprendiz se ejecuta en un Web Worker creado desde un Blob. Antes de ejecutar, el worker elimina fetch, XMLHttpRequest, WebSocket, EventSource e importScripts, de manera que ningún script puede salir a la red. Un temporizador de seis segundos en el hilo principal termina el worker si el código entra en un bucle infinito.

El editor es CodeMirror 6, cargado de forma diferida y solo en el cliente para no afectar el renderizado del servidor. Mientras carga, el capítulo muestra el código como bloque estático, así el contenido es legible incluso sin JavaScript.

Rendimiento y accesibilidad

  • Fuentes con display=swap y precarga de los orígenes.
  • Editor y celebración cargados bajo demanda.
  • Foco visible en todos los controles y etiquetas ARIA en botones de solo ícono.
  • Contraste AA verificado en tema claro y modo tenue.