FloCafe
FloCafe is the free, local-first restaurant POS in the FloPOS ecosystem. Run orders, tables, kitchen display, and local data without a software subscription.
Generate and print product labels for a selected store and product
AI summary · website content
CommerceJavaScript · HTMLGitHub @KeneQuirosMOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗Suite web para gestión de inventario, etiquetas de bodega, almacén físico, manifiestos, alistamiento, devoluciones, conteos de mercancía y trazabilidad. Todo centralizado en una sola base de datos de tiendas y productos.
Frontend: HTML/CSS/JS vanilla (sin frameworks, sin build ni bundler)
Backend: Vercel Serverless Functions (Node.js ESM)
Base de datos: Supabase PostgreSQL (30 tablas) + Supabase Storage (fotos de conteos y recepciones)
Deploy: Vercel (producción automática desde main)
Cada módulo es una página independiente (HTML + JS + CSS propios). Solo comparten el código de public/shared/. Todos se abren desde el menú lateral del generador de etiquetas.
/)auto (Halloween del 1 de oct al 2 de nov, Navidad del 3 de nov al 6 de ene), halloween, navidad o ninguna/stockforge/almacen4.html)productos.ubicacion → el QR de la etiqueta se actualiza solo/manifiesto/manifiesto.html)localStorage (hasta 24 h): si la pestaña se recarga o se cierra, se ofrece continuar donde se quedó/alistamiento/alistamiento.html)pdf-lib, sin regenerarlas)/devoluciones/devoluciones.html)devoluciones_registro con la fecha del día. El conteo por día/semana/mes se consulta en el Panel de Coordinador, pestaña "Devoluciones"/conteos/conteos.html)conteos; la foto se comprime en el navegador y se sube al bucket privado conteos de Supabase Storagegoogle/, instalación en google/README.md). Los que fallen quedan pendientes y se reenvían con "Enviar pendientes"--kiosk-printing imprime sin cuadro de diálogo (pasos en la propia pestaña)trasladar_parcial_conteo. Queda historial en conteos_traslados, la fila de Google Sheets se mueve a la pestaña nueva y se genera el mensaje para WhatsApp. Si se pide imprimir al trasladar, la estación imprime la etiqueta nueva/recepcion/recepcion.html)recepciones (vía POST /api/conteos?accion=recepcion); la foto va al bucket conteos, carpeta recepciones//trazabilidad.html)/api/tiendas para el filtro de tiendas)/reporte/reporte_distribuidor_proveedor.html)/mercado/mercado.html)La BD tiene 30 tablas en Supabase PostgreSQL. Todas tienen RLS activado y ninguna política: con la anon key o el JWT de un usuario no se puede leer ni escribir ninguna tabla ni ejecutar ninguna función directamente. Toda lectura y escritura pasa por la API (api/*.js), que usa la service role y aplica perfiles y permisos. Las tablas principales tampoco conceden INSERT/UPDATE/DELETE/TRUNCATE a anon ni authenticated, y las funciones solo las ejecuta service_role (con search_path fijo). El estado aplicado en producción y la regla para cambios están en supabase/ESTADO_PRODUCCION.md.
Core (etiquetas e inventario) — supabase-schema.sql:
tiendas — catálogo de tiendasproductos — inventario por tienda (codigo, nombre, ubicacion)configuracion — logos y ajustes clave-valor (escritos con la función upsert_config)STOCKFORGE (almacén físico) — supabase-schema.sql:
zonas, racks, celdas — estructura física del almacénskus — productos en celdas (vinculados a productos vía producto_id)responsables, rack_responsables, rack_tiendas — asignacionescelda_responsables, celda_tiendas — asignaciones por celdaaudits, changelog — trazabilidadmovimientos — historial de trasladosbodega_config — configuración global del almacénEl guardado del almacén reemplaza el estado completo en una sola transacción con la función replace_warehouse_state (supabase/replace_warehouse_state.sql).
Devoluciones — supabase/devoluciones_registro.sql:
devoluciones_registro — una fila por guía devuelta (guia, fecha). El mismo script define la función devoluciones_por_diaConteos — supabase/conteos.sql:
conteos — un registro por conteo de mercancía. El script también crea el bucket privado conteos para las fotos y la función trasladar_parcial_conteoconteos_traslados — historial de traslados de conteos entre tiendas/IDs (quién, cuándo, de dónde a dónde)Recepciones — supabase/recepciones.sql:
recepciones — una fila por recepción de mercancía (tienda, cajas, recibido por, foto, fecha y hora del servidor) y su seguimiento: llegada del ajuste de inventario y cierre (quién y cuándo)Dispositivos vinculados — supabase/dispositivos.sql:
dispositivos — equipos autorizados a enviar Conteos y Devoluciones (nombre y hash de su credencial). Sin acceso público: solo la API la leeMercado y Alistamiento — supabase/mercado.sql (sin acceso público: solo la API, porque guarda nombres de clientes):
mercado_cortes — encabezado de cada corte (fecha, horario, archivo, responsables, personas, totales, BASE, validación)mercado_lineas — el mercado: una fila por artículo y ubicación con su cantidadmercado_guias — el alistamiento: una fila por guía y artículo, con destinatariomercado_asignaciones — qué persona hizo cada tienda en cada cortemercado_alistado — artículos marcados como alistados (quién y cuándo)mercado_inventarios, mercado_ubicaciones, mercado_ubicaciones_cargas — tiendas (nombre corto, persona habitual) y tablas de ubicacionesmercado_guardar_corte, mercado_asignar, mercado_historial y mercado_reemplazar_ubicaciones. Al final del archivo hay consultas de auditoría de ejemplo (unidades y guías por persona, por tienda y día, buscar una guía)El campo skus.producto_id vincula STOCKFORGE con el catálogo de etiquetas. Cuando un SKU tiene producto_id, al guardar el almacén se actualiza automáticamente productos.ubicacion con la posición física.
No hay sistema de migraciones: todos los .sql se ejecutan a mano en el SQL Editor de Supabase. Si se modifica uno, hay que volver a ejecutarlo; todos se pueden ejecutar varias veces sin reabrir nada. Antes de ejecutar cualquier .sql en producción: respaldo + supabase/remediacion/etapa1/06_VERIFICACION.sql antes y después.
effi-etiquetas/
├── api/
│ ├── _supabase.js # cliente Supabase admin compartido
│ ├── _cors.js # CORS centralizado (env var ALLOWED_ORIGIN)
│ ├── _auth.js # requireUser(): valida el token del coordinador
│ ├── _rateLimit.js # rate limit en memoria para endpoints públicos
│ ├── _sheets.js # envío opcional de conteos a Google Sheets
│ ├── auth.js # login con Supabase Auth
│ ├── refresh.js # renovar token JWT (auto-refresh en frontend)
│ ├── change-password.js # cambio de contraseña del coordinador
│ ├── users.js # listar/crear/eliminar coordinadores
│ ├── config.js # GET/POST logos y configuración
│ ├── tiendas.js # CRUD tiendas + inventario completo
│ ├── productos.js # CRUD productos
│ ├── stockforge.js # estado completo del almacén (auth en POST)
│ ├── devoluciones.js # registro y conteo diario de guías devueltas
│ ├── conteos.js # conteos: alta, consulta, traslado, impresión, Sheets
│ └── mercado.js # mercado y alistamiento: cortes, asignaciones, avance, ubicaciones
├── public/
│ ├── index.html/js/css # generador de etiquetas + panel de coordinador ("/")
│ ├── decoracion.js # decoración de temporada
│ ├── navidad.css # tema Navidad (solo pantalla)
│ ├── halloween.css # tema Halloween (solo pantalla)
│ ├── trazabilidad.html # trazabilidad de inventario (archivo único)
│ ├── shared/
│ │ ├── api.js # capa HTTP compartida (fetch + JSON + errores)
│ │ ├── dom-utils.js # esc(), notify(), STORAGE_KEYS, guard de sesión
│ │ └── tokens.css # colores compartidos y foco accesible
│ ├── stockforge/
│ │ └── almacen4.html/js/css # STOCKFORGE (mapa de almacén)
│ ├── manifiesto/
│ │ ├── manifiesto.html/js/css
│ │ ├── manifiesto-scan-ui.js # capa visual del escaneo
│ │ ├── manifiesto-sesion.js # avance guardado
│ │ └── manifiesto-guardas.js # protección de modales contra la pistola
│ ├── alistamiento/
│ │ └── alistamiento.html/js/css
│ ├── devoluciones/
│ │ └── devoluciones.html/js/css
│ ├── conteos/
│ │ └── conteos.html/js/css # pantalla móvil pública
│ └── reporte/
│ ├── reporte_distribuidor_proveedor.html
│ └── reporte.css/js
├── supabase/
│ ├── replace_warehouse_state.sql # función de guardado completo de STOCKFORGE
│ ├── devoluciones_registro.sql # tabla + función devoluciones_por_dia
│ ├── conteos.sql # tablas, bucket y trasladar_parcial_conteo
│ ├── dispositivos.sql # dispositivos vinculados por QR
│ ├── ESTADO_PRODUCCION.md # estado de seguridad aplicado y regla para cambios
│ └── remediacion/etapa1/ # scripts de referencia, reversión y 06_VERIFICACION.sql
├── google/
│ ├── conteos-sheets.gs # Apps Script receptor de conteos
│ └── README.md # instalación de la copia a Google Sheets
├── .env.example # variables requeridas documentadas
├── package.json
├── supabase-schema.sql # schema base (16 tablas + RLS + upsert_config)
└── vercel.json # rewrites para servir /public como raíz + headers de seguridad (CSP)
| Rol | Acceso | Puede |
|---|---|---|
| Usuario | Sin login | Ver inventario, imprimir etiquetas, usar Manifiestos, Alistamiento, Devoluciones, Trazabilidad y registrar Conteos |
| Coordinador | Login email + contraseña | Todo lo anterior, más: crear/editar/eliminar tiendas y productos, subir logos, configuración, gestionar coordinadores, cambiar contraseña, ver devoluciones y conteos, trasladar conteos, estación de impresión, Reporte Distribuidor y editar STOCKFORGE, según los permisos de su perfil |
Cada cuenta del modo coordinador tiene un perfil: administrador (todo), coordinador o bodeguero. El administrador decide en "Usuarios y permisos" qué puede hacer cada perfil; la API lo comprueba en cada petición.
El coordinador usa el mismo usuario en el generador de etiquetas y en STOCKFORGE, pero cada uno mantiene su propia sesión: iniciar sesión en uno no inicia sesión en el otro. El generador guarda la sesión en localStorage (persiste entre pestañas); STOCKFORGE en sessionStorage (se borra al cerrar la pestaña). En ambos el token JWT se auto-renueva al expirar sin cerrar sesión.
supabase-schema.sqlsupabase/replace_warehouse_state.sqlsupabase/devoluciones_registro.sqlsupabase/conteos.sqlsupabase/dispositivos.sqlsupabase/mercado.sqlSUPABASE_URLanon public key → SUPABASE_ANON_KEYservice_role key → SUPABASE_SERVICE_ROLE_KEYCopiar .env.example a .env:
SUPABASE_URL=https://xxxx.supabase.co
SUPABASE_ANON_KEY=eyJxxx...
SUPABASE_SERVICE_ROLE_KEY=eyJxxx...
ALLOWED_ORIGIN=https://tu-proyecto.vercel.app,https://tu-dominio-custom.com
# Opcionales (copia de conteos a Google Sheets, ver google/README.md)
SHEETS_WEBHOOK_URL=
SHEETS_WEBHOOK_SECRET=
ALLOWED_ORIGINacepta una lista separada por comas (útil para permitir a la vez el dominio de producción y los dominios de preview de Vercel). No hay wildcard: si el origen de la petición no está en la lista, el navegador bloquea la respuesta cross-origin. En desarrollo local (vercel dev, mismo origen para frontend y API) no hace falta configurarla.
Desde JSON exportado: Coordinador → Configuración → Importar JSON (procesa en lotes de 10, mucho más rápido que uno por uno)
npm install -g vercel
vercel dev
Abre http://localhost:3000. No hay build ni linter: vercel dev sirve /public y /api en el mismo origen contra un proyecto real de Supabase.
Pruebas del cálculo de Mercado y Alistamiento (no necesitan Supabase):
npm install
npm test
Usan exports reales sin datos personales en tests/fixtures/ y comparan contra las tablas dinámicas de la hoja original. Para agregar otro export como caso de prueba, quítale los datos personales con node tests/anonimizar.mjs <entrada.xlsx> tests/fixtures/<nombre>.xlsx. El caso obligatorio CORTE031110.xlsx (503 unidades en 320 filas; PRIVADO ALI CR, ID 29 = 176 unidades en 86 filas) se salta hasta que el archivo esté en tests/fixtures/.
localStorage. Si no hay conexión, muestra el último inventario conocido.index.js, sin CDN).localStorage como caché. Carga desde caché primero y luego sincroniza con el servidor en segundo plano.productos.ubicacion). Valida el body antes de reemplazar el estado, lo hace en una sola transacción (replace_warehouse_state) y deja el guardado en la bitácora.auth, refresh, devoluciones, conteos) tienen rate limit en memoria por instancia: es una primera barrera, no un límite garantizado.api/ sin _ al inicio) por despliegue; con una más el despliegue falla y producción se queda en la versión anterior. Hoy hay 12. Para agregar un endpoint, súmalo como ?accion= a uno existente. (reporte-tiendas.js, que nadie usaba, se quitó por eso; está en el historial de git.)public/shared/api.js centraliza el fetch + parseo JSON + manejo de errores. Cada módulo conserva su propia lógica de autenticación/renovación de token.esc() antes de ir a innerHTML para prevenir XSS almacenado.vercel.json. Para agregar un script, hoja de estilos o fuente de otro CDN hay que añadir su origen a la directiva correspondiente o el navegador lo bloqueará en producción.