Appearance
Frontend - Portal de Clientes
Frontend PWA independiente para clientes finales, completamente separado del sistema administrativo.
Caracteristicas
- Tecnologia: Vite + React 19 + TypeScript
- Repositorio: Independiente (
portal-usuariossubmodule en/var/www/Bautista/portal-usuarios/) - Optimizado para: Clientes finales en dispositivos moviles (mobile-first)
- PWA: vite-plugin-pwa, Service Workers, offline support, installable
- Despliegue: Docker por tenant (build multi-stage: Node build, nginx:alpine serve)
- Build por tenant: Cada imagen Docker compila con variables
VITE_*propias del tenant (branding, URLs, credenciales) - Branding: CSS variables customizables por tenant via shadcn/ui + Tailwind CSS
- Autenticacion: JWT con password (registro, login, reset de password)
Stack Tecnologico
| Categoria | Tecnologia | Justificacion |
|---|---|---|
| Build | Vite | Build estatico, HMR instantaneo, PWA plugin oficial |
| UI Framework | React 19 + TypeScript | Componentes modernos con hooks, ecosistema maduro |
| UI Library | shadcn/ui + Radix UI | Componentes headless, altamente customizables via CSS variables. Ideal para branding por tenant |
| Styling | Tailwind CSS | Utility-first, responsive por defecto, purge automatico. Mobile-first con breakpoints sm, md, lg |
| Router | TanStack Router | Type-safe routing con validacion de search params via Zod |
| Server State | TanStack Query | Cache, refetch automatico, polling via refetchInterval para actualizaciones en tiempo real |
| Client State | React Context | Solo para auth (JWT) y branding (VITE_* env vars). Sin store global |
| Forms | React Hook Form + Zod | Validacion declarativa con schemas tipados, rendimiento con register sin re-renders |
| HTTP | Axios | Consistente con bautista-app admin, interceptors para JWT y tenant headers |
| PWA | vite-plugin-pwa | Service worker con Workbox, manifest generado desde config, precaching automatico |
| Testing | Vitest + Testing Library | Unit y componentes: renderizado, interacciones, hooks |
| E2E | Playwright | Flujos criticos: login, registro, pago |
Documentacion
Arquitectura Frontend
Arquitectura completa del frontend PWA, stack tecnologico, estructura de proyecto y componentes.
Incluye:
- Stack tecnico completo (Vite, React 19, TypeScript, shadcn/ui, Tailwind, TanStack Router/Query)
- Arquitectura de componentes con diagramas Mermaid
- Estructura de proyecto detallada
- Contextos (AuthContext con JWT, BrandingContext con CSS variables)
- TanStack Router: route tree type-safe con todas las paginas
- TanStack Query: configuracion, polling con refetchInterval
- React Hook Form + Zod: schemas de validacion
- shadcn/ui: patrones de uso de componentes
- API Client (Axios con interceptors para JWT y tenant headers)
- PDF cupon: proxy via backend (GET /portal/cupones/{id}/pdf)
- PWA: vite-plugin-pwa, service worker, manifest
- Mobile-first responsive patterns
- Testing strategy (Vitest+TL vs Playwright)
Paginas
Documentacion de cada pagina del portal:
/login- Login con DNI/CUIT + password/register- Auto-registro con validacion contra ordcon/forgot-password- Solicitar codigo de reset via email/reset-password- Ingresar codigo + nueva password/dashboard- Resumen de cuenta (saldo, facturas vencidas, ultimo pago)/deudas- Listado de deudas pendientes con indicadores de vencimiento/pagar- Seleccion de facturas y pago online/pagar/exito,/pagar/error,/pagar/pendiente- Resultado de pago (con polling automatico)/cupones- Listado y generacion de cupones con codigo de barras/historial-pagos- Historial de transacciones
Componentes
Componentes reutilizables del portal:
- Layout: Header, Footer, Navigation (shadcn/ui + Tailwind responsive)
- Auth: LoginForm, RegisterForm, ForgotPasswordForm, ResetPasswordForm (React Hook Form + Zod)
- Deudas: DeudaCard, DeudaList
- Pagos: PaymentButton, SelectFacturas
- Cupones: CuponCard, CuponList, descarga PDF via proxy
- UI (shadcn/ui): Button, Card, Input, Form, Dialog, Badge, Skeleton, Toast
API Client
Cliente de comunicacion con el backend:
- Configuracion Axios con
VITE_BACKEND_URL - Headers automaticos:
Authorization(JWT Bearer),X-Tenant-ID,X-Sucursal-ID - Interceptors: request (JWT + tenant context), response (401 -> refresh token -> retry o redirect a login)
- Modulos por recurso: auth, ctacte, pagos, cupones
- TanStack Query hooks:
useDeudas,usePagos,useCupones,useMiCuenta
PWA
Configuracion Progressive Web App con vite-plugin-pwa:
- Service Worker via Workbox (generateSW)
- Manifest generado desde
vite.config.tscon variables VITE_* - Cache strategies: NetworkFirst (API), CacheFirst (assets), StaleWhileRevalidate (fuentes)
- Precaching automatico de shell de la app
PDF Cupones
La descarga de PDF de cupones se realiza via proxy del backend:
- Frontend llama a
GET /portal/cupones/{id}/pdf - Backend recibe el request, resuelve tenant, y llama internamente al servicio de informes (puerto 9999)
- Backend retorna el PDF como stream (Content-Type: application/pdf)
- El cliente NUNCA ve ni accede directamente al servicio de informes
Polling para Actualizaciones en Tiempo Real
En vez de WebSockets o SSE, se usa polling automatico con TanStack Query:
refetchInterval: 5000(5 segundos) en paginas de resultado de pago (/pagar/exito,/pagar/pendiente)refetchInterval: 10000(10 segundos) en pagina de deudas (si hay pagos recientes pendientes de acreditacion)- El polling se desactiva automaticamente cuando la ventana pierde foco (
refetchIntervalInBackground: false) - Sin infraestructura adicional: no se necesita servidor WebSocket ni eventos del servidor
Diseno Mobile-First
El portal esta optimizado para uso desde celulares. Los clientes principalmente consultan deudas y pagan desde sus telefonos.
Patron de breakpoints Tailwind:
- Default: mobile (320px+)
sm:tabletas pequenas (640px+)md:tabletas (768px+)lg:desktop (1024px+)
Principios:
- Cards apiladas verticalmente en mobile, grid en desktop
- Botones full-width en mobile, auto-width en desktop
- Navegacion inferior en mobile, sidebar en desktop
- Touch targets minimo 44x44px
- Sin hover-only interactions
Build por Tenant
Cada tenant recibe su propia imagen Docker con configuracion integrada en build time:
dockerfile
ARG VITE_BACKEND_URL
ARG VITE_TENANT_ID
ARG VITE_SUCURSAL_ID
ARG VITE_APP_NAME
ARG VITE_LOGO_URL
ARG VITE_PRIMARY_COLOR
ARG VITE_THEME_COLORLas variables VITE_* son resueltas por Vite en build time via import.meta.env. No existe inyeccion de configuracion en runtime. Cambiar la configuracion de un tenant requiere un nuevo build de la imagen Docker.
Por que build per tenant (no runtime):
- Las variables
VITE_*son build-time only por diseno de Vite - Simplicidad: no hay logica de inyeccion de config al iniciar el contenedor
- Cada imagen es inmutable y reproducible
- El costo de build es bajo (< 1 minuto por tenant con cache de Docker layers)
Branding via Variables de Entorno
Cada instancia Docker tiene su propio branding compilado en la imagen:
| Variable | Descripcion | Uso |
|---|---|---|
VITE_APP_NAME | Nombre de la aplicacion | Header, manifest PWA, <title> |
VITE_LOGO_URL | URL del logo | Header, login, manifest icons |
VITE_PRIMARY_COLOR | Color principal (hex) | CSS variable --primary, shadcn/ui theme |
VITE_THEME_COLOR | Color del tema PWA | Manifest, <meta name="theme-color"> |
shadcn/ui facilita el theming por tenant porque sus componentes se estilizan via CSS variables de Tailwind. El BrandingContext lee import.meta.env al iniciar y aplica las variables CSS en document.documentElement.
Autenticacion
- JWT con password (no passwordless)
- Registro automatico: DNI/CUIT debe coincidir con ordcon
- Login: DNI/CUIT + password
- Reset de password via codigo por email
- AuthContext gestiona estado de autenticacion, tokens JWT y refresh
- Access token en
localStorage(SPA sin backend propio, no hay httpOnly cookies disponibles) - Refresh token UUID almacenado en
portal_usersdel backend
Testing
| Tipo | Herramienta | Alcance |
|---|---|---|
| Componentes | Vitest + Testing Library | Render, interacciones, hooks, forms, contexts |
| E2E | Playwright | Flujos criticos: login, registro, pago online, resultado de pago |
Vitest + Testing Library: Tests rapidos en memoria (jsdom). Cubren render de componentes, validaciones de formularios (Zod schemas), comportamiento de hooks (useAuth, useDeudas), y logica de contextos.
Playwright: Tests de integracion de punta a punta en navegador real. Cubren los flujos criticos que involucran multiples paginas y comunicacion con backend: registro completo, login + ver deudas, flujo de pago hasta redireccion a gateway.