# Sprint 1.2 · Criterios de Aceptación

> **Para vos, Ricci.** Esta es la checklist que vamos a recorrer juntos al cierre del sprint.
> Si algo falla, no avanzamos al Sprint 1.3.

---

## ✅ Bloque 1 · Técnico (Claude Code lo confirma)

- [ ] BD `innovium_master` existe con sus 5 tablas + tracking de migrations
- [ ] BD `innovium_demo` sigue intacta (Sprint 1.1 no se rompió)
- [ ] BD `innovium_infinia` existe con las mismas 8 tablas que demo + seed sintético
- [ ] `tenants` tiene 2 filas: `demo` (estado=activo) e `infinia` (estado=activo)
- [ ] `tenant_features` tiene features por tenant (al menos `multi_tenant`, `firma_digital`, `offline_mode` habilitadas)
- [ ] Comando `php scripts/innovium tenant:create test123` funciona end-to-end
- [ ] Comando `php scripts/innovium master:migrate` funciona idempotente
- [ ] `vendor/bin/phpunit` pasa todos los tests previos + los nuevos de aislamiento

---

## ✅ Bloque 2 · Resolución de tenant (vos lo validás)

### 2.1 · Sin subdominio

Andá a: **http://innovium.test:8000/**

- [ ] Devuelve 404 con mensaje claro tipo "Tenant requerido"
- [ ] NO muestra welcome page ni login

### 2.2 · Subdominio inexistente

Andá a: **http://noexiste.innovium.test:8000/login**

- [ ] Devuelve 404
- [ ] Mensaje genérico (NO revela si existe o está suspendido)

### 2.3 · Hostname malicioso

Andá a: **http://Demo.innovium.test:8000/login** (con D mayúscula)

- [ ] O resuelve a `demo` (case-insensitive) → entra OK
- [ ] O devuelve 404 (estricto)
- [ ] **Lo importante:** debe ser consistente y documentado

### 2.4 · Tenant válido demo

Andá a: **http://demo.innovium.test:8000/login**

- [ ] Carga la página de login
- [ ] El tenant badge dice "Innovium · Demo" + "demo.innovium.test"
- [ ] El dot verde pulsa
- [ ] Login con `vendedor@demo.cl` / `Innovium2026!` → entra al dashboard
- [ ] Dashboard muestra "Buenas tardes/días, Andrea" (usuario de demo)
- [ ] Sidebar dice "Innovium · Demo"

### 2.5 · Tenant válido infinia

Andá a: **http://infinia.innovium.test:8000/login**

- [ ] Carga la página de login
- [ ] El tenant badge dice "Innovium · Infinia"
- [ ] Login con `vendedor@infinia.cl` / `Innovium2026!` → entra al dashboard
- [ ] Dashboard muestra el nombre del usuario de infinia (NO "Andrea")
- [ ] Sidebar dice "Innovium · Infinia"

---

## ✅ Bloque 3 · Aislamiento (CRÍTICO)

### 3.1 · Cross-tenant login bloqueado

- [ ] En `infinia.innovium.test:8000/login`, intentar login con `vendedor@demo.cl` → "Credenciales inválidas"
- [ ] En `demo.innovium.test:8000/login`, intentar login con `vendedor@infinia.cl` → "Credenciales inválidas"

**Por qué:** los usuarios viven en la BD de SU tenant. El usuario de demo no existe en infinia y viceversa.

### 3.2 · Sesiones aisladas

- [ ] Logueate en demo en una pestaña: `vendedor@demo.cl`
- [ ] Abrí otra pestaña en infinia: `vendedor@infinia.cl`
- [ ] Ambas pestañas funcionan independientes (no se pisan las sesiones)

### 3.3 · Audit logs separados

```bash
mysql -u root -e "SELECT 'demo' as tenant, COUNT(*) as logins FROM innovium_demo.audit_log WHERE accion='user.login' UNION SELECT 'infinia', COUNT(*) FROM innovium_infinia.audit_log WHERE accion='user.login';"
```

- [ ] Cada tenant tiene su propio audit_log con sus propios eventos
- [ ] Los eventos de un tenant NO aparecen en el otro

### 3.4 · Tenant suspendido bloqueado

```bash
mysql -u root -e "UPDATE innovium_master.tenants SET estado='suspendido' WHERE slug='demo';"
```

- [ ] Andá a `http://demo.innovium.test:8000/login`
- [ ] Devuelve 503 con mensaje "tenant temporalmente no disponible"
- [ ] NO muestra el form de login

Después restaurá:
```bash
mysql -u root -e "UPDATE innovium_master.tenants SET estado='activo' WHERE slug='demo';"
```

---

## ✅ Bloque 4 · Comando `tenant:create`

```bash
php scripts/innovium tenant:create test456 --name="Funeraria Test" --short="Test"
```

- [ ] Crea BD `innovium_test456`
- [ ] Aplica las 8 migraciones de schema
- [ ] Inserta fila en `tenants`
- [ ] Inserta features default en `tenant_features`
- [ ] Imprime URL local: `http://test456.innovium.test:8000/login`
- [ ] Imprime password del admin inicial

Después agregar al hosts file (manual):
```
127.0.0.1   test456.innovium.test
```

Y `ipconfig /flushdns`. Probar:

- [ ] `http://test456.innovium.test:8000/login` → carga, tenant badge dice "Innovium · Test"

Limpiar después de la prueba:
```bash
mysql -u root -e "DROP DATABASE innovium_test456; DELETE FROM innovium_master.tenant_features WHERE tenant_id IN (SELECT id FROM innovium_master.tenants WHERE slug='test456'); DELETE FROM innovium_master.tenants WHERE slug='test456';"
```

---

## ✅ Bloque 5 · Validaciones de slug

Probá ejecutar:

```bash
php scripts/innovium tenant:create "ADMIN"      # uppercase
php scripts/innovium tenant:create "ad"         # muy corto
php scripts/innovium tenant:create "a-very-long-slug-that-exceeds-the-limit"  # muy largo
php scripts/innovium tenant:create "admin"      # reservado
php scripts/innovium tenant:create "with space" # con espacio
php scripts/innovium tenant:create "demo"       # ya existe
```

- [ ] Todos fallan con mensaje claro
- [ ] Ninguno crea BD ni fila en `tenants`

---

## Lo que NO hay que esperar (para que no te frustres)

- 🚫 Selector visual de tenants → Sprint 2.x
- 🚫 Pantalla de gestión de tenants → Sprint 2.x
- 🚫 Branding custom funcionando (logos, colores por tenant) → Sprint 1.4
- 🚫 Email de bienvenida al admin → Sprint 2.x

---

## Cierre del sprint

Cuando todos los checks de arriba estén ✅:

1. Tomá screenshot del login en `demo.innovium.test:8000` y otro en `infinia.innovium.test:8000` (lado a lado idealmente)
2. Pegámelos acá
3. Yo te confirmo "Sprint 1.2 cerrado, vamos al 1.3"
4. Hacés commit final: `chore: sprint 1.2 cerrado - multi-tenancy core`
5. Si querés, ahí también podés subir a GitHub (hicimos backup pendiente)

---

## Si algo falla

No improvises. Volvé acá conmigo y me decís:
- En qué bloque estás
- Qué esperabas
- Qué pasó (mensaje exacto o screenshot)
- Cualquier output de consola relevante

Te ayudo a debuguear con Claude Code.
