# Referencia: Docker runtime, base de datos local y fixes (split repos)

Este documento resume el trabajo hecho alrededor del **runtime Docker** (`cd-runtime`), **SQLite local**, **migraciones** y la dependencia **Doctrine DBAL**, para retomarlo después sin depender del chat.

Guías relacionadas que ya existían:

- `docs/repo-split-playbook.md` — bootstrap de repos split, PR al monorepo, sync local.
- `docs/split-repo-local-dev.md` — plantillas `docker-compose`, `dev.ps1`, imagen GHCR.

---

## 1. Qué es el runtime

- **Imagen**: se construye con `infrastructure/runtime/Dockerfile` (contexto: raíz del repo).
- **Publicación**: workflow `.github/workflows/build-runtime-image.yml` → típicamente `ghcr.io/<ORG>/cd-runtime:latest`.
- **Entrypoint**: `infrastructure/runtime/entrypoint.sh`
  - Asegura `vendor` (Composer si falta).
  - Copia `.env` desde `.env.example` si no existe.
  - **Fuerza SQLite** en local Docker (`DB_CONNECTION=sqlite`, `DB_DATABASE=.../database/database.sqlite`) y crea el archivo vacío.
  - Genera `APP_KEY` si falta.
  - Limpia caches de Laravel.
  - **Migraciones automáticas solo si** `AUTO_MIGRATE=1` en el entorno del contenedor; si no, hay que ejecutar `migrate` a mano (ver §4).
  - Arranca `php artisan serve` en `0.0.0.0:8000` (mapear en host, p. ej. `8080:8000`).

---

## 2. Plantillas para devs (sin clonar `cd-system`)

En cada repo split se copian al root:

- Frontend: `docs/split-repo-templates/frontend/docker-compose.yml`, `dev.ps1`, `stop.ps1`.
- Backend modules: `docs/split-repo-templates/backend-modules/...` (puerto distinto en el ejemplo).

Hay que sustituir `YOUR_ORG` por la organización real de GitHub en la imagen.

Variables típicas en compose:

- `DB_CONNECTION: sqlite`
- `DB_DATABASE: /var/www/html/database/database.sqlite`

El volumen solo monta la carpeta de trabajo (views o `app/Modules`); **no sustituye todo el monorepo**: la app completa viene **dentro de la imagen**.

---

## 3. Error: `no such table: settings` (y similares)

**Causa**: SQLite existe pero **no se aplicaron migraciones**; Laravel intenta leer `settings` (p. ej. `maintenance_mode`) y la tabla no está.

**Qué hacer** (contenedor ya arriba, servicio llamado `app` en la plantilla):

```powershell
docker compose exec app php artisan migrate --force
```

Opcional si usáis seeders que poblen datos:

```powershell
docker compose exec app php artisan db:seed --force
```

**Datos “iguales que producción”**: `migrate` solo aplica el **esquema según migraciones del código**. Para copiar datos reales hace falta **dump SQL + MySQL** (u otro motor) y variables `DB_*` acordes; no se obtiene solo con SQLite vacío + migrate.

**Migraciones al arrancar**: en `docker-compose.yml`, en el servicio `app`:

```yaml
environment:
  AUTO_MIGRATE: "1"
```

Así el entrypoint ejecuta `php artisan migrate --force` al iniciar (útil en demos; en equipos que prefieren control manual, dejarlo en `0` o sin definir).

---

## 4. Error: `Changing columns for table "posts" requires Doctrine DBAL`

**Causa**: migraciones que usan `$table->...->change()` necesitan el paquete **`doctrine/dbal`**.

**Fix en el monorepo** (ya aplicado en `cd-system`):

- En `composer.json`: `"doctrine/dbal": "^3.5"` (u otra versión compatible con Laravel 9).
- `composer.lock` actualizado para que `composer install` instale DBAL.

**Importante para Docker**: el `vendor` de la imagen se genera en el **build** (`composer install --no-dev` en el Dockerfile). Tras cambiar `composer.json` / `composer.lock`:

1. Hacer **commit y push** al branch que dispara el workflow (p. ej. `cd-system`).
2. Esperar a que GitHub Actions publique la imagen nueva (o construir localmente la misma Dockerfile).
3. En el equipo: `docker compose pull` (si usan la etiqueta `:latest`) y volver a levantar.
4. Ejecutar de nuevo:

```powershell
docker compose exec app php artisan migrate --force
```

Sin imagen nueva, el contenedor sigue sin DBAL en `vendor` y la migración fallará igual.

---

## 5. Otros detalles que ya tocamos

- **`APP_KEY`**: no usar un placeholder fijo en compose si podéis evitarlo; el entrypoint puede generar una clave válida si el `.env` del contenedor no la tiene.
- **Silenciar fallos de Composer en la imagen**: el Dockerfile debe **no** ocultar errores de `composer install`; si falla, la imagen no debería considerarse válida.
- **Silenciar fallos de migrate en entrypoint**: si `AUTO_MIGRATE=1` usa `|| true`, un fallo de migración puede pasar desapercibido; revisar logs del contenedor.
- **Windows / scripts shell**: `.gitattributes` con `*.sh text eol=lf` evita `bash\r` en Linux.
- **Prod / `--no-dev`**: registro condicional de paquetes solo de desarrollo (p. ej. Ide Helper) con `class_exists` para no romper cuando no están las dev-dependencies.

---

## 6. Git: push cuando el remoto va por delante

Si `git push` rechaza por commits nuevos en `origin`:

```powershell
git pull --rebase origin <branch>
git push origin <branch>
```

---

## 7. Checklist rápido cuando “no levanta” o falla la app

1. ¿La imagen es reciente? (`docker compose pull` / rebuild tras cambios en `composer.lock`).
2. ¿Corrieron migraciones? (`migrate --force` o `AUTO_MIGRATE=1`).
3. ¿Error de columna `->change()`? ¿Está `doctrine/dbal` en la imagen? (rebuild tras commit).
4. ¿Solo falta datos? Considerar seed o DB externa / dump, no solo SQLite vacío.

---

## 8. Archivos clave (rutas en `cd-system`)

| Pieza | Ruta |
|--------|------|
| Dockerfile runtime | `infrastructure/runtime/Dockerfile` |
| Entrypoint | `infrastructure/runtime/entrypoint.sh` |
| Workflow GHCR | `.github/workflows/build-runtime-image.yml` |
| Plantilla compose frontend | `docs/split-repo-templates/frontend/docker-compose.yml` |
| Plantilla compose backend | `docs/split-repo-templates/backend-modules/docker-compose.yml` |
| Bootstrap split repos | `scripts/bootstrap-split-repos.ps1` |
| Sync local monorepo | `scripts/sync-split-local.ps1` |

---

*Documento de continuidad operativa; si el flujo cambia, actualizar este archivo o las guías enlazadas arriba.*
