# Art4Hotel Hub — Índice y Contexto para Claude > Punto de entrada. Aquí está el mapa de TODO: documentación, sitios/servicios y accesos. > Última actualización: 2026-06-06 --- ## 📚 ÍNDICE DE DOCUMENTACIÓN (qué hay y dónde) | Documento | Cubre | Léelo cuando… | |---|---|---| | **[NEGOCIO.md](./NEGOCIO.md)** | Contexto del negocio: clientes, productos, flujo real, equipo, reglas | …antes de cualquier cambio (la app refleja el negocio) | | **[CONTEXTO.md](./CONTEXTO.md)** | Estado técnico del Hub: stack, modelo de datos, producto unificado, catálogos, galería de ejemplos, archivos, ventas | …vas a tocar código del Hub | | **[WEB.md](./WEB.md)** | Sitio público art4hotel.com + `sync_catalogo.py` (Hub → web) | …trabajas en la página pública o el sync | | **[ONBOARDING.md](./ONBOARDING.md)** | Handover: acceso, arquitectura, tabs del SPA, fórmula de margen | …repaso general rápido | | **[VALOR_SISTEMA.html](./VALOR_SISTEMA.html)** | Valor/costo del sistema, hosting, esquema (para presentar a terceros) | …explicar el sistema o cotizarlo a alguien | | **[ACCESOS.html](./ACCESOS.html)** | Tarjeta de accesos de usuario final (links de servicios) | …recordar cómo entrar a cada servicio | --- ## 🌐 MAPA DE SITIOS / SERVICIOS (servidor "iclaude") Todo corre en el servidor **iclaude** (`192.168.50.46`, una Surface vieja). Acceso por **Tailscale** (red privada) salvo lo marcado público. ### Proyectos web (cada uno su propio puerto, todos del usuario) Cada sitio tiene acceso **directo por Tailscale** (`iclaude:PUERTO`, requiere Tailscale activo) y, si está en Funnel, también una **URL pública** (desde cualquier lado, sin Tailscale). | Puerto | Sitio | Acceso privado (Tailscale) | Acceso público (Funnel) | Notas | |---|---|---|---|---| | **4401** | **Art4Hotel Hub** (este proyecto) | `http://iclaude:4401` | — (privado) | Login (usuario `claude`). Operaciones/ventas/catálogo | | **4402** | **Airbnb Pricing** | `http://iclaude:4402` | — (privado) | Panel pricing Airbnb (Hacienda Cabo Bello / Casa Montoya) | | **4403** | **Catálogo** | `http://iclaude:4403` | `https://iclaude.tail69ab9b.ts.net:8443/` 🌍 | Login. Público vía Funnel | | **4404** | **Portafolio** | `http://iclaude:4404` | `https://iclaude.tail69ab9b.ts.net/` 🌍 | Público vía Funnel (raíz) | **Cada proyecto tiene su carpeta y su propia documentación en el servidor:** | Proyecto | Carpeta | Servicio systemd | Su doc | |---|---|---|---| | Hub | `/mnt/iclaude/art4hotel-hub/` | `art4hotel-hub.service` | este `CLAUDE.md` + los .md de abajo | | Airbnb Pricing | `/mnt/iclaude/airbnb-pricing/` | `airbnb-pricing.service` | `NEGOCIO.md` | | Catálogo | `/mnt/iclaude/catalogo-borrador/` | `catalogo-borrador.service` | `CLAUDE.md` | | Portafolio/Foto Studio | `/mnt/iclaude/foto-studio/` | `foto-studio.service` | `CLAUDE.md` | Todos comparten el mismo stack (Python stdlib + SQLite + vanilla JS) y se reinician con `sudo systemctl restart `. ### Servicios de nube personal (Docker) | Servicio | Puerto | Acceso | Usuario | |---|---|---|---| | **Immich** (fotos) | 2283 | `iclaude:2283` | `claudeandrefg@gmail.com` | | **Filebrowser** (archivos) | 8085 | `iclaude:8085` | `admin` (carpeta `/mnt/iclaude/escritorio`) | ### Sitio público externo | Sitio | Dónde | Notas | |---|---|---| | **art4hotel.com** | GitHub Pages (NO en el servidor) | Landing + catálogo + wizard de leads. Repo `Claudeandrefg/art4hotel`. Se alimenta del Hub vía `sync_catalogo.py` | --- ## 🔧 INFRAESTRUCTURA (claves del servidor) - **Acceso admin**: `ssh claude@192.168.50.46` (o `claude@iclaude` por Tailscale). Usuario `claude`, sudo sin password, llave SSH. - **Tailscale**: red privada. MagicDNS activo → `iclaude` resuelve a `100.110.177.1`. Tailnet: `tail69ab9b.ts.net`. Dispositivos: iphone, macbook, pixel. - **Tailscale Funnel**: expone a internet `:443 → 4404 (Portafolio)` y `:8443 → 4403 (Catálogo)`. - **⏰ Reloj**: la Surface tiene CMOS muerta (RTC=2009) y NTP bloqueado. `sync_clock.sh` (cron @reboot + cada hora) lo corrige desde IPs fijas (1.1.1.1). **Si los logins fallan con "logged out due to inactivity" → revisar el reloj** (`date`); era el bug raíz. - **DNS**: Tailscale ya NO gestiona el DNS (`--accept-dns=false`); usa 1.1.1.1/8.8.8.8. Resuelve nombres públicos OK. - **RAM**: solo 3.7GB (sin ampliar). Apagados Odoo/NocoDB/Jellyfin/qBittorrent/pihole para liberar. NO instalar plataformas pesadas (n8n, etc.) — usar scripts ligeros (Python stdlib/cron). - **Backups**: cron diario medianoche → `backup.py` (DB + uploads, 30 días en `backups/`). --- ## ⚠️ Principio clave: producto = fuente única de verdad Cada atributo de producto impacta hasta 3 funciones. Antes de agregar/cambiar uno, define su impacto en: **(1) Operación/producción · (2) Catálogo/cotizador · (3) Página web**. ## Deploy del Hub - Host: `claude@192.168.50.46` · Path: `/mnt/iclaude/art4hotel-hub/` - Restart: `sudo systemctl restart art4hotel-hub` - Deploy: `scp index.html server.py claude@192.168.50.46:/mnt/iclaude/art4hotel-hub/ && ssh claude@192.168.50.46 "sudo systemctl restart art4hotel-hub"` ## Convenciones de edición - Toda edición a `index.html` o `server.py` se hace LOCAL aquí y se despliega con scp. - Después de cualquier cambio en DB (ALTER TABLE, migración), verificar con SSH que se aplicó. - No instalar dependencias nuevas — stack es Python stdlib + vanilla JS. Si una feature lo requiere, discutir antes. - Cambios masivos (renombrar IDs, reorganizar tablas) → backup primero: `cp art4hotel.db art4hotel.db.bak_`. - Listas de personalización: editar la tabla `trabajos` en DB, no hardcodear en index.html. Hay `TRABAJO_OPTS` como fallback + `trabajoOpts()` helper que prefiere `S.trabajos` dinámico. ## Tareas frecuentes - **Ver duplicados**: `python3 -c "import sqlite3; c=sqlite3.connect('art4hotel.db'); print(list(c.execute('SELECT orden_id,COUNT(*) FROM ordenes GROUP BY orden_id HAVING COUNT(*)>1')))"` - **Backup manual**: `cp art4hotel.db art4hotel.db.bak_$(date +%Y%m%d_%H%M%S)` - **Logs del servicio**: `sudo journalctl -u art4hotel-hub -n 50 --no-pager` ## Si Clod te pide algo - Si es feature nueva → propón primero antes de implementar (usar AskUserQuestion). - Si es fix → identifica la causa raíz, confírmala con el código y datos, después arregla. - Si es cambio cosmético → directo, sin overthink.