diff --git a/.claude/rules/INDEX.md b/.claude/rules/INDEX.md index bde8f0ed..3182630a 100644 --- a/.claude/rules/INDEX.md +++ b/.claude/rules/INDEX.md @@ -17,3 +17,4 @@ Reglas operativas del proyecto. Cada archivo es una regla independiente. | 11 | [sources.md](sources.md) | Extraccion de funciones desde repos externos | | 12 | [notebook_collaboration.md](notebook_collaboration.md) | Colaboración en notebooks Jupyter via funciones del registry | | 13 | [frontend_theming.md](frontend_theming.md) | Componentes propios y sistema de temas en frontends | +| 14 | [deploy.md](deploy.md) | Deploy de apps a VPS remotos via SSH + systemd + rsync | diff --git a/.claude/rules/deploy.md b/.claude/rules/deploy.md new file mode 100644 index 00000000..55bb1827 --- /dev/null +++ b/.claude/rules/deploy.md @@ -0,0 +1,134 @@ +## Deploy de apps a VPS remotos + +### Arquitectura + +El sistema de deploy usa SSH + systemd + rsync. No Docker, no Kubernetes. + +- **Conexiones SSH** → `~/.ssh/config` (alias, IP, user, key). Ya hay funciones CRUD: `ssh_config_read`, `ssh_config_find`, `ssh_config_parse`. +- **Config de deploy** → `apps/deploy_server/operations.db` tabla `deploy_targets` (app, host, remote_dir, build_cmd, port, health_path, env). +- **Logs de deploy** → misma BD, tabla `deploy_logs` (app, host, status, trigger, duration_ms, error). + +### App: `deploy_server` (`apps/deploy_server/`) + +CLI + servidor HTTP. Binario: `deploy_server`. Build: `CGO_ENABLED=1 go build -o deploy_server .` + +```bash +cd apps/deploy_server + +# Gestionar targets +./deploy_server target add --app --host --port --health /path --build "comando" [--user deploy] [--env '{"K":"V"}'] +./deploy_server target list +./deploy_server target remove + +# Setup inicial (primera vez, crea dirs + systemd unit) +./deploy_server setup --host + +# Deploy continuo (build local → rsync → restart → health check) +./deploy_server deploy [--host ] + +# Estado del servicio remoto +./deploy_server status +./deploy_server status --all + +# Servidor webhook (auto-deploy en cada push a Gitea) +./deploy_server serve --port 9090 +``` + +### Funciones del registry involucradas + +| Función | Qué hace | Purity | +|---|---|---| +| `rsync_deploy_bash_infra` | rsync local→remoto con exclusiones | impure | +| `systemd_generate_unit_go_infra` | Genera texto .service | **pure** | +| `systemd_install_go_infra` | Sube unit + daemon-reload + enable + start | impure | +| `systemd_restart_go_infra` | Reinicia servicio remoto | impure | +| `systemd_status_go_infra` | Estado + logs de servicio remoto | impure | +| `vps_setup_app_go_infra` | Crea dirs + usuario en VPS | impure | +| `gitea_create_webhook_bash_infra` | Crea webhook push en Gitea | impure | +| `setup_vps_app_go_infra` | Pipeline: setup completo primera vez | impure | +| `deploy_app_remote_go_infra` | Pipeline: deploy continuo | impure | + +Tipo: `DeployConfig_go_infra` — struct con toda la config de deploy. + +### Workflow para un agente + +Cuando el usuario diga **"sube esta app a este VPS"** o **"deploya X en Y"**: + +#### 1. Verificar que el host SSH existe + +```bash +grep "^Host " ~/.ssh/config +# Si no existe el alias, añadirlo: +# Usar ssh_config_add_entry o editar ~/.ssh/config directamente +``` + +#### 2. Verificar conectividad + +```bash +ssh -o BatchMode=yes -o ConnectTimeout=5 true +``` + +#### 3. Registrar el target en deploy_server + +```bash +cd apps/deploy_server +# Build deploy_server si no existe el binario +CGO_ENABLED=1 go build -o deploy_server . + +./deploy_server target add \ + --app \ + --host \ + --port \ + --health \ + --build "CGO_ENABLED=0 GOOS=linux go build -o ." \ + --user deploy +``` + +#### 4. Setup inicial + +```bash +./deploy_server setup --host +``` + +Esto crea dirs en `/opt/apps//`, sube el código, genera el unit systemd e instala el servicio. + +#### 5. Deploys posteriores + +```bash +./deploy_server deploy +``` + +Build local → rsync → restart systemd → health check. + +#### 6. Auto-deploy con webhook (opcional) + +```bash +# Lanzar servidor +./deploy_server serve --port 9090 + +# Crear webhook en Gitea +source bash/functions/infra/gitea_create_webhook.sh +gitea_create_webhook "" "" "http://:9090/webhook/push" "" +``` + +### Requisitos en el VPS + +- SSH accesible con key auth (configurado en `~/.ssh/config` local) +- El usuario SSH debe tener **sudo sin password** para: `systemctl`, `mv` a `/etc/systemd/system/`, `mkdir` en `/opt/apps/`, `useradd`, `chown` +- `rsync` instalado en el VPS +- Puerto del servicio abierto en el firewall del VPS + +### Builds por lenguaje + +| Lenguaje | Build command típico | +|---|---| +| Go | `CGO_ENABLED=0 GOOS=linux go build -o .` | +| Go + SQLite | `CGO_ENABLED=1 GOOS=linux go build -tags fts5 -o .` | +| Python | No build — rsync sube los .py, systemd ejecuta `python3 main.py` | +| Bash | No build — rsync sube los .sh, systemd ejecuta `bash main.sh` | + +Para Go con CGO (SQLite), el VPS debe tener `gcc` y `libc-dev`, o cross-compilar con `CGO_ENABLED=0` si la app no usa SQLite. + +### Exclusiones de rsync + +El deploy excluye automáticamente: `.git`, `operations.db*`, `*.exe`, `node_modules`, `.venv`, `__pycache__`, `build/`, `*.db-shm`, `*.db-wal`, `registry.db`. diff --git a/.gitignore b/.gitignore index 755e00c7..8a8bcc66 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,13 @@ python/.venv/ apps/*/ analysis/*/ +# Projects (each is its own git repo, only project.md templates are versioned) +projects/*/ + +# Vaults — data stores (symlinks, dirs, files); only vault.yaml manifest is versioned +vaults/*/ +!vaults/vault.yaml + # Node / pnpm **/node_modules/ diff --git a/docs/templates/project.md b/docs/templates/project.md new file mode 100644 index 00000000..ecddc590 --- /dev/null +++ b/docs/templates/project.md @@ -0,0 +1,10 @@ +--- +name: my_project +description: "Descripcion breve del proyecto." +tags: [] +repo_url: "" +--- + +## Notas + +Notas adicionales sobre el proyecto.