Multi-restaurante de verdad: cómo modelamos cadenas y franquicias
Una de las primeras cosas que vimos en las entrevistas fue que muchas operaciones tienen más de un local. No hablamos solo de cadenas grandes; hablamos de un grupo familiar con dos asadores y una cervecería, o de una franquicia pequeña con tres locales en la misma ciudad. Si el software te obliga a crear una cuenta por sitio y reescribir los datos cada vez, te sale gratis odiarlo.
Por eso, en octubre, dedicamos un par de semanas a un tema que parece interno y aburrido pero que define el techo del producto: cómo modelamos los datos.
Workspace, restaurante, miembros
El núcleo del modelo gira alrededor de tres entidades:
- Workspace. Es el contenedor de una organización. Un grupo hostelero, una franquicia, o simplemente un restaurante independiente que se queda con un solo workspace.
- Restaurante. Cada local físico. Un workspace puede tener uno o varios.
- Miembros. Personas con acceso. Un encargado puede tener visibilidad de los tres restaurantes del grupo; un camarero, solo del suyo.
La gracia es que la relación es real: si añades un cliente desde el local A y luego visita el local B del mismo grupo, el equipo del B sabe que es habitual de la casa. La ficha de cliente vive a nivel de workspace, no de restaurante. Eso abre puertas para fidelización cruzada que veremos más adelante.
RLS: la red de seguridad
Aquí es donde entra el Row Level Security de Postgres. En lugar de filtrar "WHERE workspace_id = X" en cada consulta del backend (y rezar para que ningún becario se olvide), las propias políticas de la base de datos impiden que un usuario lea datos que no son suyos. Aunque el código de aplicación tenga un bug, la base de datos no le va a devolver nada.
Esto fue costoso de configurar bien. Hicimos:
- Una política por tabla, restrictiva por defecto.
- Un script de auditoría (
npm run audit:cross-restaurant) que recorre las tablas y verifica que ninguna se quedó sin políticas. - Migraciones explícitas con tests manuales: crear dos workspaces, intentar leer datos del otro, comprobar que devuelve cero filas.
Lo que cuesta esta decisión
No es gratis. Multi-tenant desde el día 1 implica:
- Toda consulta lleva un workspace_id. Olvidarte uno es un bug de seguridad, no un bug funcional.
- Los índices de la base de datos hay que diseñarlos pensando en este filtro extra.
- El cambio de restaurante en la interfaz tiene que ser instantáneo y no perder estado.
Pero a cambio, evitamos lo que vimos pasar a competidores: empezar mono-tenant y, cuando llega el primer cliente con tres locales, reescribir medio producto.
Cómo se ve para el usuario
Toda esta complejidad termina en un detalle muy pequeño en la interfaz: un selector de restaurante arriba a la izquierda. Pulsas, cambias de local, y todo lo que ves se ajusta. La parte difícil queda escondida; que es como debe ser.