# Plan de implementación — Multi-tenant labSoft

> **Estado:** MT-0 y **MT-1** implementados (datos + backoffice provisión).  
> MT-2…MT-3 y onboarding dueño pendientes (`PLAN_ONBOARDING.md`).  
> **Fecha:** 2026-07-23 · actualizado 2026-07-28  


> **Producto:** labSoft (LIMS SaaS)  
> **Relacionado:** decisiones técnicas base en `PLAN_ACTUALIZACION.md` (Fases 2–3);  
> contexto actual en `ANALISIS_CONTEXTO.md`.

Este documento detalla **qué se construye** en multi-tenant desde el punto de vista de
producto y UX, con foco en:

1. **Backoffice del creador/vendedor** (tú) — operación comercial del SaaS.
2. **Configuración del dueño del laboratorio** — datos del tenant, preferencias y
   **sucursales**.

No sustituye `PLAN_ACTUALIZACION.md` (fases técnicas, stack, bitácora); lo **complementa**
con el mapa de pantallas, flujos y reglas de negocio del aislamiento por tenant.

---

## 1. Objetivo de producto

Convertir labSoft de un LIMS **single-tenant** (un solo laboratorio en la BD) a un
**SaaS multi-tenant** donde:

| Actor | Quién es | Qué hace |
|-------|----------|----------|
| **Creador / vendedor** | Tú (operador del producto) | Alta/baja de laboratorios (tenants), soporte, visión global, estado comercial |
| **Dueño del laboratorio** | Cliente que te contrata | Configura su lab, sucursales, catálogo, personal y opera el día a día |
| **Personal del lab** | Empleados y laboratoristas | Venden, capturan resultados, entregan — siempre **dentro de un solo tenant** |

**Regla de oro:** un usuario de laboratorio **nunca** ve ni modifica datos de otro
laboratorio. El vendedor **sí** ve el listado de tenants y métricas agregadas, pero
**no** opera el POS ni la captura clínica de un tenant como si fuera staff (salvo
impersonación opcional y auditada, si se decide más adelante).

---

## 2. Decisiones ya cerradas (no reabrir sin motivo)

| Tema | Decisión |
|------|----------|
| Modelo de datos | **Una sola BD MySQL** + columna `tenant_id` en tablas de negocio |
| Resolución de tenant | **Login global** por `username` (Shield); el tenant sale del usuario, no de subdominio |
| Alta de laboratorios | **Superadmin** (asistida) y, cuando se implemente, **self-signup trial** desde landing (`PLAN_LANDING_REGISTRO.md`). Sin pagos automáticos en v1 del signup. |
| Super-admin | Grupo Shield `superadmin`, `users.tenant_id = NULL` |
| Dueño del lab | Grupo `admin` **con** `tenant_id` del laboratorio (rol operativo actual) |
| Staff | `empleado` / `laboratorista` con el mismo `tenant_id` |
| Scoping | `BaseTenantModel` + helper `tenant_id()` fail-closed + SQL crudo revisado |
| Provisión | Transacción `TenantProvisioner` al crear un tenant |
| CDB / folios | Sin rediseño del formato CDB; `consecutivo` **por sucursal y tenant** |
| Fuera de alcance v1 | Pagos de suscripción, auto-signup, subdominios, white-label completo |

---

## 3. Modelo mental: Tenant vs Sucursal

```
labSoft (plataforma)
└── Tenant = un laboratorio / negocio cliente
    ├── Config del laboratorio (razón social, contacto, logo, puntos, estado)
    ├── Sucursal Principal
    ├── Sucursal 2…N  (opcionales)
    │     └── consecutivo / folio de venta por sucursal
    ├── Catálogo (análisis + precios) — del tenant, compartido entre sucursales
    ├── Clientes, ventas, muestras, resultados — del tenant
    └── Usuarios (admin dueño, empleados, laboratoristas)
```

- **Tenant** = unidad de facturación y aislamiento de datos (“Laboratorio X”).
- **Sucursal** = punto físico/operativo **dentro** del tenant (caja, folio, reportes por sede).
- Un usuario staff se asocia a **una sucursal** (como hoy vía `idsucursal` en sesión).
- El **admin dueño** del tenant ve todas las sucursales de **su** laboratorio.

---

## 4. Roles y permisos (visión multi-tenant)

### 4.1 Matriz

| Capacidad | `superadmin` (vendedor) | `admin` (dueño lab) | `empleado` | `laboratorista` |
|-----------|-------------------------|---------------------|------------|-----------------|
| Listar / crear / suspender tenants | ✅ | ❌ | ❌ | ❌ |
| Métricas globales de la plataforma | ✅ | ❌ | ❌ | ❌ |
| Config del **propio** laboratorio | ❌* | ✅ | ❌ | ❌ |
| CRUD sucursales del tenant | ❌* | ✅ | ❌ | ❌ |
| Catálogo, precios, usuarios del tenant | ❌* | ✅ | lectura según hoy | lectura según hoy |
| POS / ventas | ❌ | ✅ (ya hoy) | ✅ | ❌ |
| Captura de resultados | ❌ | ❌ | ❌ | ✅ |
| Datos de **otro** tenant | solo metadatos de tenant | ❌ | ❌ | ❌ |

\* En v1 el superadmin **no** edita catálogo clínico del tenant; solo gestiona el
ciclo de vida del tenant y el usuario admin inicial. Si hace falta soporte, se
añade “impersonar tenant” en una fase posterior (con bitácora).

### 4.2 Sesión

Tras login (`poblar_sesion_usuario()`):

| Clave de sesión | Superadmin | Usuario de tenant |
|-----------------|------------|-------------------|
| `tenant_id` | `null` | `int` del laboratorio |
| `tenant_nombre` | opcional / “Plataforma” | nombre comercial |
| `idsucursal` | n/a o null | sucursal del empleado o elegida |
| `accesslevel` | `9` (compat) | `0` / `1` / `2` |

- Si el tenant está **inactivo/suspendido** → login de su staff **rechazado**.
- Superadmin **siempre** entra al layout de backoffice, nunca al POS del tenant.

---

## 5. Backoffice del creador/vendedor (`superadmin`)

### 5.1 Propósito

Panel desde el que **tú** operas el negocio SaaS: dar de alta laboratorios, ver su
estado, resetear el admin del tenant si hace falta, y (más adelante) métricas de uso.

**Home sugerida:** `/super` o `/super/dashboard`  
**Layout:** `layouts/super.php` (distinto del admin del lab; sin menú clínico).

### 5.2 Módulos del backoffice

#### A. Dashboard plataforma

- KPI: tenants activos / suspendidos / totales.
- Altas recientes (últimos 7/30 días).
- (Opcional v1.1) ventas agregadas o conteo de ventas por tenant (sin detalle clínico).
- Accesos rápidos: “Nuevo laboratorio”, “Listado de tenants”.

#### B. Laboratorios (tenants) — CRUD

| Pantalla | Ruta sugerida | Acciones |
|----------|---------------|----------|
| Listado | `GET /super/tenants` | Buscar, filtrar por estado, DataTable |
| Alta | `GET/POST /super/tenants/nuevo` | Formulario + provisión |
| Detalle | `GET /super/tenants/(:id)` | Resumen, sucursales count, admin principal, fechas |
| Editar metadatos | `POST /super/tenants/(:id)` | Nombre, contacto, notas internas, plan (texto) |
| Suspender / reactivar | `POST /super/tenants/(:id)/estado` | `activo` 0/1 |
| Regenerar admin | `POST /super/tenants/(:id)/reset-admin` | Nueva contraseña temporal del admin |

**Campos del tenant (propuesta de tabla `tenant`):**

| Campo | Tipo | Uso |
|-------|------|-----|
| `id` | PK | `tenant_id` en el resto de tablas |
| `nombre` | string | Nombre comercial del laboratorio |
| `slug` | string unique | Identificador interno (futuro subdominio) |
| `rfc` | string null | Fiscal (opcional v1) |
| `email_contacto` | string | Contacto del dueño / facturación |
| `telefono` | string null | |
| `activo` | bool | Si `false`, nadie del tenant entra |
| `notas_internas` | text null | Solo visibles para superadmin |
| `plan` | string null | Etiqueta libre (“trial”, “mensual”…) — sin cobro automático en v1 |
| `created_at` / `updated_at` / soft delete + `*_by` | auditoría | Como el resto del sistema |

#### C. Provisión al “Nuevo laboratorio”

Al guardar un tenant nuevo, **una sola transacción** (`TenantProvisioner`):

1. Insertar fila en `tenant`.
2. Crear **Sucursal Principal** (nombre configurable en el form).
3. Crear fila en `consecutivo` para esa sucursal (folio inicial 1 o el indicado).
4. Crear fila en `maximos` (puntos/descuento por defecto).
5. Crear usuario **admin dueño** (Shield: `users` + identity + grupo `admin`) con
   `tenant_id` del nuevo tenant y vínculo a empleado “Dueño” o admin sin caja.
6. (Opcional configurable) Sembrar **catálogo base** de análisis (reusar seeder)
   con precios en $0 o plantilla.
7. Registrar en `auditoria` la alta del tenant.

**Salida al vendedor:** mostrar usuario admin + contraseña temporal (una sola vez)
y checklist “entrega al cliente”.

#### D. Usuarios plataforma (opcional v1)

- Listar solo `superadmin` (y crear un segundo superadmin si hace falta).
- **No** mezclar con el CRUD de usuarios de un tenant.

#### E. Fuera de backoffice v1 (backlog)

- Impersonación de tenant (entrar como admin del lab con banner y log).
- Facturación / Stripe / recordatorios de pago.
- Export masivo de un tenant.
- Branding por tenant (color, logo) desde el super (el dueño lo haría en su config).

### 5.3 Navegación superadmin

```
[labSoft · Plataforma]
  Dashboard
  Laboratorios
  (Usuarios plataforma)
  Cerrar sesión
```

Sin enlaces a `/cotizacion`, `/pendientes`, CRUDs clínicos.

### 5.4 Seguridad del backoffice

- Rutas bajo filtro `['auth', 'group:superadmin']`.
- Guard adicional: `session('tenant_id')` debe ser **null** (o grupo superadmin).
- CSRF en todos los POST.
- Toda acción de ciclo de vida del tenant → `auditoria_log()`.
- Rate limit razonable en login (ya Shield/Throttle si aplica).

---

## 6. Configuración del dueño del laboratorio (`admin` del tenant)

### 6.1 Propósito

Sección donde el **dueño** (y solo usuarios `admin` de **ese** tenant) configura
cómo opera su laboratorio: identidad, reglas de puntos, sucursales y (reutilizando
módulos actuales) personal y catálogo.

**Entrada en menú admin actual:** ampliar “Configuración” (hoy puntos) a un
**hub de configuración del laboratorio**.

**Ruta base sugerida:** `/configuracion` (o prefijo `/admin/config` si se reorganiza).

### 6.2 Hub de configuración

Estructura de menú / pestañas:

```
Configuración del laboratorio
├── 1. Datos del laboratorio
├── 2. Sucursales
├── 3. Puntos y descuentos          (maximos — ya existe)
├── 4. Personal y accesos           (atajo a Empleados + Usuarios)
└── 5. Catálogo                     (atajo a Análisis / Precios)
```

Las secciones 4 y 5 pueden ser **solo enlaces** a los CRUDs ya existentes; el valor
nuevo está en **1 y 2** + scoping multi-tenant de todo lo demás.

### 6.3 Datos del laboratorio (tenant “propio”)

Pantalla: el admin edita **solo su** fila de `tenant` (scoped por sesión).

| Campo editable por el dueño | Notas |
|-----------------------------|--------|
| Nombre comercial | Aparece en topbar, tickets, PDFs |
| Teléfono / email de contacto | Operación |
| Dirección fiscal o principal | Texto libre v1 |
| Logo (opcional) | Upload a `writable/uploads/tenants/{id}/` — fase 1.1 si se complica |
| Mensaje en ticket / pie de resultado | Texto corto opcional |

**No editable por el dueño:**

- `activo` / suspensión (solo superadmin).
- `plan`, `notas_internas`.
- `id` / `slug` (slug solo lectura o inmutable tras creación).

**Efecto en documentos:** `PdfTicket`, `PdfResultado`, ticket HTML y títulos de
layout leen `session('tenant_nombre')` o config cacheada del tenant (dejar de
hardcodear “labSoft” como nombre del **laboratorio cliente**; “labSoft” queda como
marca de la **plataforma** en login super / pie de plataforma).

### 6.4 Sucursales (configuración crítica)

Reutilizar y endurecer el CRUD actual `Admin/Sucursal` bajo el tenant:

| Acción | Reglas |
|--------|--------|
| Listar | Solo sucursales con `tenant_id` de sesión |
| Crear | Inserta con `tenant_id` + crea `consecutivo` asociado |
| Editar | Nombre, dirección, teléfono, activo |
| Desactivar | Soft-delete o `activo=0`; no borrar si hay ventas (preferir inactivar) |
| Sucursal por defecto | Marcar una como principal (venta admin sin empleado, reportes) |

**Campos sugeridos por sucursal (además de los actuales):**

- `nombre`, `direccion`, `telefono`
- `activo`
- `es_principal` (bool; una sola por tenant)
- `tenant_id` (obligatorio, inyectado)

**Folios:** al crear sucursal → fila en `consecutivo` con `tenant_id` + `idsucursal`.
El `VentaService` ya bloquea consecutivo con `FOR UPDATE`; debe filtrar también
por tenant.

**Asignación de personal:**

- Empleado/usuario de caja → `idsucursal` al crear/editar (como hoy).
- Admin dueño puede no tener sucursal fija; al vender elige sucursal
  (pendiente POS-01 en `PLAN_POS.md` — se vuelve obligatorio en multi-sucursal real).

### 6.5 Puntos y descuentos (`maximos`)

- Deja de ser “1 fila global” → **1 fila por tenant** (`UNIQUE(tenant_id)`).
- La pantalla `Admin/Config` actual solo edita la fila del tenant en sesión.
- Superadmin no toca esto en v1.

### 6.6 Qué no va en “configuración del dueño”

- Alta de **otros** tenants.
- Ver ventas de otros laboratorios.
- Cambiar su propio `tenant_id`.

---

## 7. Impacto en el software existente (por área)

### 7.1 Datos y modelos

```
NUEVO
  tenant                          # laboratorios clientes
  (opcional) tenant_settings      # si se prefiere no inflar tenant

ALTER en tablas de negocio
  + tenant_id NOT NULL (FK) + índice
  users.tenant_id NULLABLE        # NULL solo superadmin
  maximos: UNIQUE(tenant_id)
  auditoria: + tenant_id          # o filtrar vía usuario
  consecutivo: scoped por tenant + sucursal
```

- `BaseAuditModel` → extender a `BaseTenantModel` (audit + tenant).
- SQL crudo en `VentaModel`, `MuestraModel`, `PrecioModel`, etc.: añadir
  `AND …tenant_id = ?` en cada join/consulta.
- Helper: `tenant_id(): int` lanza si falta (fail-closed).

### 7.2 Auth y rutas

```
/login                          # global (todos los roles)
/super/*                        # group:superadmin
/dashboard, /configuracion, …   # group:admin  (+ tenant_id set)
/cotizacion, /venta, …          # group:admin,empleado
/pendientes, /capturas, …       # group:laboratorista
```

- Filtro opcional `tenant` que verifica sesión y tenant activo.
- Home de superadmin ≠ home de admin de lab.

### 7.3 UI / marca

| Contexto | Nombre mostrado |
|----------|-----------------|
| Login público (staff de labs) | Marca plataforma **labSoft** + subtítulo “Sistema de laboratorio” |
| Topbar admin/empleado/lab | **Nombre del tenant** (laboratorio del cliente) |
| Backoffice super | **labSoft · Plataforma** |
| Tickets / PDF del lab | Nombre del **tenant** (+ sucursal si aplica) |

### 7.4 Provisión y seeds

- Migración: tenant `id=1` con el laboratorio actual (backfill `tenant_id = 1`).
- Seed superadmin (usuario tuyo) con `tenant_id NULL`.
- `InstallSeeder` / `AnalisisSeeder` parametrizados por `tenant_id`.

### 7.5 POS y sucursales

- Empleado: sucursal de sesión (hoy).
- Admin multi-sucursal: selector de sucursal al vender (alinear con POS-01).
- Carrito en sesión: incluir `tenant_id` implícito al refrescar catálogo
  (ya se relee de BD; el scope del modelo lo aislará).

---

## 8. Flujos de extremo a extremo

### 8.1 Alta de un laboratorio (vendedor)

```
Tú (superadmin)
  → /super/tenants/nuevo
  → Datos: nombre lab, contacto, admin user/pass, nombre sucursal principal
  → TenantProvisioner (transacción)
  → Entregas al dueño: URL, usuario admin, contraseña temporal
```

### 8.2 Primer acceso del dueño

> **Detalle de producto:** ver `PLAN_ONBOARDING.md` (decisiones cerradas 2026-07-27).

```
Dueño
  → /login (admin del tenant)
  → [obligatorio] cambiar contraseña temporal
  → /dashboard con checklist “Configura tu laboratorio”
       · esenciales: datos del lab + sucursal principal (confirmar)
       · opcionales: personal, precios, puntos, explorar POS
  → cierre auto al cumplir esenciales o “Marcar como listo”
  → Operar (POS y resto del sistema ya eran usables sin wizard)
```

### 8.3 Día a día de un empleado

```
Empleado (tenant A, sucursal 2)
  → login → solo datos de tenant A
  → POS con folio de sucursal 2
  → no puede ver tenant B aunque adivine IDs (BaseTenantModel + fail-closed)
```

### 8.4 Suspensión

```
Superadmin marca tenant.activo = 0
  → staff del tenant no puede hacer login
  → datos conservados (no se borran)
  → reactivar restaura acceso
```

---

## 9. Fases de implementación (orden recomendado)

> Compatible con Fases 2–3 de `PLAN_ACTUALIZACION.md`, desglosadas por valor de producto.

### Fase MT-0 — Preparación (sin UI)

- [x] Migración `CreateTenant` + backfill tenant 1.
- [x] Migración `AddTenantId` en tablas de negocio + `users.tenant_id`.
- [x] `BaseTenantModel` + `tenant_id()` + tests de aislamiento.
- [x] Revisar SQL crudo y `VentaService`.
- [x] `poblar_sesion_usuario()` con `tenant_id` / rechazo si inactivo.
- [x] Seed superadmin (+ stub `/super` para que el login no quede sin home).

**Criterio de salida:** dos tenants en BD; queries no cruzan datos; login carga tenant.  
**Hecho 2026-07-28:** migraciones aplicadas; tests `TenantHelperTest` + `BaseTenantModelTest`; seed `super` / `Super2026lab!`.

### Fase MT-1 — Backoffice vendedor (MVP)

> **Plan:** `PLAN_MT1.md`. **Hecho 2026-07-28.**

- [x] Layout + dashboard super (ampliar stub).
- [x] Listado / alta / detalle / suspender tenants (páginas completas).
- [x] `TenantProvisioner` (tenant + sucursal + consecutivo + maximos + admin + catálogo precios 0).
- [x] Rutas y guards `group:superadmin`.
- [x] Reset admin + auditoría de altas/suspensiones.
- [x] Credenciales admin mostradas **una vez** post-alta.

**Criterio de salida:** puedes dar de alta un lab nuevo y el dueño entra solo a su mundo. ✅

### Fase MT-2 — Configuración del dueño

- [ ] Hub `/configuracion`.
- [ ] Editar datos del propio tenant (nombre, contacto, textos de ticket).
- [ ] Sucursales scoped + alta con consecutivo.
- [ ] `maximos` por tenant.
- [ ] Tickets/PDF/layouts usan nombre del tenant.
- [ ] Selector de sucursal en venta admin (si hay >1 sucursal).

**Criterio de salida:** dueño configura lab + 2 sucursales y opera sin ver otros tenants.

### Fase MT-3 — Endurecimiento

- [ ] Tests automatizados de aislamiento (modelo + 1 flujo HTTP).
- [ ] Checklist manual de regresión POS / lab / reportes con 2 tenants.
- [ ] Documentar en `INSTALACION.md` el rol superadmin y el flujo de alta.
- [ ] Bitácora en `PLAN_ACTUALIZACION.md`.

### Fase MT-4 — Mejoras (backlog, no bloquean MVP)

- [ ] Logo por tenant en ticket/PDF.
- [ ] Impersonación auditada desde super.
- [ ] Métricas de uso por tenant en dashboard super.
- [ ] Tema de color por tenant (tokens Modernize).
- [ ] Subdominio o path por tenant (si se necesita más adelante).
- [ ] Cobro de suscripciones.

---

## 10. Wireframe textual de pantallas clave

### Super — Listado de laboratorios

```
+----------------------------------------------------------+
| labSoft · Plataforma          [usuario super] [salir]    |
| Dashboard | Laboratorios                                 |
+----------------------------------------------------------+
| Laboratorios                    [+ Nuevo laboratorio]    |
| [buscar...]  [filtro: todos|activos|suspendidos]         |
|----------------------------------------------------------|
| Nombre          Contacto        Estado    Altas   Acciones|
| Lab Norte SA    a@x.com         Activo    12      Ver     |
| Lab Centro      b@y.com         Suspend.  3       Ver     |
+----------------------------------------------------------+
```

### Super — Alta de laboratorio

```
Nombre comercial *
Slug (auto desde nombre)
Email contacto *
Teléfono
Notas internas (solo tú)

--- Acceso del dueño ---
Usuario admin *
Contraseña temporal *
Nombre a mostrar del dueño

--- Sucursal inicial ---
Nombre sucursal *  (default: "Sucursal Principal")
Folio inicial      (default: 1)

[ ] Sembrar catálogo base de análisis

[Cancelar]  [Crear laboratorio]
```

### Dueño — Configuración › Datos del laboratorio

```
Nombre comercial *     [ Lab Norte SA        ]
Teléfono               [ ... ]
Email                  [ ... ]
Dirección              [ ... ]
Texto pie de ticket    [ ... ]

[Guardar]
```

### Dueño — Configuración › Sucursales

```
[+ Nueva sucursal]
| Nombre              Principal  Activa  Acciones     |
| Sucursal Principal  sí         sí      Editar       |
| Plaza Sur           no         sí      Editar       |
```

---

## 11. Criterios de aceptación globales

1. **Aislamiento:** usuario del tenant A no obtiene filas del tenant B por ID directo
   (GET/POST), listados ni reportes.
2. **Provisión:** crear tenant deja el lab usable (login admin + 1 sucursal + folio).
3. **Suspensión:** tenant inactivo → staff no entra; datos intactos.
4. **Superadmin:** no ve menús clínicos; solo backoffice.
5. **Dueño:** configura nombre y sucursales; no ve otros tenants ni notas internas.
6. **Auditoría:** altas/cambios de estado de tenant y cambios de config quedan
   registrados.
7. **Regresión:** flujo venta → captura → resultados sigue funcionando en tenant
   migrado (id=1).

---

## 12. Riesgos y mitigaciones

| Riesgo | Mitigación |
|--------|------------|
| Query cruda sin `tenant_id` | Checklist grep + tests; BaseTenantModel por defecto |
| Superadmin con `tenant_id` mal seteado | Guard en rutas `/super` y al poblar sesión |
| Admin elige mal sucursal / folio cruzado | Consecutivo por (tenant, sucursal); selector explícito |
| Hardcode de marca en PDF | Fuente única: config/session del tenant |
| Backfill incompleto en prod | Migración con `DEFAULT 1` + verificación COUNT por tabla |
| Catálogo sembrado no deseado | Checkbox en provisión; precios en 0 |

---

## 13. Fuera de alcance de este plan (explícito)

- Pasarela de pagos / suscripciones automáticas.
- Marketplace o cobros automáticos (el **self-signup trial** se planifica en `PLAN_LANDING_REGISTRO.md`; no es marketplace).
- App móvil nativa.
- Multi-BD por tenant.
- RBAC fino dentro del tenant más allá de los 3 grupos actuales
  (`admin` / `empleado` / `laboratorista`).

---

## 14. Entregables cuando se implemente

| Entregable | Ubicación esperada |
|------------|-------------------|
| Migraciones tenant + tenant_id | `app/Database/Migrations/` |
| `BaseTenantModel`, `TenantModel` | `app/Models/` |
| `TenantProvisioner` | `app/Services/` |
| Controladores super | `app/Controllers/Super/` |
| Vistas super | `app/Views/super/` + `layouts/super.php` |
| Config dueño | ampliar `Admin/Config` o `Admin/Laboratorio` + vistas |
| Tests aislamiento | `tests/unit/BaseTenantModelTest.php` (+ HTTP si aplica) |
| Docs operación | actualizar `INSTALACION.md` + bitácora `PLAN_ACTUALIZACION.md` |

---

## 15. Resumen ejecutivo

1. **Tú (superadmin)** operas un **backoffice** para crear, suspender y dar soporte a
   laboratorios-cliente, con provisión automática (sucursal, folio, admin, opcional
   catálogo).
2. **El dueño (`admin` del tenant)** tiene una **configuración de laboratorio**
   (identidad) y **sucursales** (sedes + folios), más los módulos ya existentes
   (personal, catálogo, puntos) **aislados a su tenant**.
3. El aislamiento es **una BD + `tenant_id`**, login único, sin subdominios en v1.
4. Implementar en orden: **núcleo de datos → backoffice vendedor → config dueño →
   endurecimiento**.

Cuando se apruebe este plan, la ejecución debe seguir las fases MT-0…MT-3 y
registrarse en la bitácora de `PLAN_ACTUALIZACION.md`.
