# Guía de despliegue gratuito · Café OS

Esta guía deja las tres apps funcionando en internet, con base de datos en la nube y sin pagar hosting ni servidor. Tiempo estimado: **25–40 minutos**.

> Si solo quieres ver el sistema, usa la demo local (`INICIAR-DEMO.bat`). Para operar tu negocio, sigue esta guía.

---

## 0. Lo que vas a crear

- **Supabase Free**: Postgres + Auth + Realtime + API. Es el intermediario real entre las tres apps.
- **Cloudflare Pages** (recomendado), **Netlify** o **GitHub Pages**: hosting estático gratuito.
- **Tres URLs** (pueden ser el mismo dominio):
  - `https://tu-sitio.pages.dev/manager.html`
  - `https://tu-sitio.pages.dev/central.html`
  - `https://tu-sitio.pages.dev/cafeteria.html`

No necesitas servidor, Node, Docker ni tarjeta de crédito para el plan gratuito.

---

## 1. Crear el proyecto en Supabase

1. Entra a [supabase.com](https://supabase.com) y crea una cuenta.
2. **New project**:
   - Nombre: `cafe-os` (o el de tu negocio).
   - Contraseña de base de datos: guárdala en un lugar seguro (no se usa en el frontend).
   - Región: la más cercana a tu operación.
   - Plan: **Free**.
3. Espera a que el proyecto termine de aprovisionarse.

### Ejecutar el esquema

1. En el menú lateral entra a **SQL Editor → New query**.
2. Abre el archivo [`supabase/schema.sql`](supabase/schema.sql), copia **todo** su contenido y pégalo.
3. Pulsa **Run** (o `Ctrl + Enter`).
4. Debe terminar sin errores. Si el editor muestra solo “Success. No rows returned”, está bien.
5. Verifica en **Table Editor** que existan las tablas: `cafeterias`, `profiles`, `products`, `inventory`, `sales`, `closures`, `shipments`, `stock_requests`, etc.

El script es idempotente para una instalación nueva: crea tablas, políticas RLS, funciones, triggers y agrega las tablas a Realtime.

> Si vuelves a ejecutarlo sobre una base ya existente, no borra datos, pero tampoco migra columnas nuevas. Para cambios grandes crea una migración aparte.

### Configurar autenticación

1. Ve a **Authentication → Providers → Email**.
2. Deja habilitado **Email**.
3. **Desactiva “Confirm email”**. Es indispensable: los trabajadores usan un correo interno (`usuario@staff.cafe-os.app`) que no recibe mensajes.
4. En **Authentication → URL Configuration**, más adelante pone la URL de tu sitio en **Site URL** (por ejemplo `https://cafe-os.pages.dev`). Para probar en local puedes dejar `http://localhost:8080`.
5. Opcional: en **Authentication → Settings**, revisa la longitud mínima de contraseña (6 es suficiente para el PIN de trabajadores).

### Copiar credenciales

En **Project Settings → API** copia:

- **Project URL** → `https://xxxxx.supabase.co`
- **anon public** (clave pública) → `eyJ...`

No copies `service_role`. Esa clave salta RLS y **nunca** debe estar en el navegador.

---

## 2. Conectar las apps

Abre [`assets/js/config.js`](assets/js/config.js) y pega los datos:

```js
window.CAFE_OS_CONFIG = {
  supabaseUrl: "https://xxxxx.supabase.co",
  supabaseAnonKey: "eyJ...",
  staffEmailDomain: "staff.cafe-os.app",
  brand: "Café OS",
  demo: "auto"
};
```

Notas:

- `staffEmailDomain` es el dominio interno de las cuentas de trabajadores. **No lo cambies después de crear cuentas**: el login deriva el correo desde el usuario.
- `demo: "auto"` usa Supabase si hay credenciales y cae a demo si están vacías. Puedes forzar la demo con `?demo=1` en cualquier URL.
- La `anon key` es pública. La seguridad está en RLS.

### Probar en local con la nube

```bash
cd cafe-os
python serve.py
```

Abre `http://127.0.0.1:8080/manager.html` y crea la cuenta de gerente. Si usas local, agrega `http://127.0.0.1:8080` en **Site URL** (o ignóralo si no usas enlaces mágicos; el login por contraseña funciona igual).

---

## 3. Publicar gratis

### Opción A · Cloudflare Pages (recomendado)

**Ventajas:** plan gratis generoso, HTTPS, CDN, despliegue por arrastre o GitHub, dominio `*.pages.dev`.

1. Crea una cuenta en [dash.cloudflare.com](https://dash.cloudflare.com).
2. **Workers & Pages → Create → Pages → Upload assets**.
3. Nombre del proyecto: `cafe-os`.
4. Arrastra **el contenido** de la carpeta `cafe-os/` (no la carpeta padre). Debes ver `index.html`, `manager.html`, `assets/`, `supabase/`… en la raíz del proyecto.
5. **Deploy site**.
6. Abre la URL `https://cafe-os.pages.dev/manager.html`.

No hay comando de build; es un sitio estático. Si usas GitHub:

- Sube el contenido de `cafe-os/` a la raíz del repositorio.
- En Pages conecta el repo, **Framework preset: None**, **Build command: vacío**, **Output directory: `/`**.

### Opción B · Netlify Drop

1. Entra a [app.netlify.com/drop](https://app.netlify.com/drop).
2. Arrastra la carpeta `cafe-os` completa.
3. Te dará una URL `*.netlify.app`. Listo.

### Opción C · GitHub Pages

1. Crea un repositorio **público** y sube el contenido de `cafe-os/`.
2. **Settings → Pages → Deploy from a branch → main / (root)**.
3. Espera la URL `https://tuusuario.github.io/turepo/manager.html`.

> GitHub Pages sirve bien archivos estáticos, pero Cloudflare Pages suele ser más rápido y permite despliegues privados.

---

## 4. Crear la cuenta de gerente

1. Abre `https://tu-sitio/manager.html`.
2. Pulsa **Crear cuenta**.
3. Usa tu correo real y una contraseña segura.
4. La primera cuenta se convierte en **administradora** (función `claim_admin`).
5. Si aparece “Tu cuenta está pendiente”, ya existía un administrador. Pide que te promuevan o usa la cuenta original.

### ¿Necesitas otro administrador?

Por seguridad solo la primera cuenta se auto-promueve. Para promover otra cuenta, ejecuta en SQL Editor:

```sql
update public.profiles
set role = 'admin', active = true
where email = 'otro-correo@ejemplo.com';
```

### ¿Olvidaste la contraseña del gerente?

Supabase Auth permite enviar recuperación si tienes el correo real y el proveedor de email configurado. También puedes crear otra cuenta y promoverla por SQL, o restablecer desde **Authentication → Users**.

---

## 5. Configurar la operación

### 5.1 Crear cafeterías

**Gerencia → Cafeterías → Nueva cafetería**. Nombre, código, dirección, teléfono. El código debe ser único (por ejemplo `C-01`).

### 5.2 Crear catálogo

**Gerencia → Catálogo → Nuevo producto**:

- SKU único.
- Categoría, unidad.
- Costo y precio de venta.
- El producto nace activo y con stock de almacén en 0.

Puedes ajustar el precio por sucursal con el icono de etiqueta.

### 5.3 Cargar stock inicial

Dos caminos:

1. **Central → Almacén → Registrar entrada**: suma mercancía al almacén central (compras a proveedores). Luego despacha a cada local.
2. **Gerencia → Inventario → Ajustar stock**: define directamente la cantidad inicial de un producto en una cafetería (con motivo). Útil para arrancar sin despacho.

### 5.4 Invitar personal

**Gerencia → Equipo → Generar invitación**:

- **Trabajador de cafetería**: elige el local. La persona recibe un código.
- **Central / bodega**: sin local; podrá ver todos los locales.

El código es de un solo uso, vence en los días indicados y se puede revocar.

#### Canje del trabajador

1. Abre `cafeteria.html`.
2. Pestaña **Primer ingreso**.
3. Código + nombre + **usuario** (por ejemplo `maria.gomez`) + **PIN de 6+ caracteres**.
4. Al confirmar, inicia sesión automáticamente.

El usuario debe ser único en toda la base de datos. Si quieres otro local para la misma persona, crea otra cuenta con otro usuario (el historial queda separado).

#### Canje de Central

1. Abre `central.html`.
2. **Primer ingreso**.
3. Código + nombre + correo real + contraseña.

---

## 6. Probar el ciclo completo

1. **Central → Almacén**: registra entrada de un producto.
2. **Central → Despachos → Nuevo despacho**: elige cafetería y cantidades.
3. **Cafetería → Recepciones**: abre el despacho y confirma cantidades.
4. **Cafetería → Vender**:
   - Abre turno con fondo inicial.
   - Agrega productos y cobra (efectivo, transferencia o mixto).
5. **Cafetería → Cierre de caja**:
   - Registra un gasto si aplica.
   - **Comenzar cierre** → nombre → conteo por denominaciones → transferencia → revisar → cerrar.
6. **Gerencia → Cierres**: revisa el resultado y márcalo como revisado.
7. **Central → Solicitudes**: verás las solicitudes de reposición que haga la cafetería.

---

## 7. Cómo funcionan los datos importantes

### Cierre y diferencias

- `expected_cash = opening_cash + ventas_efectivo + ingresos_extra − gastos_caja`
- `expected_transfer = ventas_transferencia`
- `counted_cash = Σ(denominación × cantidad)`
- `counted_transfer` lo reporta el trabajador.
- `diferencia = contado − esperado`, por medio y total.
- Si la diferencia está dentro de la tolerancia configurada (por defecto 0), el cierre es **cuadrado**; si no, **descuadre** y exige nota.

Todo se recalcula en PostgreSQL (`close_shift`), no se confía en los totales del navegador.

### Inventario

- Venta: descuenta `inventory` de la cafetería y registra `stock_movements`.
- Recepción de despacho: suma inventario, actualiza `shipment_items.cantidad_recibida`.
- Recepción directa: suma inventario sin pasar por almacén.
- Ajuste de gerencia/central: fija cantidad y deja trazabilidad.
- El stock puede quedar negativo si una venta ocurrió con datos desactualizados; se marca para revisión. La venta nunca se pierde.

### Despachos

- `dispatch_shipment` descuenta almacén, crea el despacho y lo deja **enviada**.
- La cafetería confirma; si recibe menos, queda **parcial** (puede completar después).
- Cancelar un despacho devuelve la mercancía al almacén.

### Ventas offline

- Se guardan en `localStorage` del dispositivo (`cafeos_outbox_v1_…`).
- La venta local descuenta inventario visualmente.
- Al volver internet se envían con un `client_uuid` idempotente: si se reintenta, no se duplica.
- Mientras haya pendientes:
  - Se muestra un aviso.
  - El cierre está bloqueado.
  - Se sincroniza al volver la conexión o manualmente.
- Si se cierra el navegador sin conexión, la cola se conserva en ese equipo. **No borres los datos del navegador** hasta sincronizar.

---

## 8. Seguridad y roles

| Rol | Acceso |
|---|---|
| `admin` | Todo. Único que gestiona equipo, locales y ajustes. |
| `central` | Almacén, despachos, solicitudes, ver ventas/cierres de todos los locales. No gestiona usuarios ni ajustes. |
| `worker` | Solo su cafetería: vender, recibir, inventario, caja. |
| `pending` | Sin acceso a datos. |

- Todas las tablas tienen **RLS activado**.
- Los datos se filtran por `auth_cafeteria()`.
- Las operaciones críticas son funciones `security definer` con validación de rol y transacciones atómicas.
- El frontend nunca recibe la clave `service_role`.
- La primera cuenta se auto-promueve a admin: publica y crea tu cuenta de inmediato.

### Recomendaciones

- Usa contraseñas largas para gerencia y bodega.
- Comparte los códigos de invitación por un canal privado.
- Revoca invitaciones no usadas.
- Desactiva cuentas de personas que salen (no borra su historial).
- Descarga un respaldo JSON periódicamente desde **Gerencia → Ajustes**.
- Configura un backup de la base en Supabase (el plan Free incluye backups básicos limitados; revisa el panel).

---

## 9. Personalización

- **Nombre del negocio, moneda, locale, zona horaria y tolerancia:** Gerencia → Ajustes. Se comparte con las tres apps.
- **Denominaciones:** `assets/js/constants.js` y la función `close_shift` en `supabase/schema.sql` deben tener la misma lista.
- **Colores/tipografía:** variables `:root` al inicio de `assets/css/app.css`.
- **Dominio de usuarios de cafetería:** `staffEmailDomain` en `assets/js/config.js`. No lo cambies con cuentas creadas.
- **Textos y flujos:** módulos `manager.js`, `central.js`, `cafeteria.js`.
- **PWA:** cambia `VERSION` en `sw.js` cuando publiques cambios importantes para forzar la actualización de caché.

---

## 10. Solución de problemas

| Síntoma | Causa probable | Solución |
|---|---|---|
| Página en blanco con el logo “Preparando…” | Abriste el HTML con `file://` o falló la carga de módulos. | Usa `INICIAR-DEMO.bat` / `python serve.py` o la URL publicada. Revisa la consola. |
| “No se pudo conectar con la nube” | URL/clave incorrecta, sin internet o proyecto pausado. | Revisa `config.js`, reactiva el proyecto en Supabase. |
| “Invalid API key” | Copiaste mal la anon key. | Vuelve a copiarla desde Project Settings → API. |
| “Tu cuenta está pendiente” | Ya existe un admin y tu cuenta no tenía invitación. | Promueve por SQL o usa una invitación. |
| “Debes confirmar tu correo” | Confirm email sigue activo. | Authentication → Providers → Email → desactiva Confirm email. |
| “El código no existe / expiró / ya fue usado” | Invitación vencida, revocada o consumida. | Genera una nueva en Equipo. |
| “Ese usuario ya está en uso” | El usuario debe ser único global. | Elige otro usuario. |
| No carga el inventario / errores de permisos | El SQL no se ejecutó completo o la cuenta no tiene cafetería. | Ejecuta el schema completo y asigna cafetería al trabajador. |
| Realtime no actualiza | La tabla no está en la publicación. | Ejecuta de nuevo la sección Realtime del schema o revisa Database → Replication. |
| El cierre está bloqueado | Hay ventas offline pendientes. | Pulsa “Sincronizar ahora” con internet. |
| “La caja no coincide” | Faltante/sobrante real o gasto no registrado. | Revisa el conteo, registra gastos, o explica la diferencia. |
| La app se ve vieja después de actualizar | Caché del service worker. | Recarga forzada (`Ctrl+Shift+R`) o sube `VERSION` en `sw.js`. |
| El trabajador olvidó su PIN | Las cuentas de caja usan correo sintético, no pueden recuperar por email. | Desactiva la cuenta y genera una nueva invitación con otro usuario. El historial anterior se conserva. |
| No se ven los datos de prueba | Se borró `localStorage`. | La demo se regenera al recargar; en producción los datos están en Supabase. |

---

## 11. Límites del plan gratuito y cuándo escalar

- Supabase Free incluye base de datos, Auth y Realtime con límites de almacenamiento, filas/API y usuarios activos. Los valores cambian; consulta [supabase.com/pricing](https://supabase.com/pricing).
- Los proyectos gratuitos pueden **pausarse por inactividad**. Se reactivan desde el panel; para un negocio en operación diaria normalmente hay actividad.
- Cloudflare Pages / Netlify / GitHub Pages tienen límites de ancho de banda y despliegues gratuitos suficientes para un negocio pequeño.
- Si creces a muchos locales o miles de ventas diarias:
  - Supabase Pro elimina la pausa y amplía límites.
  - Considera vistas agregadas/materializadas para reportes.
  - Configura backups automáticos y monitoreo.

---

## 12. Actualizar el sistema

1. Guarda una copia de tus cambios locales.
2. Reemplaza los archivos estáticos en el hosting (o haz push al repositorio).
3. Si cambiaste `sw.js` o CSS/JS crítico, incrementa `VERSION` en `sw.js`.
4. Si cambias el esquema, crea un script de migración y ejecútalo antes de desplegar el frontend.
5. Prueba en la demo y en un local de prueba antes de tocar producción.

---

## 13. Checklist de lanzamiento

- [ ] Proyecto Supabase creado.
- [ ] `schema.sql` ejecutado sin errores.
- [ ] “Confirm email” desactivado.
- [ ] `config.js` con URL y anon key.
- [ ] Sitio publicado con HTTPS.
- [ ] Cuenta de gerente creada.
- [ ] Nombre, moneda y zona horaria configurados.
- [ ] Cafeterías y catálogo cargados.
- [ ] Stock inicial en almacén o inventario.
- [ ] Invitaciones entregadas a trabajadores y bodega.
- [ ] Ciclo de prueba: despacho → recepción → venta → cierre → revisión.
- [ ] Respaldo JSON descargado.
- [ ] URL y credenciales guardadas en un lugar seguro.

---

¿Listo? Abre **`manager.html`**, crea tu operación y empieza a operar. ☕
