Files
SKEEN-Proyecto/docs/segunda-instancia.md
Consultoría Alcaraz Salazar 582c267ec0 segunda instancia white-label (clinica2) + fix de orden de menus en instalacion limpia
Infra (todo convive en la misma VPS, mismo addons_path read-only):
- infra/clinica2/: odoo.conf (puerto 8070, db clinica2_odoo, data_dir
  propio), odoo-clinica2.service (sin env vars de WACRM/Supabase/Hermes),
  nginx-vhost (80 con server_name clinica2.consultoria-as.com + 8880 LAN,
  /api/odoo -> 8070, /wacrm/ cortado con 403), postinstall.py (brand neutro,
  menu WACRM vacio, admin con password propio y must_change_password)
- docs/segunda-instancia.md: mapa completo de la instalacion, pasos para
  reproducir (instancia 3+), pendiente del hostname en dashboard del tunel
  (remotamente administrado), aislamiento de datos escenario B
- frontend/public/brand/: logos SVG neutros + favicon para la instancia 2

Fix de menus (aplica a todas las instalaciones limpias, una sola pasada):
- menu_skeen_root se mueve a skeen_pacientes (modulo raiz de la jerarquia);
  en bases existentes se transfirio el ownership del xmlid (ir_model_data)
  asi actualizar no duplica el menu
- menu_skeen_citas (padre) se declara en skeen_citas/views/menus.xml que
  carga antes que bloqueo/lista_espera; menu_views.xml conserva las entradas
  con action (cargan despues de cita_views, donde se define la accion)
- referencias actualizadas: pacientes(catalogos/recetas), monedero, ventas,
  inventario, visitas -> skeen_pacientes.menu_skeen_root

Verificacion: produccion (skeen_odoo) actualizada sin duplicar menus y API
intacta; instalacion limpia clinica2_odoo 9 modulos OK; 15/15 tests
end-to-end (brand neutro, login admin, WACRM oculto+403, datos vacios)
2026-10-08 00:44:30 +00:00

4.6 KiB
Raw Blame History

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:

- 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.