# Gustito Xpress

Sistema operativo para negocios de comida en Venezuela: el pedido nace en el
telefono del cliente o en la mano del mesero, suena en la cocina, se acumula en
la mesa, se cobra (junto o por partes), sale en la moto con GPS en vivo y
**termina en una factura fiscal sellada**. Cada negocio vende con SU marca, su
menu y su propio delivery.

> Proyecto independiente. No comparte codigo, base de datos ni cuentas con ningun otro proyecto.

## Que resuelve

| Frente | Que hace |
|---|---|
| **Tienda en linea** | Catalogo por negocio con su marca y su enlace propio, carrito, checkout y seguimiento |
| **Servicio en mesa** | QR por mesa, cuenta que se acumula, recuperar la cuenta al re-escanear, pago desde la mesa |
| **Modo mesero** | El equipo de sala entra con su usuario, toma pedidos y cobra; cada pedido queda firmado con su nombre |
| **Cuentas separadas** | El grupo paga por partes: se cobran pedidos sueltos y la mesa se libera cuando el saldo llega a cero |
| **Cocina (KDS)** | Pantalla con cronometro, opciones y contornos por plato |
| **Punto de venta** | Toma de pedidos en caja con personalizacion y asignacion de repartidor |
| **Delivery** | Reparto propio con GPS en vivo (Realtime Broadcast) y mapa para el cliente |
| **Pagos** | Pago Movil con comprobante adjunto y verificacion del negocio; multimoneda con tasa BCV automatica |
| **Gestion** | Caja, inventario, clientes, estadisticas y reporte de cierre del dia |
| **Avisos** | Web Push (VAPID) al encargado y al repartidor, con la app cerrada |
| **Facturacion fiscal** | Programa instalable que lleva el libro del negocio, numera, calcula el IVA, transmite a la imprenta digital y entrega la factura en papel, pantalla y correo (PDF) |
| **Impresion local** | Puente que manda comandas y facturas a las impresoras del local, con la caja funcionando sin internet |

## Arquitectura

Monorepo (npm workspaces). Tres aplicaciones web contra un backend Supabase,
mas la pata fiscal, que es un programa **instalado en el negocio** por exigencia
normativa.

```
apps/
  cliente/          Comensal: menu, carrito, checkout, mesa, seguimiento en mapa  (PWA)
  restaurante/      Landing + panel del negocio: pedidos, cocina, mesas, POS, caja
  repartidor/       Motorizado: pedido asignado, GPS en vivo, entrega             (PWA)
  fiscal/           Estacion Fiscal: libro sellado, IVA, transmision, factura     (exe Windows)
  cerebrito/        Puente de impresion del local (termicas USB y de red)         (exe Windows)
  validador/        Imprenta digital: numeracion, sello del QR, panel, correo     (Cloudflare Pages)
  instalador/       Instaladores nativos, uno por producto                        (C#, ~23 KB)
  respaldo-imprenta/ Respaldo cifrado del esquema fiscal a R2, fuera del proveedor (Worker)
packages/
  shared/           Cliente Supabase tipado, tipos, estados del pedido, utils
supabase/
  migrations/       Esquema, RLS y funciones (fuente de verdad del backend)
  functions/        Edge Functions (push, importar menu con IA, tasa BCV, equipo)
scripts/            Verificaciones end to end contra la base viva
```

### Decisiones clave

- **La regla de negocio vive en la base de datos, no en la pantalla.** Horario,
  precios, anti-duplicado, una sola cuenta activa por mesa, un pedido se cobra
  una sola vez: todo son candados en Postgres. El frontend es solo la cara amable.
- **Operaciones criticas por RPC atomica** (crear pedido, cobrar parte de la
  cuenta, confirmar pago, asignar repartidor) para evitar condiciones de carrera.
- **La identidad se estampa del lado del servidor**: quien toma un pedido sale de
  `auth.uid()` dentro de la funcion, no de lo que mande la app.
- **Roles con RLS estricto**: el dueño administra; el encargado opera sin ver la
  plata; el mesero opera la sala; el repartidor solo ve lo suyo.
- **GPS por Realtime Broadcast**, no por escrituras a la base: el repartidor
  emite su posicion por un canal efimero y solo se persisten hitos.
- **Frontend estatico** (Vite + React + TS + Tailwind): escala por CDN.
- **Mapas con MapLibre + OpenStreetMap** (sin API key de pago).
- **Nada con forma de token vive en el repo**: las llaves van en `.env` local,
  en los secretos de las Edge Functions, en Vault (para triggers) o en las
  variables del proyecto de Cloudflare Pages.

### La frontera fiscal (lo que decide el diseño de `apps/fiscal`)

Lo fiscal **no vive en la nube de Gustito**. Vive dentro de un programa instalado
en el negocio, atado a un solo RIF, porque asi lo exige el marco normativo
venezolano (Providencias SNAT/2024/000121 y SNAT/2024/000102).

- **Gustito manda la venta y recibe el numero. Nunca escribe en el libro fiscal.**
  Ni calcula, ni muestra, ni reporta impuesto. Si esa frontera se rompe, habria
  que homologar la aplicacion entera.
- **Libro de solo agregado con hash encadenado**: nada se edita ni se borra. La
  correccion es siempre por nota de credito o debito ligada al original.
- **Numeracion ciega**: la lleva el libro por tipo de documento, sin saltos ni
  repeticiones. Ninguna pantalla permite escogerla.
- **La anulacion viaja como solicitud** por la cola: el panel la pide con su
  motivo y la Estacion emite la nota; una venta ya facturada que se cancela
  genera su nota de credito sola.
- **Reloj custodiado**: si la hora del equipo esta alterada, no se sella (la
  venta espera en el buzon, no se pierde).
- **Respaldo cifrado fuera del equipo** a los segundos de cada asiento, con
  frase de recuperacion que solo tiene el negocio, y restauracion probada.
- **El programa no se auto-actualiza**: cada version se homologa antes de
  instalarse (arts. 9 al 11). El canal de versiones solo avisa.
- **Tres vias de entrada** para que cualquier sistema de ventas pueda facturar:
  cola en la nube, API local en `127.0.0.1` con llave de maquina, y buzon de
  carpeta (un JSON depositado en `intercambio/entrada`) para los administrativos
  que no integran por API. Contrato en `apps/fiscal/GUIA_INTEGRACION.md`.

## Correr en local

Requisitos: Node >= 20, Docker Desktop corriendo.

```bash
npm install                 # instala todo el monorepo
npm run db:start            # levanta Supabase local (Docker)
npm run db:reset            # aplica migraciones + seed
npm run db:types            # genera los tipos TS desde la BD

npm run dev:cliente         # http://localhost:5173
npm run dev:restaurante     # http://localhost:5174
npm run dev:repartidor      # http://localhost:5175
```

Crea un `.env` en la raiz con `VITE_SUPABASE_URL` y `VITE_SUPABASE_ANON_KEY`
(los imprime `supabase start`).

Los programas instalables se levantan y empaquetan aparte:

```bash
npm run build --workspace apps/fiscal      # compila la Estacion
npm run start --workspace apps/fiscal      # http://127.0.0.1:8739
npm run empaquetar --workspace apps/fiscal # exe autonomo (Node SEA)
```

## Validar

```bash
npm run typecheck           # todos los paquetes
npm run build               # build de las 3 apps web

npm run prueba --workspace apps/fiscal     # suite de la Estacion Fiscal
npm run prueba --workspace apps/cerebrito  # suite del puente de impresion

node scripts/test_mesero.mjs             # modo mesero (identidad y candados de rol)
node scripts/test_cuentas_separadas.mjs  # cobro por partes (doble cobro, saldos)
node scripts/test_interruptor_fiscal.mjs # habilitacion, cola de sellado y breaker
node scripts/test_anulacion_fiscal.mjs   # solicitudes de anulacion y notas de credito
```

Los scripts de `scripts/` corren **contra la base viva** y limpian lo que crean.
Necesitan `SUPABASE_URL`, `SUPABASE_ANON_KEY` y `SUPABASE_SERVICE_KEY` en el
entorno.

> Regla dura de los scripts vivos: usan el RIF de pruebas, nunca el de un cliente
> real, y abortan si el emisor tiene libro respaldado en la nube. Su limpieza
> borra el emisor completo.

## Convenciones

- **Idioma:** todo en español (codigo, tablas, columnas y textos de la interfaz).
  En lo fiscal, ademas, lenguaje de expediente: formal pero claro.
- **Migraciones:** se aplican por el SQL endpoint de la Management API, no con
  `db push`. La base viva es la fuente de verdad; despues de cada migracion hay
  que regenerar `packages/shared/src/database.types.ts`.
- **Deploy:** manual con wrangler a Cloudflare Pages (no hay auto-deploy). Los
  proyectos con Pages Functions se despliegan desde la carpeta de la app.
- **Edge Functions:** cada una necesita su entrada en `supabase/config.toml`.
- **Documentacion de la pata fiscal:** `apps/fiscal/MEMORIA_TECNICA.md` (como
  cumple cada requisito), `MANUAL_USUARIO.md`, `GUIA_INTEGRACION.md` y
  `COTEJO_ART7.md` (la factura, requisito por requisito). Se actualizan en el
  mismo commit que cambia el comportamiento.
