Cursor BYOK Frontend
Construye sobre los componentes y el sistema de temas ya presentes en apps/desktop. Preserva el límite HTTP de Tauri; las funciones de gestión del frontend llaman a /__byok-api__/api y nunca añaden APIs de negocio IPC.
Comunicación HTTP de escritorio
- Trata el servidor de gestión Rust como el único origen HTTP para la UI de escritorio. El WebView principal y las páginas de detalle abiertas en el navegador deben usar
http://127.0.0.1:<dynamic-port>/__byok-api__/; no cargues la UI principal desdetauri://localhostni expongas un segundo origen de frontend. - Realiza cada petición de gestión del frontend de forma relativa a
/__byok-api__/api. No descubras, inyectes, persistas ni pases unapiOrigin, y no construyas URLs de gestión desde un puerto fijo. - Mantén el espacio de nombres
/__byok-api__/reservado para este límite:/__byok-api__/api/*es manejado localmente por la API de gestión Rust.- Otras rutas
/__byok-api__/*son documentos del frontend, assets, módulos y recursos de desarrollo.
- En producción, sirve el frontend incrustado por
frontendDistde Tauri a través del servidor Rust. Reutiliza el resolvedor de assets de Tauri en lugar de empaquetar o copiar un segundo conjunto de recursos del frontend. - En desarrollo, haz que el servidor Rust haga proxy inverso de las peticiones no-API
/__byok-api__/*a Vite. Preserva la ruta de la petición y la cadena de consulta. No configures Vite para hacer proxy de las peticiones de la API de gestión de vuelta a Rust. - Configura la ruta base de Vite como
/__byok-api__/para que los assets generados, las importaciones de módulos y las URLs del cliente de desarrollo permanezcan bajo el espacio de nombres reservado. - Vincula el servidor Vite de desarrollo a una dirección de loopback explícita compatible con el objetivo del proxy Rust; no confíes en que
localhostse resuelva a la misma familia IP. - Abre páginas de detalle externas con su URL HTTP de loopback normal y ruta hash. Como la página y la API son del mismo origen, no añadas soluciones alternativas de URL de Tauri, parámetros de consulta de origen de API ni flujos de navegador dependientes de CORS.
- Usa comandos de Tauri solo para capacidades nativas de escritorio como abrir Terminal, integración con la bandeja del sistema o acciones del sistema operativo. No crees espejos IPC para APIs de negocio HTTP.
Límites de componentes
- Mantén el estado de Proveedor, Modelo, Llamada, Uso y configuración persistida fuera de los componentes de presentación.
- Permite que los componentes reciban instantáneas de negocio y disparen acciones. El estado local de React está permitido para comportamientos transitorios de UI como foco, estado abierto, estado de arrastre y borradores de entrada.
- Divide páginas, diseños, gráficos, formularios y controles reutilizables en componentes enfocados. No recojas un conjunto completo de características en
App.tsx. - Mantén
App.tsxcomo la raíz de composición de rutas.
Diseño de página
- Construye cada página de altura completa con
components/layout/PageLayout.tsx; no diseñes shells de página manualmente con filas de grid. - Coloca comandos y controles a nivel de página como crear, importar, exportar, filtrar, ordenar y opciones de vista en la región de acciones de página compartida a través de
PageActions. Mantén solo las operaciones que apuntan a un elemento de lista concreto, como editar y eliminar, dentro de la fila de ese elemento. No añadas barras de acciones duplicadas ni controles de cabecera de panel dentro del contenido de la página. - Nunca renderices una región de título encima de una tabla de datos o una lista plana de datos. Usa el título de la página para contexto, mantén las etiquetas de columna en el encabezado de la tabla, coloca los controles a nivel de página en
PageActionsy envuelve la tabla en unaCardsin título. Una etiqueta de jerarquía que identifica datos padre en una vista jerárquica padre-hijo agrupada no es un título de tabla. - Mantén el viewport de desplazamiento principal a altura completa y con
position: relative; coloca el título de página y la región de acciones de forma absoluta sobre él. - Reserva la región de título/acciones absoluta con
padding-topen el contenido de desplazamiento, nunca acortando o desplazando el viewport de desplazamiento. - Mantén el menú Card fijo y resérvalo con
margin-leftdel área de contenido; no coloques Header, menú y contenido en un grid de flujo. - No uses padding de hijo o sección para crear espaciado externo. Usa gaps flex/grid entre hermanos y márgenes o desplazamientos fijos en los límites del contenedor; el padding-top del contenido de desplazamiento está reservado solo para su superposición absoluta de título/acciones.
- Usa un diseño flex vertical con estos invariantes:
- Header:
flex: 0 0 auto. - Footer:
flex: 0 0 auto. - Contenido:
flex: 1 1 auto,min-height: 0yoverflow: hidden.
- Header:
- Mantén Header y Footer fuera del viewport de desplazamiento. Nunca deben crecer o encogerse con el contenido.
- Aplica variables de área segura para esquinas de ventana de macOS, Windows y Linux solo al borde del cromo que pueda entrar en esquinas redondeadas nativas.
- Mantén el espacio de los semáforos de tráfico de macOS y la tira de arrastre fija superior libres de controles interactivos.
- Evita texto de marca decorativo y copia explicativa cuando no ayude al usuario a realizar una acción o interpretar el estado.
Tipografía
- Escribe estilos de componentes en SCSS y obtén cada
font-sizedesrc/styles/_typography.scss; nunca codifiques un tamaño de fuente en SCSS, estilos de React u opciones de gráficos. - Usa
basepara texto normal de UI y títulos ordinarios, incluyendo barras de título, paneles, cards y encabezados de sección. No aumentes una fuente solo porque su elemento seah1oh2. - Usa
xssolo para información secundaria. Reservalgpara un título de visualización explícitamente sobredimensionado; no lo uses para encabezados rutinarios. - Audita todos los usos de los tokens de tipografía después de cambiar la escala, no solo los tamaños de fuente numéricos crudos.
Desplazamiento y virtualización
- Usa
components/layout/VirtualPage.tsxpara contenido de página con desplazamiento vertical. - Usa
components/virtual/VirtualList.tsxpara colecciones de datos y menús que puedan crecer. - Trata
ScrollAreacomo la primitiva de bajo nivel propiedad de la implementación de desplazamiento virtual. No importesScrollAreadirectamente en páginas o diseños. - Usa las máscaras globales
scroll-shadow-topyscroll-shadow-bottompara sombras de borde de desplazamiento. Cuando un inset de contenido de desplazamiento reserve una superposición absoluta, obtén la distancia de la sombra superior de la misma variable CSS que supadding-top. - Modela páginas que no son listas como una secuencia corta de secciones virtuales medibles de alto nivel.
- No uses desplazamiento de documento,
overflow: autonativo de página ni contenedores de desplazamiento vertical anidados. - Asegura que cada ancestro flex/grid de un viewport virtual tenga
min-height: 0y que el viewport tenga una altura explícita acotada.
Enrutamiento y páginas
- Usa
HashRouterpara compatibilidad con Tauri. - Mantén
/como el panel de estadísticas y expón cada página principal a través del menú persistente en elAppLayoutcompartido. - Usa rutas de nivel superior para páginas principales:
/,/providers,/models,/callsy/settings. - No crees shells separados de Inicio y Configuración ni añadas un control de cambio de Inicio.
- Mantén el contenido de la ruta independiente del Header y Footer de la ventana.
Gráficos
- Usa ECharts a través de
components/charts/EChart.tsx. - Registra solo los gráficos, componentes y renderizadores de ECharts Core necesarios.
- Mantén los componentes de gráficos declarativos: aceptan datos de dominio y construyen una opción sin obtener ni persistir datos.
- Deja que
ResizeObserverredimensione el gráfico con su contenedor de diseño y elimine la instancia al desmontar.
Validación
Ejecuta desde apps/desktop:
npm run check
npm run tauri:build -- --debug --no-bundle
Verifica que Header y Footer permanezcan fijos, solo el viewport de contenido virtual se desplace, la navegación de configuración siga siendo accesible con el tamaño mínimo de ventana, y los controles de macOS permanezcan fuera de las regiones no seguras de esquinas redondeadas y semáforos de tráfico.