# Plan — Landing pública + registro de laboratorio

> **Estado:** planificación con decisiones cerradas (2026-07-28).  
> **LR-0 + LR-1 implementados (2026-07-28).** LR-2 email pulido/docs CAPTCHA externo pendiente.  
> **Depende de:** MT-0 + MT-1 (`TenantProvisioner`).  
> **Complementa:** `PLAN_ONBOARDING.md` (post-registro del dueño),  
> `PLAN_MULTITENANT.md` (antes: alta solo superadmin; este plan **añade** canal público).

---

## 1. Objetivo de producto

Que un laboratorio pueda, desde la **web pública de labSoft**:

1. Entender el producto (landing).
2. **Registrarse solo** y obtener un laboratorio **listo para usar en trial**.
3. Entrar de inmediato con el usuario admin que eligió.

Tú (superadmin) sigues pudiendo dar de alta labs a mano en `/super` (ventas asistidas, demos, clientes enterprise).

---

## 2. Decisiones cerradas

| Tema | Decisión |
|------|----------|
| Alcance de la web | **Landing de producto + registro** en el mismo producto |
| Resultado del registro | **Alta inmediata usable** (trial) vía `TenantProvisioner` |
| Stack / hosting | **Dentro de lab_saas (CodeIgniter)** — rutas públicas en el mismo deploy |
| Datos del form | **Mínimo:** lab + admin (ver §5) |
| Pagos | **No** en este alcance — solo trial gratuito (`plan = trial`) |
| Anti-abuso | **CAPTCHA** + email de bienvenida **sin bloquear** el acceso |
| Verificación de email | No bloquea login (el mail es informativo) |
| Alta manual superadmin | Se mantiene en `/super/tenants/nuevo` |

---

## 3. Modelo mental del visitante

```
Visitante anónimo
  → Landing (/)
  → CTA “Probar gratis” / “Crear mi laboratorio”
  → /registro (form)
  → CAPTCHA OK + validación
  → TenantProvisioner (trial, catálogo precios 0)
  → Sesión del admin (opcional auto-login) o redirect a /login con mensaje
  → /dashboard + checklist onboarding (cuando exista PLAN_ONBOARDING)
```

**Si ya hay sesión:** `/` redirige al home del rol (como hoy `Home::index`).

---

## 4. Rutas públicas y auth

### 4.1 Rutas nuevas (sin `auth`)

| Método | Ruta | Controlador | Notas |
|--------|------|-------------|--------|
| GET | `/` | `Public\Landing::index` | Landing si guest; si logueado → dispatcher actual |
| GET | `/registro` | `Public\Registro::form` | Formulario |
| POST | `/registro` | `Public\Registro::crear` | Provisión + anti-abuso |
| GET | `/precios` (opc.) | `Public\Landing::precios` | Ancla o página simple “planes” sin cobro |
| GET | `/privacidad`, `/terminos` (opc. v1.1) | estáticos | Recomendable antes de prod comercial |

**Throttle:** filtro de rate limit en `POST /registro` (p. ej. 5/hora por IP).

### 4.2 Ajuste de `/`

Hoy `Home::index` exige login o manda a `/login`. Cambiar a:

```
si loggedIn → match por grupo (super → /super, admin → /dashboard, …)
si guest    → vista landing
```

`/login` y Shield sin cambios de marca mayor; el layout de login puede enlazar “¿No tienes lab? Crear cuenta”.

### 4.3 Qué no es público

- Todo `/super/*`, POS, lab, etc. siguen con `auth` + `group:`.

---

## 5. Formulario de registro (mínimo)

| Campo | Obligatorio | Notas |
|-------|-------------|--------|
| Nombre del laboratorio | sí | → `tenant.nombre` |
| Slug | no (auto) | Auto desde nombre; editable avanzado opcional (collapse) |
| Nombre del dueño | sí | → empleado / display |
| Usuario (login) | sí | unique global; 3–45 chars, reglas Shield |
| Email de contacto | sí | contacto del tenant + identity placeholder / bienvenida |
| Contraseña | sí | mín. según política (p. ej. 8); confirmación |
| Teléfono | no | `tenant.telefono` |
| Acepto términos | sí | checkbox |
| CAPTCHA | sí | Turnstile/hCaptcha (configurable) |
| Honeypot | sí | campo oculto anti-bots simples |

**No pedir en v1:** RFC, dirección fiscal, N sucursales, tarjeta, tamaño del lab.

**Defaults de provisión:**

- `plan = trial`
- `sucursal_nombre = Sucursal Principal`
- `folio_inicial = 1`
- `sembrar_catalogo = true` (precios 0)
- `onboarding_completed_at = NULL`
- `force_password_reset = 0` (el dueño **eligió** su contraseña; no forzar cambio)
- `activo = 1`

Reutilizar **`TenantProvisioner`** con un origen `source = public_signup` en auditoría.

---

## 6. Flujo post-registro

### 6.1 Éxito (recomendado)

1. Provisionar.
2. **Auto-login** del admin creado (Shield).
3. `poblar_sesion_usuario`.
4. Redirect `/dashboard` (o `/` dispatcher).
5. Flash: “Bienvenido a labSoft. Tu laboratorio trial está listo.”
6. Cuando exista onboarding: checklist en dashboard.

**Alternativa** (si auto-login complica CSRF/Shield): redirect a `/login?registered=1` con mensaje. Preferir auto-login si es limpio en CI4 Shield.

### 6.2 Email de bienvenida (no bloqueante)

- Asunto: “Tu laboratorio labSoft está listo”
- Body: nombre lab, URL login, username (sin contraseña).
- Si SMTP no configurado: `log_message` + no fallar el registro.

### 6.3 Superadmin

- El lab aparece en `/super/tenants` con `plan=trial`.
- Opcional v1.1: badge “Signup público” / contador en dashboard super.
- Opcional: email a super “Nuevo lab: X” (misma regla SMTP).

---

## 7. Landing (contenido y UI)

### 7.1 Secciones (implementado 2026-07-28)

Orden canónico y copy de conversión en `app/Views/public/landing.php`
y reglas visuales en `docs/MANUAL_IDENTIDAD_PUBLICA.md`:

1. **Nav** — Funciones · Cómo funciona · Acceso $0 · FAQ · Entrar · Empezar gratis.
2. **Hero** — valor unificado + **$0 en desarrollo** · precios por definir · CTAs
   “Crear mi laboratorio gratis” / “Ver el flujo”.
3. **Preview** mock del producto + stats ($0, roles, flujo, tiempo).
4. **Problema (PAS)** — caos operativo / mostrador / datos dispersos + banner solución.
5. **Funciones** — 6 cards en lenguaje de **beneficio** (no jerga de features).
6. **Split** operación unificada (caja → lab → entrega).
7. **Cómo funciona** — 3 pasos + CTA a $0.
8. **Acceso early** (`#trial`) — $0 mientras esté en desarrollo; precios TBD;
   sin badge “Recomendado”; sin “Cancela cuando quieras”.
9. **Para quién / no para quién** (`#para-quien`).
10. **Escenarios por rol** (`#testimonios`) — no reseñas falsas.
11. **FAQ** (`#faq`) — 7 preguntas; precio primero.
12. **CTA final** + footer con nota de pricing.

**Animación:** GSAP 3 + ScrollTrigger (`public/js/landing.js`), solo en landing;
respeta `prefers-reduced-motion`.

### 7.2 Diseño

- Misma base visual Modernize / tokens `app.css` (coherencia con la app).
- Layout **público** distinto: `layouts/public.php` (sin menú de roles; topbar marketing).
- Mobile-first; sin build tooling (HTML/CSS/JS como el resto).
- Sin jQuery obligatorio en landing (vanilla + Bootstrap JS + GSAP en home).

### 7.3 SEO básico

- `<title>`, meta description, OG tags desde `Home::index` (incl. $0 en desarrollo).
- Un solo H1 en hero.

---

## 8. Seguridad y abuso

| Control | Detalle |
|---------|---------|
| CAPTCHA | Cloudflare Turnstile o hCaptcha; keys en `.env` |
| Rate limit | `ThrottleFilter` en POST registro |
| Honeypot | Campo `website` vacío |
| Validación server | Username/slug unique, password strength, email format |
| CSRF | Activo (formularios CI4) |
| No enumeración agresiva | Mensajes genéricos donde aplique; slug/user taken sí se puede decir (UX) |
| Contenido generado | Escapar todo en vistas |

**No en v1:** verificación telefónica, KYC, límites de uso por trial (se puede añadir `trial_ends_at` en MT posterior).

---

## 9. Modelo de datos (cambios mínimos)

Idealmente **sin migración bloqueante** si reutilizamos campos:

| Campo | Uso |
|-------|-----|
| `tenant.plan` | `trial` en signup |
| `tenant.notas_internas` | opcional: `signup:public` + IP + fecha (o solo auditoría) |
| `auditoria` | `tenant_create_public` con ip, email, slug |

**Opcional (recomendado en misma fase o v1.1):**

```sql
tenant.signup_source ENUM/VARCHAR  -- 'super' | 'public'
tenant.trial_ends_at DATETIME NULL -- p.ej. now + 30 días (sin enforcement aún)
```

Enforcement de fin de trial = fase de cobros; aquí solo se **registra** la fecha si se añade la columna.

---

## 10. Arquitectura de código

| Pieza | Ubicación |
|-------|-----------|
| Layout público | `app/Views/layouts/public.php` |
| Landing | `app/Views/public/landing.php` |
| Registro form | `app/Views/public/registro.php` |
| Controladores | `Home::index` (guest → landing), `Registro.php` |
| Servicio | Reusar `TenantProvisioner`; flag/origen en auditoría |
| JS landing | `public/js/landing.js` (GSAP + ScrollTrigger vía CDN) |
| CSS | Bloque `.public-site` en `public/css/app.css` |
| Tests | `tests/unit/LandingRegistroTest.php` |
| Config | CAPTCHA suma + honeypot + throttle (ver implementación Registro) |

**Home:** `Home::index` — guest → landing; auth → home por rol.

---

## 11. Copy de acceso (honestidad de producto) — **vigente**

Mensaje maestro (hero, card `#trial`, FAQ, CTA, footer, OG):

> **labSoft cuesta $0 mientras está en fase de desarrollo. Los precios del software
> están por determinarse; cuando existan, se comunicarán con claridad. No pedimos tarjeta.**

Reglas:

- No prometer “14 días con tarjeta”, “gratis para siempre” ni planes cobrables inventados.
- No usar “Cancela cuando quieras” mientras no haya billing.
- `plan = trial` en BD es el **código interno** del alta; en marketing se habla de
  **acceso early / $0 en desarrollo**, no de trial con caducidad de cobro.
- Superadmin puede cambiar `plan` / suspender en `/super` si un alta abusa.

---

## 12. Fases de implementación

### LR-0 — Cimientos públicos

- [x] `layouts/public.php` + rutas guest
- [x] `/` landing estática (contenido v1) + CTA
- [x] Ajuste Home: guest → landing; auth → dispatcher
- [x] Enlaces login ↔ registro

### LR-1 — Registro + provisión

- [x] Form `/registro` + validación
- [x] CAPTCHA + honeypot + throttle
- [x] `TenantProvisioner` desde público (trial, catalogo ON, force_password 0)
- [x] Auto-login o redirect login
- [x] Auditoría `tenant_create_public`
- [x] Test de registro (o test del servicio con origen public)

### LR-2 — Email y pulido

- [x] Email bienvenida (fail-open)
- [ ] Mensajes flash y página de error amable
- [ ] Badge/filtro “trial” en super listado (opcional)
- [ ] Docs `INSTALACION.md` (CAPTCHA keys, SMTP)
- [ ] Bitácora `PLAN_ACTUALIZACION.md`

### LR-3 — Backlog (no bloquea MVP)

- [ ] Términos / privacidad
- [ ] `trial_ends_at` + banner “tu trial termina el…”
- [ ] Stripe / planes de pago
- [ ] Verificación de email obligatoria
- [ ] Multi-idioma
- [ ] Blog / recursos
- [ ] Landing en subdominio `www` separado

---

## 13. Criterios de aceptación

1. Guest en `/` ve landing; no ve menús de lab.
2. CTA lleva a `/registro`.
3. Registro válido crea tenant activo trial, sucursal, admin, catálogo precios 0.
4. CAPTCHA inválido o honeypot → no crea tenant.
5. Username/slug duplicado → error claro, sin provisión a medias.
6. Dueño puede entrar y operar (POS/config) solo su tenant.
7. Super ve el nuevo lab en `/super/tenants`.
8. SMTP caído no impide el alta.
9. Usuario logueado que visita `/` va a su home de rol.
10. Rate limit mitiga spam de altas.

---

## 14. Relación con otros planes

| Plan | Relación |
|------|----------|
| MT-1 | **Reutiliza** `TenantProvisioner` y listado super |
| Onboarding | Tras signup, el dueño ve checklist (cuando se implemente); **no** force-password si eligió pass |
| MT-2 | Config del lab (nombre, sucursales) sigue en app autenticada |
| Cobros | Fuera; trial sin enforcement de fecha en MVP |

**Cambio de doctrina multi-tenant:**  
Antes: “Alta solo superadmin”.  
Ahora: “Alta **superadmin o self-signup trial**”; sin marketplace ni pagos automáticos.”

---

## 15. Riesgos

| Riesgo | Mitigación |
|--------|------------|
| Spam de labs | CAPTCHA + throttle + super puede suspender |
| Expectativa de “SaaS de pago” | Copy honesto de trial |
| Conflicto de rutas `/` | Dispatcher auth/guest claro |
| SMTP | Fail-open en mail |
| Catálogo vacío si tenant 1 sin datos | Mismo warning que MT-1; provisión OK |
| Abuso de trial eterno | Super suspende; luego `trial_ends_at` |

---

## 16. Resumen ejecutivo

1. **Landing + registro** en CodeIgniter (mismo deploy).
2. Registro = **provisión inmediata trial**, sin tarjeta.
3. Anti-abuso: **CAPTCHA + throttle**; email de bienvenida opcional.
4. Superadmin **sigue** pudiendo crear labs y suspender.
5. Implementar en **LR-0 → LR-1 → LR-2**; pagos y verificación dura en backlog.

---

## 17. Aprobación

Implementar cuando el usuario diga **adelante / implementa landing** (o por fases: primero solo landing LR-0, luego registro LR-1).

Preguntas menores a resolver en implementación (no bloquean el plan):

- Driver CAPTCHA por defecto (Turnstile vs hCaptcha vs honeypot-only en dev).
- Auto-login vs pantalla “cuenta creada, inicia sesión”.
- Textos exactos de la landing (marketing).
