Art4Hotel Hub: código + documentación extensiva
ERP a la medida (Python stdlib + SQLite + vanilla JS SPA). Incluye server.py, index.html, utilidades y documentación: README, MODELO_DATOS, API, INSTALACION, CONTEXTO, NEGOCIO, WEB, ONBOARDING, VALOR_SISTEMA, CLAUDE. Secretos y datos (art4hotel.db, secret.key, ACCESOS.html, uploads/, backups/) excluidos vía .gitignore. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
122
INSTALACION.md
Normal file
122
INSTALACION.md
Normal file
@@ -0,0 +1,122 @@
|
||||
# Instalación y Despliegue — Art4Hotel Hub
|
||||
|
||||
Sin Docker, sin pip, sin CI/CD. Solo Python 3 y `systemd`.
|
||||
|
||||
---
|
||||
|
||||
## Requisitos
|
||||
|
||||
- **Python 3.8+** (stdlib únicamente — `http.server`, `sqlite3`, `hashlib`, `hmac`)
|
||||
- Linux con `systemd` (para correr como servicio). En Windows/Mac corre igual con `python3 server.py`.
|
||||
|
||||
---
|
||||
|
||||
## 1. Desarrollo local
|
||||
|
||||
```bash
|
||||
git clone https://git.consultoria-as.com/consultoria-as/art4hotel-hub.git
|
||||
cd art4hotel-hub
|
||||
python3 server.py
|
||||
# → http://localhost:4401
|
||||
```
|
||||
|
||||
Primera vez: la app pide **crear la cuenta admin** (pantalla de setup). Genera `art4hotel.db` y `secret.key` automáticamente.
|
||||
|
||||
---
|
||||
|
||||
## 2. Despliegue en servidor
|
||||
|
||||
### a) Copiar archivos
|
||||
|
||||
```bash
|
||||
scp server.py index.html backup.py usuario@servidor:/ruta/art4hotel-hub/
|
||||
```
|
||||
|
||||
> **No copiar** `secret.key` ni `art4hotel.db` desde tu máquina local — el servidor genera los suyos en el primer arranque (o migra los existentes en producción). Los datos del negocio viven solo en el servidor.
|
||||
|
||||
### b) Servicio systemd
|
||||
|
||||
`/etc/systemd/system/art4hotel-hub.service`:
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=Art4Hotel Hub
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=claude
|
||||
WorkingDirectory=/ruta/art4hotel-hub
|
||||
ExecStart=/usr/bin/python3 server.py
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
```bash
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now art4hotel-hub
|
||||
sudo systemctl status art4hotel-hub
|
||||
```
|
||||
|
||||
### c) Redespliegue (actualizar código)
|
||||
|
||||
```bash
|
||||
scp server.py index.html usuario@servidor:/ruta/art4hotel-hub/
|
||||
ssh usuario@servidor 'sudo systemctl restart art4hotel-hub'
|
||||
```
|
||||
|
||||
Las migraciones de esquema corren solas al reiniciar (idempotentes).
|
||||
|
||||
---
|
||||
|
||||
## 3. Acceso remoto (Tailscale)
|
||||
|
||||
El Hub vive en una red privada **Tailscale** (MagicDNS `iclaude`):
|
||||
|
||||
- **Privado** (equipos en la tailnet): `http://iclaude:4401/`
|
||||
- **Público** (si se requiere exponer): Tailscale **Funnel** en un puerto dedicado (443/8443/10000).
|
||||
|
||||
```bash
|
||||
tailscale funnel --bg 4401 # expone el Hub públicamente
|
||||
tailscale funnel status # ver qué está expuesto
|
||||
```
|
||||
|
||||
> Nota de seguridad: el Hub ya tiene login propio, pero exponerlo públicamente amplía la superficie de ataque. Mantener el login activo y contraseñas fuertes.
|
||||
|
||||
---
|
||||
|
||||
## 4. Respaldos
|
||||
|
||||
`backup.py` por cron diario:
|
||||
|
||||
```cron
|
||||
0 3 * * * cd /ruta/art4hotel-hub && /usr/bin/python3 backup.py
|
||||
```
|
||||
|
||||
Hace: online backup de la DB (seguro con WAL) + `uploads.tar.gz`. Retiene 30 días en `backups/`.
|
||||
También disponible bajo demanda desde la UI (`POST /api/backup-now`).
|
||||
|
||||
---
|
||||
|
||||
## 5. Reloj del servidor (importante)
|
||||
|
||||
El servidor de producción tiene CMOS muerto y NTP bloqueado; un reloj desfasado **rompe los logins basados en token** (Filebrowser/Immich) y firma de sesiones.
|
||||
Mitigación: cron `sync_clock.sh` que toma el header `Date` de `1.1.1.1` y ajusta la hora. Verificar `date` tras reinicios.
|
||||
|
||||
---
|
||||
|
||||
## 6. Solución de problemas
|
||||
|
||||
| Síntoma | Causa probable | Solución |
|
||||
|---|---|---|
|
||||
| "Sesión inválida" constante | reloj del servidor desfasado | corregir hora; revisar `sync_clock.sh` |
|
||||
| `secret.key` regenerado → todos deslogueados | se borró/cambió la clave | restaurar `secret.key`; es la clave de firma |
|
||||
| Imágenes equivocadas como ejemplo | prefijos de archivo | ver lógica `first_image` en `/api/file-counts` |
|
||||
| No resuelve nombres públicos | DNS de Tailscale sin upstream | `tailscale set --accept-dns=false` |
|
||||
|
||||
---
|
||||
|
||||
*Stack deliberadamente mínimo: todo el sistema cabe en una USB y corre con un solo `python3 server.py`.*
|
||||
Reference in New Issue
Block a user