diff --git a/docs/segunda-instancia.md b/docs/segunda-instancia.md
new file mode 100644
index 0000000..217fb24
--- /dev/null
+++ b/docs/segunda-instancia.md
@@ -0,0 +1,91 @@
+# Segunda instancia white-label (sin branding SKEEN)
+
+Segunda clínica sobre el mismo código y la misma VPS. La marca no vive en el
+código: sale del parámetro `skeen.clinic.brand` (ver `GET /skeen/frontend/v1/brand`),
+así que esta y futuras instancias son solo infra + config.
+
+## Mapa de la instalación
+
+| Componente | SKEEN (instancia 1) | Clínica 2 (instancia white-label) |
+|---|---|---|
+| Odoo HTTP | 8069 | **8070** |
+| Odoo longpolling | 8072 | **8073** |
+| Base de datos | `skeen_odoo` | **`clinica2_odoo`** |
+| Conf | `/root/skeen-odoo/odoo.conf` | **`/root/clinica2-odoo.conf`** |
+| Systemd | `odoo-skeen.service` | **`odoo-clinica2.service`** |
+| Frontend | `/var/www/skeen-frontend` | **`/var/www/clinica2-frontend`** |
+| Nginx | vhost `skeen-crm` (80) | **vhost `clinica2` (80 + 8880)** |
+| Acceso LAN | http://192.168.10.114 | **http://192.168.10.114:8880** |
+| Acceso público | skeen.consultoria-as.com | **clinica2.consultoria-as.com (pendiente: dashboard del túnel)** |
+| WhatsApp (WACRM) | integrado | **oculto + bloqueado (escenario B)** |
+
+`addons_path` se comparte (read-only): `/root/skeen-odoo/addons`. Un solo
+código, N bases de datos.
+
+## Cómo se levantó (orden de pasos)
+
+Los archivos canónicos están en `infra/clinica2/`:
+
+1. `odoo.conf` — copia del de SKEEN con `db_name=clinica2_odoo`, `http_port=8070`,
+ `longpolling_port=8073`, `data_dir=/var/lib/odoo-clinica2`.
+2. Crear la base (el rol `skeen` no tiene CREATEDB; se crea como `postgres`):
+ `CREATE DATABASE clinica2_odoo OWNER skeen ...`
+3. Instalar módulos limpio (sin demo):
+ `odoo-bin -c /root/clinica2-odoo.conf -d clinica2_odoo --without-demo=all --init=skeen_whatsapp,skeen_chat,skeen_visitas --stop-after-init --no-http`
+ (skeen_whatsapp arrastra citas/pacientes/ventas/pagos/monedero; visitas
+ arrastra inventario).
+4. `postinstall.py` — brand neutro (`skeen.clinic.brand`), menú WACRM vacío
+ para todos (`skeen.menu_roles`), password de admin propio +
+ `must_change_password`, empresa renombrada.
+5. `systemctl enable --now odoo-clinica2`.
+6. `nginx-vhost` → `/etc/nginx/sites-enabled/clinica2` + `nginx -t && reload`.
+7. Frontend: mismo build de SKEEN (`rsync -a dist/ /var/www/clinica2-frontend/`)
+ más `public/brand/` (logos SVG neutros + favicon, versionados en el repo).
+
+## Pendiente para acceso público (único paso manual)
+
+El túnel cloudflared corre con `--token` (remotamente administrado): el
+`config.yml` local NO aplica. En el dashboard de Cloudflare (Zero Trust →
+Networks → Tunnels → f2517233…) agregar el ingress:
+
+```yaml
+- hostname: clinica2.consultoria-as.com
+ service: http://localhost:80
+```
+
+El vhost nginx ya escucha en el 80 con ese `server_name`; al agregar el
+hostname el túnel enruta solo. El 8880 queda como acceso LAN permanente.
+
+## Aislamiento de datos (escenario B: sin WhatsApp)
+
+- Sin `SUPABASE_URL` / `WACRM_API_*` / `HERMES_BRIDGE_URL` en la unit systemd
+ (el backend respondería "Falta configuración").
+- Aun así, el backend tiene fallback a `localhost:3000`; por eso el vhost
+ nginx corta `/api/odoo/skeen/frontend/v1/wacrm/` con `return 403;` — doble
+ candado, la instancia 2 no puede leer ni escribir las conversaciones de
+ SKEEN aunque alguien llame la API a mano.
+- Menú WACRM oculto para todos los roles vía matriz (`/wacrm/*: []`).
+
+Para activar WhatsApp en la instancia 2 (escenario A) se necesita: número
+propio de WhatsApp Business + decisión de WACRM multi-clínica (estimar aparte).
+
+## Fix de menús que esta fase destapó (aplica a TODAS las instancias)
+
+Las vistas XML referenciaban `skeen_citas.menu_skeen_root`, pero `skeen_citas`
+depende de `skeen_pacientes`: en instalación limpia de una sola pasada el
+xmlid aún no existe y la carga falla (la base de SKEEN se construyó por fases
+y por eso nunca explotó). Se movió el menú raíz a `skeen_pacientes` (módulo
+raíz de la jerarquía) y todas las referencias apuntan a
+`skeen_pacientes.menu_skeen_root`. En bases existentes se transfirió el
+ownership del xmlid (`UPDATE ir_model_data SET module='skeen_pacientes' …`),
+así actualizar no duplica el menú. Mismo tratamiento para el menú padre de
+Citas (`skeen_citas/views/menus.xml` carga antes que bloqueos/lista de espera).
+
+## Operación habitual
+
+- Logs: `tail -f /tmp/odoo2.log` (instancia 2) vs `/tmp/odoo.log` (SKEEN).
+- Ambas instancias comparten código: un `git pull` + rebuild afecta el build
+ de ambas solo si se vuelven a copiar los `dist/` (cada uno tiene el suyo).
+- Para una tercera clínica: repetir pasos 1–7 con `clinica3` (puertos 8074/8075,
+ db `clinica3_odoo`, vhost propio) y setear su brand desde
+ Configuración → Clínica o con `PUT /brand`.
diff --git a/frontend/public/brand/favicon.svg b/frontend/public/brand/favicon.svg
new file mode 100644
index 0000000..8d743f4
--- /dev/null
+++ b/frontend/public/brand/favicon.svg
@@ -0,0 +1,4 @@
+
diff --git a/frontend/public/brand/logo-blanco.svg b/frontend/public/brand/logo-blanco.svg
new file mode 100644
index 0000000..3492999
--- /dev/null
+++ b/frontend/public/brand/logo-blanco.svg
@@ -0,0 +1,5 @@
+
diff --git a/frontend/public/brand/logo-negro.svg b/frontend/public/brand/logo-negro.svg
new file mode 100644
index 0000000..c505bc2
--- /dev/null
+++ b/frontend/public/brand/logo-negro.svg
@@ -0,0 +1,5 @@
+
diff --git a/infra/clinica2/nginx-vhost b/infra/clinica2/nginx-vhost
new file mode 100644
index 0000000..01b55fd
--- /dev/null
+++ b/infra/clinica2/nginx-vhost
@@ -0,0 +1,47 @@
+# Segunda instancia (white-label) — frontend React + API Odoo en puerto 8070.
+#
+# Acceso LAN inmediato: http://192.168.10.114:8880
+# Acceso publico: requiere agregar el hostname en el dashboard del tunel
+# cloudflared (remotamente administrado, sin config local):
+# ingress: - hostname: clinica2.consultoria-as.com
+# service: http://localhost:80
+server {
+ listen 80;
+ listen 8880;
+ server_name clinica2.consultoria-as.com;
+
+ # Frontend React (mismo build que SKEEN; el brand sale del API /brand)
+ location / {
+ root /var/www/clinica2-frontend;
+ try_files $uri $uri/ /index.html;
+ add_header Cache-Control "no-cache";
+ }
+
+ # Odoo API para el frontend
+ location /api/odoo/ {
+ proxy_pass http://127.0.0.1:8070/;
+ proxy_http_version 1.1;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_read_timeout 120s;
+ }
+
+ # Backend Odoo (administracion directa, opcional)
+ location /web/ {
+ proxy_pass http://127.0.0.1:8070/web/;
+ proxy_http_version 1.1;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_read_timeout 120s;
+ }
+
+ # Escenario B: la instancia 2 no tiene WhatsApp. Aunque el backend tenga
+ # fallback a localhost:3000, aqui se corta la ruta: 403 fijo, sin excepciones.
+ location /api/odoo/skeen/frontend/v1/wacrm/ {
+ return 403;
+ }
+}
diff --git a/infra/clinica2/odoo-clinica2.service b/infra/clinica2/odoo-clinica2.service
new file mode 100644
index 0000000..3c80648
--- /dev/null
+++ b/infra/clinica2/odoo-clinica2.service
@@ -0,0 +1,19 @@
+[Unit]
+Description=Odoo CLINICA2 (skeen-odoo venv, instancia white-label)
+After=network.target postgresql.service
+Wants=postgresql.service
+
+[Service]
+Type=simple
+User=root
+WorkingDirectory=/root/skeen-odoo
+# Sin SUPABASE_URL / WACRM_API_* / HERMES_BRIDGE_URL a proposito: la instancia
+# 2 arranca en escenario B (sin WhatsApp). Los endpoints WACRM responden
+# "Falta configuracion" en vez de tocar la instancia compartida de SKEEN.
+ExecStart=/root/odoo-venv/bin/python /root/skeen-odoo/odoo-bin -c /root/clinica2-odoo.conf --logfile=/tmp/odoo2.log
+Restart=always
+RestartSec=5
+TimeoutStartSec=120
+
+[Install]
+WantedBy=multi-user.target
diff --git a/infra/clinica2/odoo.conf b/infra/clinica2/odoo.conf
new file mode 100644
index 0000000..f2b5ce0
--- /dev/null
+++ b/infra/clinica2/odoo.conf
@@ -0,0 +1,55 @@
+[options]
+addons_path = /root/skeen-odoo/addons,/root/skeen-odoo/odoo/addons
+admin_passwd = skeen_admin_2026
+csv_internal_sep = ,
+data_dir = /var/lib/odoo-clinica2
+db_host = localhost
+db_maxconn = 64
+db_name = clinica2_odoo
+db_password = skeen_dev_2026
+db_port = 5432
+db_sslmode = prefer
+db_user = skeen
+demo = {}
+email_from = False
+http_enable = True
+http_interface =
+http_port = 8070
+import_partial =
+limit_memory_hard = 2684354560
+limit_memory_soft = 2147483648
+limit_request = 8192
+limit_time_cpu = 60
+limit_time_real = 120
+limit_time_real_cron = -1
+list_db = True
+log_db = False
+log_db_level = warning
+log_handler = :INFO
+log_level = info
+logfile =
+longpolling_port = 8073
+max_cron_threads = 2
+osv_memory_age_limit = False
+osv_memory_count_limit = False
+pg_path =
+pidfile =
+proxy_mode = True
+reportgz = False
+screencasts =
+screenshots = /tmp/odoo_screenshots_clinica2
+server_wide_modules = base,web
+smtp_password = False
+smtp_port = 25
+smtp_server = localhost
+smtp_ssl = False
+smtp_ssl_certificate_filename = False
+smtp_ssl_private_key_filename = False
+smtp_user = False
+test_file =
+test_tags = None
+translate_modules = ['all']
+unaccent = False
+upgrade_path =
+without_demo = False
+workers = 0
diff --git a/infra/clinica2/postinstall.py b/infra/clinica2/postinstall.py
new file mode 100644
index 0000000..0eb334d
--- /dev/null
+++ b/infra/clinica2/postinstall.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""Post-instalación de la instancia clinica2_odoo (white-label, sin WACRM).
+
+- Brand neutro (skeen.clinic.brand) apuntando a logos genericos servidos por
+ el nginx de la instancia (no SKEEN).
+- skeen.menu_roles con /wacrm/* en lista vacia: modulo WhatsApp oculto para
+ todos (escenario B: la clinica nueva aun no tiene numero de WhatsApp).
+- Admin con password distinto a la instancia SKEEN y must_change_password.
+- Empresa principal renombrada al nombre neutro.
+"""
+import json
+import sys
+
+sys.path.insert(0, '/root/skeen-odoo')
+
+import odoo
+from odoo.tools import config
+
+config.parse_config([
+ '-c', '/root/clinica2-odoo.conf',
+ '--no-http',
+ '--log-level', 'error',
+])
+
+odoo.service.server.load_server_wide_modules()
+registry = odoo.registry(config['db_name'])
+
+BRAND = {
+ 'nombre': 'Clínica',
+ 'logo_claro': '/brand/logo-blanco.svg',
+ 'logo_oscuro': '/brand/logo-negro.svg',
+ 'pie': 'Sistema de gestión clínica',
+}
+
+ADMIN_PASSWORD = 'Clinica2Admin2026!'
+
+with registry.cursor() as cr:
+ env = odoo.api.Environment(cr, odoo.SUPERUSER_ID, {})
+ ICP = env['ir.config_parameter'].sudo()
+
+ # 1) Brand neutro
+ ICP.set_param('skeen.clinic.brand', json.dumps(BRAND, ensure_ascii=False))
+ print('brand:', ICP.get_param('skeen.clinic.brand'))
+
+ # 2) Ocultar WACRM para todos (lista vacia = ningun rol)
+ roles = json.loads(ICP.get_param('skeen.menu_roles') or '{}')
+ roles['/wacrm/messages'] = []
+ roles['/wacrm/leads'] = []
+ ICP.set_param('skeen.menu_roles', json.dumps(roles, ensure_ascii=False))
+ print('menu_roles wacrm:', roles.get('/wacrm/messages'), roles.get('/wacrm/leads'))
+
+ # 3) Admin: password propio de la instancia + cambio forzado
+ admin = env['skeen.frontend.user'].sudo().search([('login', '=', 'admin')], limit=1)
+ admin.set_password(ADMIN_PASSWORD)
+ admin.write({'must_change_password': True})
+ print('admin:', admin.login, 'must_change_password:', admin.must_change_password)
+
+ # 4) Empresa principal renombrada (el backend Odoo la muestra)
+ company = env['res.company'].sudo().search([], limit=1, order='id')
+ if company:
+ company.write({'name': 'Clínica'})
+ print('company:', company.name)
+
+ cr.commit()
+print('POST-INSTALL OK')
diff --git a/odoo-addons/skeen_citas/__manifest__.py b/odoo-addons/skeen_citas/__manifest__.py
index 56ac383..df4a2cb 100644
--- a/odoo-addons/skeen_citas/__manifest__.py
+++ b/odoo-addons/skeen_citas/__manifest__.py
@@ -14,6 +14,8 @@
'data': [
'security/ir.model.access.csv',
'data/sequences.xml',
+ # Menú padre primero: las vistas de abajo cuelgan de él.
+ 'views/menus.xml',
'views/cita_views.xml',
'views/bloqueo_views.xml',
'views/lista_espera_views.xml',
diff --git a/odoo-addons/skeen_citas/views/menu_views.xml b/odoo-addons/skeen_citas/views/menu_views.xml
index a1c33dd..fc0a740 100644
--- a/odoo-addons/skeen_citas/views/menu_views.xml
+++ b/odoo-addons/skeen_citas/views/menu_views.xml
@@ -1,10 +1,7 @@
-
-
-
-
-
-
\ No newline at end of file
+
diff --git a/odoo-addons/skeen_citas/views/menus.xml b/odoo-addons/skeen_citas/views/menus.xml
new file mode 100644
index 0000000..2a6606d
--- /dev/null
+++ b/odoo-addons/skeen_citas/views/menus.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/odoo-addons/skeen_inventario/views/inventario_views.xml b/odoo-addons/skeen_inventario/views/inventario_views.xml
index 12e30c3..51898fe 100644
--- a/odoo-addons/skeen_inventario/views/inventario_views.xml
+++ b/odoo-addons/skeen_inventario/views/inventario_views.xml
@@ -133,7 +133,7 @@
-
+