Files
AgendaPro/README.md
T

182 lines
8.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AgendaMax
Aplicación web **multi-tenant (SaaS)** para la gestión de negocios de servicios (estética, spa, barbería, clínicas, etc.):
calendario de citas con **arrastrar y soltar**, gestión de **empleados**, **servicios**, **clientes** y **tickets**,
y un **tablero** con ingresos, mejores empleados, servicios más rentables y clientes top.
Tres roles: **Administrador de plataforma** (crea y gestiona todos los negocios desde la consola admin),
**Dueño** (ve su negocio y el tablero) y **Empleado** (agenda citas que se auto-asignan a él).
## Stack
- **Frontend**: React 18 + TypeScript + Vite + Tailwind CSS
- **Calendario**: FullCalendar (drag & drop, resize, day/time grid)
- **Gráficas**: Recharts
- **Backend**: Node.js + Express
- **Base de datos**: SQLite (vía `node:sqlite`, nativo de Node — sin compilación nativa)
## Requisitos
- Node.js **22.5+** (recomendado 24+). Este proyecto usa el módulo nativo `node:sqlite`.
## Instalación
```bash
npm install
```
La base de datos se **siembra automáticamente** con datos demo la primera vez que arranca el servidor.
Para regenerarla desde cero:
```bash
# Borra la DB y vuelve a sembrar
npm run seed
# o, forzando reset desde el servidor:
$env:RESET_DB="1"; npm run dev:server # PowerShell
RESET_DB=1 npm run dev:server # bash
```
## Desarrollo
```bash
npm run dev
```
Abre http://localhost:5173 (el frontend proxya `/api` al backend en el puerto 3000).
## Producción
```bash
npm run build # compila TS y empaqueta el frontend en dist/
npm start # sirve la API y el frontend estático en http://localhost:3000
```
## Instalar AgendaMax como app
- **Android/Chrome**: abre la URL HTTPS y selecciona la acción de instalación mostrada por AgendaMax o por la barra de direcciones del navegador.
- **iPhone/iPad Safari**: usa **Compartir -> Añadir a pantalla de inicio**; iOS no expone el aviso de instalación dentro de la página de Android.
- La app instalada puede abrirse sin la interfaz del navegador, pero los datos del negocio siguen requiriendo conexión a internet.
- Validación local: ejecuta `npm.cmd run build`, inicia producción con `npm.cmd start` y después ejecuta `npm.cmd run test:pwa`.
- La validación de producción requiere el dominio HTTPS de Coolify, no una dirección IP HTTP.
`npm.cmd run test:pwa` usa estas variables opcionales para los flujos autenticados;
si no se definen, usa las cuentas demo locales:
```text
[email protected]
[email protected]
PWA_PASSWORD=demo1234
```
## Tests y auditoría visual
```bash
npm run test:e2e # 22 pruebas end-to-end de la API (login, CRUD, dashboard, auto-asignación, roles, multi-tenant)
npm run test:admin # 17 pruebas del admin (crear negocio + plantilla, aislamiento, reset-demo, delete cascade)
npm run audit:visual # Playwright: navega 10 páginas × 4 viewports (móvil/tablet/desktop/wide),
# mide overflow horizontal, captura errores de consola y guarda capturas en screenshots/
```
La auditoría visual verifica responsividad en 375 / 768 / 1280 / 1536 px, detecta overflow,
errores de consola y confirma que el calendario, el modal de cita y el cambio de sesión funcionan en cada tamaño.
## Cuentas demo
Todas usan la contraseña **`demo1234`**.
| Rol | Email | Contraseña | Nombre |
|----------|----------------------------------|------------|------------------|
| **Admin**| `[email protected]` | `demo1234` | Administrador |
| Dueño | `[email protected]` | `demo1234` | Daniela Reyes |
| Empleado | `[email protected]` | `demo1234` | Valentina Cruz |
| Empleado | `[email protected]` | `demo1234` | Mateo Herrera |
| Empleado | `sofía.ramí[email protected]` | `demo1234` | Sofía Ramírez |
| Empleado | `[email protected]` | `demo1234` | Diego Castillo |
| Empleado | `[email protected]` | `demo1234` | Isabela Torres |
| Empleado | `carolina.mé[email protected]` | `demo1234` | Carolina Méndez |
> En la pantalla de login aparecen botones de acceso rápido a las cuentas demo,
> y desde la barra lateral puedes cambiar de cuenta con **“Ver como…”**.
## Multi-tenant y consola de administrador
AgendaMax es **multi-tenant**: cada negocio es un tenant aislado (todos los datos llevan `business_id`
y las consultas se filtran por el negocio del usuario). El **administrador de plataforma** gestiona
todos los negocios desde `/admin`:
- **Resumen**: KPIs globales (negocios activos, usuarios, ingresos y citas de toda la plataforma).
- **Negocios**: lista buscable con stats por negocio (usuarios, citas, ingresos).
- **Crear negocio** (2 pasos): eliges una **plantilla** → se cargan empleados, servicios y clientes demo
con historial de citas/tickets listos para usar; defines los datos del negocio y la cuenta del dueño.
- **Detalle de negocio**: editar nombre/industria, cambiar **plan** (Prueba/Pro/Free) y **estado**
(Activo/Suspendido), **recargar datos demo** con otra plantilla (preserva las cuentas de usuario)
o **eliminar** el negocio por completo (con cascade de todos sus datos).
**Plantillas disponibles**: `estetica-spa` (Lumière), `barberia` (Urban Cut), `clinica` (Dental Sonrisa)
y `blank` (vacío, para configurar desde cero). Defínelas en `server/lib/templates.ts`.
El aislamiento entre tenants se valida: un dueño solo ve los datos de su negocio, y los empleados
no pueden acceder al tablero ni a la gestión (403).
## Funcionalidades
### Calendario (Dueño y Empleado)
- Vistas de mes / semana / día, con indicador de hora actual.
- **En móvil** se abre por defecto en **vista Día** y se ofrece una **vista Lista** (agenda) —
la vista Semana/Mes queda reservada para tablet/desktop para evitar columnas aplastadas.
- **Arrastra** para reagendar y **redimensiona** para cambiar duración.
- Clic en un hueco o en **Nueva cita** para abrir el formulario.
- Clic en una cita para **editarla**: cambiar servicio, especialista, cliente, hora, precio, notas.
- **Marcar como completada** (genera un ticket con propina y método de pago).
- **Cancelar** o **eliminar** citas.
- Filtra por **empleado** y por **estado** (programada / completada / cancelada).
### Formulario de cita
- **Servicio** desplegable (menú del negocio), con precio y duración.
- **Especialista**: el empleado lo tiene auto-asignado por defecto (filtrado a quienes ofrecen el servicio).
- **Cliente**: buscar **existente** o crear uno **nuevo** al vuelo.
- Duración, precio y notas editables.
### Tablero (Dueño)
- KPIs: ingresos del período, citas programadas, ticket promedio, ocupación y % de cancelación.
- Gráfica de **ingresos diarios** y **distribución por categoría**.
- **Mejores empleados** por ingreso, con rating y utilización.
- **Servicios más rentables**.
- **Tickets más altos** recientes.
- **Top clientes** (por gasto) y **clientes frecuentes** (por visitas).
- Rango de tiempo ajustable (7 / 30 / 60 días).
### Gestión (Dueño)
- **Empleados**: crear, editar, asignar servicios, ver ingresos/citas/rating.
- **Servicios**: catálogo agrupado por categoría, con especialistas asignados.
- **Tickets**: historial de ventas con filtros por método de pago.
### Clientes (Dueño y Empleado)
- Buscador por nombre / teléfono / correo.
- Ficha del cliente con historial de citas, gasto total y visitas.
## Estructura
```
.
├── server/ # API Express + SQLite
│ ├── db.ts # esquema multi-tenant + sistema de migraciones versionado
│ ├── index.ts # app Express (auto-siembla admin + negocio demo en primer arranque)
│ ├── lib/auth.ts # middlewares: authRequired, ownerOnly, adminOnly
│ ├── lib/templates.ts # plantillas: estetica-spa, barberia, clinica, blank
│ ├── routes/ # auth, business, employees, services, clients, appointments, dashboard, admin
│ └── scripts/seed.ts# seedBusiness(businessId, template) reutilizable + script standalone
├── shared/types.ts # tipos TS compartidos cliente/servidor
├── src/ # frontend React
│ ├── components/ # AppShell, AdminShell, Modal, AppointmentModal, ui, DemoSwitcher, admin/CreateBusinessModal
│ ├── lib/ # api, auth, format
│ └── pages/ # Login, Dashboard, Calendar, Employees, Services, Clients, Tickets + admin/*
└── data/ # SQLite (generado, .gitignored)
```
## Notas de seguridad
Es una **demo**. La autenticación usa un token trivial (el id del usuario) sin hashing de contraseña
ni sesiones reales — **no usar en producción** tal cual. Antes de un despliegue real habría que añadir
hashing (bcrypt), JWT firmados, validación estricta con zod, rate-limiting y HTTPS.