# Arquitectura de sincronización cd-frontend-dev ↔ cd-system

> **Audiencia**: maintainers de cd-system que necesitan modificar/extender qué se sincroniza entre repos.
> **Doc operativo de PRs (etapas, comandos, troubleshooting)**: [`../infrastructure/06-frontend-pr-workflow.md`](../infrastructure/06-frontend-pr-workflow.md)
> **Última actualización**: 2026-05-04 (v2 — sincronización bidireccional)

Este doc cubre **qué archivos se sincronizan, cómo se exponen al dev (volumes Docker), y qué cambiar cuando hay que ampliar el scope**.

## Sincronización bidireccional (desde 2026-05-04)

Hay **dos workflows simétricos** que mantienen ambos repos alineados:

| Sentido | Workflow | Trigger | Acción | Por qué |
|---------|----------|---------|--------|---------|
| `cd-frontend-dev` → `cd-system` | `cd-frontend-dev/.github/workflows/sync-to-main.yml` | Push a `main` con cambios en `resources/**` o `public/**` | Abre/actualiza PR contra `cd-system @ staging-frontend` (branch `frontend-sync/pending`) | El cambio del dev frontend necesita revisión humana antes de entrar al monorepo |
| `cd-system` → `cd-frontend-dev` | `cd-system/.github/workflows/sync-to-frontend-dev.yml` | Push a **`cd-system`** (productiva) con cambios en paths sincronizables | Push directo a `cd-frontend-dev/main` | El cambio ya pasó revisión en cd-system; no tiene sentido pedir revisión doble |

**Anti-loop**: cada workflow detecta y skipea commits del otro:
- `sync-to-main.yml` skipea commits cuyo mensaje arranca con `chore: sync desde cd-system`.
- `sync-to-frontend-dev.yml` skipea commits cuyo mensaje arranca con `feat(frontend): sync desde cd-frontend-dev`.

**Secrets requeridos**:
- En `cd-frontend-dev`: `CD_SYSTEM_PAT` (PAT classic con scope `repo` sobre cd-system)
- En `cd-system`: `CD_FRONTEND_DEV_PAT` (PAT classic con scope `repo` sobre cd-frontend-dev)

**Resultado**: el dev frontend siempre tiene la última versión maestra al hacer `git pull`. El maintainer no puede crear drift silencioso editando directo en cd-system.

---

## El problema que resuelve

`cd-system` es un monorepo Laravel completo. `cd-frontend-dev` es un repo mínimo pensado para devs frontend. Para que un dev frontend pueda **editar y testear localmente** los archivos visuales, necesitamos:

1. **Que los archivos editables existan en su filesystem local** (clonados con el repo).
2. **Que sus ediciones se reflejen en su browser local** (volume mounts Docker).
3. **Que sus pushes lleguen a cd-system para revisión** (GH Actions workflow).

Las 3 piezas tienen que estar **alineadas**. Si una falla, el dev no puede trabajar.

---

## Las 4 capas de sincronización

```
┌──────────────────────────────────────────────────────────┐
│ CAPA 1 — Repo cd-frontend-dev (lo que el dev tiene)     │
│   git clone trae estos paths a su laptop                │
└──────────────────────────────────────────────────────────┘
                          │
                          │ docker compose up -d
                          ▼
┌──────────────────────────────────────────────────────────┐
│ CAPA 2 — Container Docker (lo que el browser sirve)     │
│   docker-compose.yml monta los paths sobre la imagen    │
│   ghcr.io/lacompaniadigital/cd-system:latest            │
└──────────────────────────────────────────────────────────┘
                          │
                          │ git push origin main (cd-frontend-dev)
                          ▼
┌──────────────────────────────────────────────────────────┐
│ CAPA 3 — Workflow Sync DEV→MAESTRO (review gate)        │
│   cd-frontend-dev/.github/workflows/sync-to-main.yml    │
│   filtra paths y abre PR contra staging-frontend        │
└──────────────────────────────────────────────────────────┘
                          ▲
                          │ git push origin main (cd-system, post-merge)
                          │
┌──────────────────────────────────────────────────────────┐
│ CAPA 4 — Workflow Sync MAESTRO→DEV (broadcast)          │
│   cd-system/.github/workflows/sync-to-frontend-dev.yml  │
│   escucha pushes a cd-system (branch productiva) y      │
│   pushea directo a cd-frontend-dev/main                 │
└──────────────────────────────────────────────────────────┘
```

> **Nota 1**: la capa 4 cierra el círculo. Antes (v1) la sincronización era unidireccional → riesgo de drift silencioso si el maintainer editaba paths sincronizables directo en cd-system.
>
> **Nota 2 (2026-05-05)**: en cd-system la branch productiva es `cd-system`, no `main`. La rama `main` quedó con histories no relacionadas (initial commit distinto) y está abandonada. El sync inverso escucha `cd-system` directamente. La rama `staging-frontend` está basada en `cd-system` HEAD.

### Capa 1 — Paths en el repo cd-frontend-dev

Lo que se clona cuando un dev hace `git clone`:

| Path | Contenido |
|------|-----------|
| `resources/views/modules/cd-base/frontend/` | Welcome / about / contact de cada demo + partials del demo |
| `resources/views/layout/front/headers/` | Headers de los 18 demos activos + default |
| `resources/views/layout/front/footers/` | Footers idem |
| `resources/views/layout/front/partials/` | Page-headers (17) + 5 partials default (`_header`, `_footer`, `_styles`, `_scripts`, `_whatsapp`) |
| `public/template/css/demos/` | CSS de los 18 demos activos |
| `public/template/css/skins/` | Skins (paletas) de 17 demos (creative-portfolio sin skin propio) |
| `public/template/js/demos/` | JS custom de los 12 demos que lo usan |
| `docker-compose.yml`, `Makefile`, `.env.docker`, `.gitignore` | Setup local |
| `README.md`, `docs/comandos/demos.md` | Doc operativa mínima (referencia a cd-system para el resto) |
| `.github/workflows/sync-to-main.yml` | El workflow que sincroniza |

### Capa 2 — Volume mounts en docker-compose.yml

```yaml
services:
  app:
    image: ghcr.io/lacompaniadigital/cd-system:latest
    volumes:
      # Vistas de cada demo
      - ./resources/views/modules/cd-base/frontend:/var/www/html/resources/views/modules/cd-base/frontend
      # Headers, footers, page-headers, partials defaults
      - ./resources/views/layout/front:/var/www/html/resources/views/layout/front
      # CSS por demo + skins
      - ./public/template/css/demos:/var/www/html/public/template/css/demos
      - ./public/template/css/skins:/var/www/html/public/template/css/skins
      # JS custom por demo
      - ./public/template/js/demos:/var/www/html/public/template/js/demos
```

**Regla clave**: cualquier path montado **sobrescribe** el contenido del container en ese mismo path. Por eso el dev edita en su laptop y ve el cambio sin rebuildear la imagen.

**No se montan**:
- `app/`, `config/`, `database/`, `routes/`, `bootstrap/` — backend Laravel, fuera del scope frontend.
- `app/Modules/<X>/` — módulos funcionales (Blog, Services, etc.), fuera del scope.
- `resources/views/modules/<X>/` (que no sean cd-base) — vistas de cada módulo, viven solo en cd-system.
- `public/cd-project/img/demos/<X>/` — 82 MB de imágenes. Disponibles dentro del container (vienen en la imagen), pero no editables localmente. Si un dev necesita modificar imágenes, las pide al maintainer.

### Capa 3 — Workflow filter (`sync-to-main.yml`)

```yaml
on:
  push:
    branches: [main]
    paths:
      - "resources/**"
      - "public/**"
```

El workflow se dispara **solo** si el push tocó algo bajo `resources/**` o `public/**`. Cualquier path que agreguemos a la Capa 1 + 2 dentro de esos prefijos quedará automáticamente cubierto.

> Si en el futuro agregamos un path top-level distinto (ej. `assets/`), hay que actualizar este filter.

---

## Cómo agregar un nuevo path al sync

Si querés que el dev pueda editar algo nuevo (ej. `resources/views/layout/front/sidebars/`):

| # | Acción | Donde |
|---|--------|-------|
| 1 | Copiar los archivos al repo | `cd-frontend-dev/resources/views/layout/front/sidebars/` |
| 2 | Agregar volume mount | `cd-frontend-dev/docker-compose.yml` |
| 3 | Verificar que el path esté bajo `resources/**` o `public/**` | `cd-frontend-dev/.github/workflows/sync-to-main.yml` |
| 4 | **Agregar el path al filter del sync inverso** | `cd-system/.github/workflows/sync-to-frontend-dev.yml` (sección `paths:` y regex de `git diff`) |
| 5 | Documentar en anatomía | `cd-system/docs/bewpro2.0/repo-frontend-dev/anatomia-de-un-demo.md` |
| 6 | Documentar en este doc (capa 1 + 2) | acá |
| 7 | Bump versión en README.md de cd-frontend-dev | `cd-frontend-dev/README.md` |
| 8 | Commit en cd-frontend-dev → smoke test | push a `cd-frontend-dev/main`, verificar PR auto |
| 9 | Smoke test del sync inverso | tocar el archivo en cd-system/main, verificar que aparece en cd-frontend-dev |

---

## Cómo quitar paths del sync

Lo opuesto: si decidimos que cierto path **no debe** ser editable por devs frontend (ej. `_styles.blade.php` porque tiene lógica que rompe en mal manos):

1. Mover el archivo a un path sin volume mount (ej. dentro de `app/`).
2. Eliminarlo del repo cd-frontend-dev.
3. Quitar el volume mount si aplicaba.
4. Documentar el cambio acá + en anatomía.

---

## Implicancias de no respetar la separación

Algunos riesgos si no respetamos las 4 capas alineadas:

| Escenario | Síntoma | Cómo evitarlo |
|-----------|---------|---------------|
| Archivo en repo pero no en volume | Dev edita, ve cambio en su laptop, pero el browser local no lo refleja | Capa 2 alineada con Capa 1 |
| Volume mount sin archivo en repo | Container arranca con un mount vacío → page errors 500 | Verificar que la carpeta existe en el repo (aunque sea vacía con `.gitkeep`) |
| Path no cubierto por workflow filter (capa 3) | Dev pushea, no se abre PR | Verificar `paths:` en `sync-to-main.yml` |
| Path no cubierto por filter del sync inverso (capa 4) | Maintainer edita en cd-system, no se propaga a cd-frontend-dev → drift silencioso | Verificar `paths:` en `sync-to-frontend-dev.yml` cubre el mismo conjunto que la capa 3 |
| Bucle infinito entre los 2 workflows | Cada commit dispara el otro, infinitos runs | Filter por mensaje de commit (ya implementado: `chore: sync desde cd-system` / `feat(frontend): sync desde cd-frontend-dev`) |
| Archivo agregado al filter pero no copiado a cd-system tras merge | El cambio nunca llega a producción | Etapas 3a y 3b del flujo de PRs |

## Troubleshooting del sync inverso (cd-system → cd-frontend-dev)

### "Edité un demo en cd-system/main pero no aparece en cd-frontend-dev"

```bash
# 1. ¿El push tocó algún path sincronizable?
gh api repos/LACOMPANIADIGITAL/cd-system/commits/<sha> -q '.files[].filename'

# 2. ¿El workflow corrió?
gh run list --repo LACOMPANIADIGITAL/cd-system --workflow=sync-to-frontend-dev.yml --limit 3

# 3. Si falló: ver log
gh run view <run-id> --repo LACOMPANIADIGITAL/cd-system --log-failed
```

Causas comunes:
- Path fuera del filter (ej. archivo en `resources/views/modules/blog/` no se sincroniza, solo `cd-base/frontend/`).
- Secret `CD_FRONTEND_DEV_PAT` ausente o expirado.
- Mensaje de commit accidentalmente arranca con `feat(frontend): sync desde cd-frontend-dev` → workflow se skipea.

### "Veo dos commits idénticos haciendo ping-pong entre los repos"

→ El anti-loop falló. Verificar:
- En cd-system, el commit del sync arranca con `chore: sync desde cd-system` exactamente.
- En cd-frontend-dev, el filter `if: !startsWith(...)` está activo en `sync-to-main.yml`.

### "Tengo conflictos al hacer git pull en cd-frontend-dev"

→ Editaste algo localmente que también cambió en cd-system. Resolver como cualquier conflicto git:

```bash
git pull --rebase origin main
# Resolver conflictos manualmente
git add <archivos resueltos>
git rebase --continue
git push
```

---

## Decisiones registradas

| Pregunta | Respuesta | Por qué |
|----------|-----------|---------|
| ¿Incluir las imágenes (82 MB) en el repo? | **No** (están en la imagen Docker, no editables localmente) | Mantener el repo liviano. Si un dev necesita cambiar imágenes, lo pide al maintainer |
| ¿Incluir todos los CSS legacy (59) o solo los activos (18)? | **Solo activos** | Los demos legacy no se usan; mantienen el repo limpio |
| ¿Replicar la doc completa en cd-frontend-dev? | **No** — solo README operativo mínimo | Una sola fuente de verdad: `cd-system/docs/bewpro2.0/repo-frontend-dev/`. Evita drift |
| ¿Permitir editar partials defaults (`_header`, `_footer`, etc.)? | **Sí pero con cuidado** | Son orquestadores — un mal cambio rompe todos los demos. Documentado como "regla crítica" |
| ¿Incluir los `dynamic-header.blade.php` de los módulos? | **No por ahora** | Son del scope de los módulos, no del demo. Si en el futuro un dev frontend tiene que retocarlos, evaluamos |
| ¿Sincronización bidireccional? | **Sí** (desde 2026-05-04) | Sin sync inverso, el maintainer puede editar paths sincronizables directo en cd-system y crear drift silencioso (dev pullea versión vieja, sobrescribe el cambio del maintainer al pushear). El sync inverso elimina ese riesgo |
| ¿Push directo o PR para el sync inverso? | **Push directo** | El cambio ya pasó revisión humana en cd-system vía PR de la etapa 3a (staging-frontend → main). Doble revisión sería ruido sin valor |
| ¿Misma branch fija para ambos sentidos? | **Sí en cd-frontend-dev (`frontend-sync/pending`), No en cd-system (push directo a main)** | Asimetría intencional: el sentido humano-a-bot necesita gate de revisión (PR), el sentido bot-a-bot no |

---

## Referencias

- Setup y comandos del dev: [`guia-de-uso.md`](guia-de-uso.md)
- Anatomía de un demo: [`anatomia-de-un-demo.md`](anatomia-de-un-demo.md)
- Flujo de PRs (3 etapas): [`../infrastructure/06-frontend-pr-workflow.md`](../infrastructure/06-frontend-pr-workflow.md)
- Estándar técnico de un demo: [`../product-readiness/estandar-demo.md`](../product-readiness/estandar-demo.md)
