From dfb720700104f867332e7181ae678b8fa46e182d Mon Sep 17 00:00:00 2001 From: Leandro Ronetto Date: Sun, 23 Aug 2026 17:50:37 -0300 Subject: [PATCH] chore(orquestrador): adiciona stacks finance e claudeweb ao Makefile Makefile: - FINANCE_DIR / CLAUDEWEB_DIR + alvos up/down/logs/pull/rebuild pra ambas - up: main -> gitea -> wedding -> finance -> claudeweb (down inverso) - claudeweb usa deploy/compose.yml com .env na raiz do repo, e up/rebuild delegam ao Makefile dele porque a imagem do worker efemero (worker-image) nao e servico do compose - network-claudeweb cria a network external claudeweb-workers reusando network.sh via INFRA_NETWORK= - clone-claudeweb e URLs dos repos registradas no cabecalho CLAUDE.md: secoes 2, 4, 5, 6 e 10 atualizadas (deixou de ser "3 stacks"). Novo gotcha na secao 9: os snippets de Caddy e do init do Postgres que finance e claudeweb trazem ainda nao foram aplicados neste repo, entao os dois sobem mas nao ficam acessiveis por HTTPS. Co-Authored-By: Claude Opus 5 --- CLAUDE.md | 97 ++++++++++++++++++++++++++++++++++++++------------ Makefile | 103 ++++++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 160 insertions(+), 40 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 95bdd47..487c702 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -12,21 +12,28 @@ App web pro casamento de **Stefanie & Leandro**. Convidados escaneiam um QR Code --- -## 2. Arquitetura: 3 repositórios / 3 stacks Docker Compose +## 2. Arquitetura: um repositório por stack Docker Compose -Cada stack é um repositório git separado, com seu próprio `docker-compose.yml` isolado. Os 3 compartilham uma **network Docker externa** chamada `infra-net`. +Cada stack é um repositório git separado, com seu próprio compose isolado. Todas compartilham uma **network Docker externa** chamada `infra-net`. ``` -lronetto-main/ Postgres + Redis + MinIO + pgAdmin + Caddy (+ orquestrador) -lronetto-gitea/ Gitea + Actions runner -lronetto-wedding/ App FastAPI + sidecars de backup (+ deploy CI) +lronetto-main/ Postgres + Redis + MinIO + pgAdmin + Caddy (+ orquestrador) +lronetto-gitea/ Gitea + Actions runner +lronetto-wedding/ App FastAPI + sidecars de backup (+ deploy CI) +lronetto-finance/ App FastAPI (Pluggy / open finance) (+ deploy CI) +lronetto-claudeweb/ API FastAPI + SPA + workers efêmeros (+ deploy CI) ``` -No disco os 3 ficam como **diretórios irmãos** (ex.: `C:\Users\lrone\code\lronetto-*`). O `Makefile` orquestrador (neste repo, `lronetto-main`) referencia os outros dois por caminho relativo (`../lronetto-gitea`, `../lronetto-wedding`) — sobrescrevível via `GITEA_DIR=` / `WEDDING_DIR=`. +No disco todos ficam como **diretórios irmãos** (ex.: `C:\Users\lrone\code\lronetto-*`). O `Makefile` orquestrador (neste repo, `lronetto-main`) referencia os outros por caminho relativo — sobrescrevível via `GITEA_DIR=` / `WEDDING_DIR=` / `FINANCE_DIR=` / `CLAUDEWEB_DIR=`. + +Duas pegadinhas de layout, já tratadas no Makefile orquestrador: + +- **claudeweb**: o compose fica em `deploy/compose.yml`, mas o `.env` fica na **raiz** do repo (daí o `--env-file` explícito). E o `up` dele builda antes a imagem do worker efêmero (`make worker-image`), que **não é serviço do compose** — por isso `up-claudeweb` delega pro Makefile do próprio repo em vez de chamar `docker compose` direto. +- **claudeweb** declara uma segunda network external, `claudeweb-workers` (isola os workers efêmeros da `infra-net`). O alvo `network-claudeweb` a cria reusando o `network.sh` via `INFRA_NETWORK=`. **Por que repos separados**: cada stack tem ciclo de vida, histórico e CI próprios. Subir/derrubar ou versionar uma não afeta as outras. Gitea pode ser desativado sem tocar no app. -**`lronetto-main` é o "platform layer"** que os consumidores usam. `gitea` e `wedding` conectam ao Postgres e MinIO de lá pela `infra-net`. +**`lronetto-main` é o "platform layer"** que os consumidores usam. `gitea`, `wedding`, `finance` e `claudeweb` conectam ao Postgres/Redis/MinIO de lá pela `infra-net`, e são expostos pelo Caddy de lá. > Histórico: nasceu como monorepo `wedding-app` (branch `main`) com tudo em `infra/{main,gitea,wedding_photo}/`. Foi dividido em 3 repos (fresh start, sem histórico herdado — o monorepo original fica arquivado como backup). @@ -63,7 +70,7 @@ Três repos irmãos no mesmo diretório pai: ``` lronetto-main/ # PLATFORM LAYER + ORQUESTRADOR (este repo) ├── .gitignore -├── Makefile # Orquestra as 3 stacks (refs ../lronetto-{gitea,wedding}) +├── Makefile # Orquestra as stacks (refs ../lronetto-{gitea,wedding,finance,claudeweb}) ├── network.sh # Cria infra-net (idempotente) ├── CLAUDE.md # Este arquivo ├── docker-compose.yml @@ -79,7 +86,7 @@ lronetto-gitea/ # GIT + CI ├── .env.example └── runner/Dockerfile # act_runner + docker-cli -lronetto-wedding/ # APLICAÇÃO +lronetto-wedding/ # APLICAÇÃO (fotos do casamento) ├── .gitignore ├── docker-compose.yml # app + postgres-backup + media-backup ├── .env.example @@ -111,25 +118,54 @@ lronetto-wedding/ # APLICAÇÃO └── backups/ # destino dos sidecars (gitignored) ├── postgres/ └── media/ + +lronetto-finance/ # APLICAÇÃO (open finance via Pluggy) +├── docker-compose.yml # serviço único: finance_app +├── Dockerfile, Makefile, .env.example +├── .gitea/workflows/ # CI: build + push da imagem, deploy via SSH +├── apps/{api,web}/ # FastAPI + Vite/React +└── infra-snippets/ # trechos a colar no lronetto-main (Caddy + init do postgres) + +lronetto-claudeweb/ # APLICAÇÃO (Claude Code via web) +├── deploy/ +│ ├── compose.yml # api + web + worker-proxy (.env fica na RAIZ) +│ ├── Caddyfile.snippet # bloco code.lronetto.com p/ o Caddy do main +│ └── proxy/ # tinyproxy: egress dos workers +├── backend/ # FastAPI (orquestra os workers via docker.sock) +├── frontend/ # Vite/React SPA (servida por nginx) +├── worker/ # imagem efêmera, fora do compose (make worker-image) +└── migrations/ # SQL puro ``` --- ## 5. Network e roteamento -### Network +### Networks `infra-net` é **external**. Criada pelo `network.sh` (chamada por `make network`). Containers de stacks diferentes se enxergam por nome via DNS interno do Docker. +`claudeweb-workers` é uma segunda network external, usada só pelo claudeweb: os workers efêmeros sobem **apenas** nela, isolados da `infra-net` (egress via `worker-proxy`). Criada por `make network-claudeweb`. Os containers da stack main que os workers precisam alcançar (`redis`, `gitea`, `minio`) têm que ser **conectados manualmente** a ela — ver README do claudeweb: + +```bash +docker network connect claudeweb-workers redis +docker network connect claudeweb-workers gitea +docker network connect claudeweb-workers minio +``` + ### Container names fixos - `postgres`, `redis`, `minio`, `pgadmin`, `caddy` (stack main) - `gitea`, `gitea_runner` (stack gitea) -- `wedding_app`, `wedding_pg_backup`, `wedding_media_backup` (stack wedding_photo) +- `wedding_app`, `wedding_pg_backup`, `wedding_media_backup` (stack wedding) +- `finance_app` (stack finance) +- `claudeweb-api`, `claudeweb-web`, `claudeweb-worker-proxy` (stack claudeweb) — os workers efêmeros sobem e morrem com nome próprio por sessão ### URLs (com `DOMAIN_BASE`) | Hostname | Serve | |---|---| | `https://wedding.{DOMAIN_BASE}` | Site dos noivos (uploads + galeria + admin) | +| `https://finance.{DOMAIN_BASE}` | App de finanças (Pluggy) — rota Caddy pendente, ver §9 | +| `https://code.lronetto.com` | claudeweb (API + SPA) — rota Caddy pendente, ver §9 | | `https://gitea.{DOMAIN_BASE}` | Git hosting + Actions | | `https://pgadmin.{DOMAIN_BASE}` | Web UI dos bancos | | `https://minio.{DOMAIN_BASE}` | Console admin do MinIO | @@ -139,7 +175,7 @@ lronetto-wedding/ # APLICAÇÃO ### `DOMAIN_BASE` - **Dev local**: `localhost` → Caddy emite cert interno automático pra `*.localhost` - **Produção**: domínio real (ex.: `lronetto.com`) → Let's Encrypt automático -- Mudar `DOMAIN_BASE` requer **down + up** das 3 stacks (envs lidos no boot) +- Mudar `DOMAIN_BASE` requer **down + up** de todas as stacks (envs lidos no boot) ### Hairpin / `extra_hosts` `wedding_app` tem `extra_hosts: media.{DOMAIN_BASE}:host-gateway` e `wedding.{DOMAIN_BASE}:host-gateway` pra que, mesmo dentro do container, ele resolva esses hostnames pro Docker host gateway → Caddy. Assim assinaturas S3 fecham (signing host == host que o browser usa pra PUT). @@ -149,24 +185,30 @@ lronetto-wedding/ # APLICAÇÃO ## 6. Comandos ### Orquestrador (`lronetto-main/Makefile`) -Sobe/derruba as 3 stacks de uma vez. Precisa que `lronetto-gitea` e -`lronetto-wedding` estejam como diretórios irmãos (ou ajuste `GITEA_DIR=` / -`WEDDING_DIR=`). +Sobe/derruba todas as stacks de uma vez. Precisa que os outros repos estejam +como diretórios irmãos (ou ajuste `GITEA_DIR=` / `WEDDING_DIR=` / +`FINANCE_DIR=` / `CLAUDEWEB_DIR=`). ```bash make help # lista tudo -make up # network + main + gitea + wedding (na ordem) +make up # network + main + gitea + wedding + finance + claudeweb make down # inverso make restart # down + up -make status # ps das 3 stacks +make status # ps de todas as stacks make up-main # só infra base (este repo) make up-gitea make up-wedding # rebuilda imagem do app +make up-finance # rebuilda imagem do app +make up-claudeweb # delega pro Makefile do repo (builda o worker-image antes) -make rebuild-wedding # build --no-cache + up -make down-{main,gitea,wedding} -make logs-{main,gitea,wedding} -make pull-{main,gitea,wedding} +make rebuild-{wedding,finance,claudeweb} # build --no-cache + up +make down-{main,gitea,wedding,finance,claudeweb} +make logs-{main,gitea,wedding,finance,claudeweb} +make pull-{main,gitea,wedding,finance,claudeweb} + +make network # cria infra-net +make network-claudeweb # cria claudeweb-workers +make clone-claudeweb # clona o repo do claudeweb como irmão ``` ### App wedding (`lronetto-wedding/Makefile`) @@ -315,6 +357,15 @@ Setup (1ª vez): ## 9. Gotchas conhecidos +### Caddy e Postgres do main não conhecem finance nem claudeweb (pendente) +`caddy/Caddyfile` (neste repo) tem blocos só pra `gitea`, `wedding`, `pgadmin`, `minio` e `media`. E `postgres/init/01-create-databases.sh` cria role/DB só pra wedding e gitea. Os dois apps novos trazem os trechos prontos pra colar aqui: + +- `../lronetto-finance/infra-snippets/caddy-finance.snippet` → `caddy/Caddyfile` +- `../lronetto-finance/infra-snippets/postgres-finance-db.snippet.sh` → `postgres/init/01-create-databases.sh` +- `../lronetto-claudeweb/deploy/Caddyfile.snippet` → `caddy/Caddyfile` + +Enquanto não forem aplicados, `make up-finance` / `make up-claudeweb` sobem os containers mas eles não ficam acessíveis por HTTPS (e falham ao conectar no banco). Lembre que o init do postgres **só roda com `PGDATA` vazio** — em banco já existente, crie role/DB manualmente (ver abaixo). + ### Postgres init script só roda na 1ª vez `postgres/init/01-create-databases.sh` (neste repo, `lronetto-main`) é executado pelo entrypoint do postgres **apenas quando `PGDATA` está vazio**. Pra "rerodar": ```bash @@ -388,8 +439,10 @@ O `extra_hosts: host-gateway` pra `media.{DOMAIN_BASE}` faz o container resolver 6. **Deploy CI + rename main**: workflow Gitea Actions de deploy via SSH; branch renomeada pra `main`. 7. **Split em 3 repos**: `lronetto-main` + `lronetto-gitea` + `lronetto-wedding` (fresh start). Orquestrador no main, deploy CI no wedding. Monorepo `wedding-app` arquivado. +8. **Novas apps na plataforma**: `lronetto-finance` (open finance via Pluggy) e `lronetto-claudeweb` (Claude Code via web, com workers efêmeros em rede isolada). Ambas entraram no Makefile orquestrador; os snippets de Caddy/Postgres delas ainda não foram aplicados neste repo (§9). + Repos / branches: -- `lronetto-main`, `lronetto-gitea`, `lronetto-wedding` (atuais; default branch `main`) +- `lronetto-main`, `lronetto-gitea`, `lronetto-wedding`, `lronetto-finance`, `lronetto-claudeweb` (atuais; default branch `main`) - Arquivados no monorepo `wedding-app`: `claude/wedding-qrcode-photos-C0PQt` (Cloudflare original), `claude/docker-vps-migration` (1ª migração Docker Node) --- diff --git a/Makefile b/Makefile index c8e05e8..0c1f415 100644 --- a/Makefile +++ b/Makefile @@ -1,27 +1,43 @@ -.PHONY: help network up down restart status \ - up-main up-gitea up-wedding \ - down-main down-gitea down-wedding \ - logs-main logs-gitea logs-wedding \ - pull-main pull-gitea pull-wedding \ - rebuild-wedding +.PHONY: help network network-claudeweb up down restart status \ + up-main up-gitea up-wedding up-finance up-claudeweb \ + down-main down-gitea down-wedding down-finance down-claudeweb \ + logs-main logs-gitea logs-wedding logs-finance logs-claudeweb \ + pull-main pull-gitea pull-wedding pull-finance pull-claudeweb \ + rebuild-wedding rebuild-finance rebuild-claudeweb clone-claudeweb -# Orquestrador das 3 stacks. `lronetto-main` é o "platform layer" -# (postgres + redis + minio + pgadmin + caddy). Os repos lronetto-gitea e -# lronetto-wedding são clonados como diretórios IRMÃOS e referenciados aqui. -# Ajuste os caminhos abaixo se usar outro layout no disco. +# Orquestrador das stacks. `lronetto-main` é o "platform layer" +# (postgres + redis + minio + pgadmin + caddy). Os demais repos são clonados +# como diretórios IRMÃOS e referenciados aqui. Ajuste os caminhos abaixo se +# usar outro layout no disco. +# +# lronetto-gitea https://gitea.lronetto.com/lronetto/lronetto-gitea.git +# lronetto-wedding https://gitea.lronetto.com/lronetto/lronetto-wedding.git +# lronetto-finance https://gitea.lronetto.com/lronetto/lronetto-finance.git +# lronetto-claudeweb https://gitea.lronetto.com/lronetto/lronetto-claudeweb.git NET := infra-net -WEDDING_DIR ?= ../lronetto-wedding -GITEA_DIR ?= ../lronetto-gitea +# Rede isolada dos workers efêmeros do claudeweb (declarada external no compose dele). +NET_WORKERS := claudeweb-workers + +WEDDING_DIR ?= ../lronetto-wedding +GITEA_DIR ?= ../lronetto-gitea +FINANCE_DIR ?= ../lronetto-finance +CLAUDEWEB_DIR ?= ../lronetto-claudeweb + +CLAUDEWEB_REPO ?= https://gitea.lronetto.com/lronetto/lronetto-claudeweb.git DC_MAIN := docker compose -f docker-compose.yml --env-file .env DC_GITEA := docker compose -f $(GITEA_DIR)/docker-compose.yml --env-file $(GITEA_DIR)/.env DC_WEDDING := docker compose -f $(WEDDING_DIR)/docker-compose.yml --env-file $(WEDDING_DIR)/.env +DC_FINANCE := docker compose -f $(FINANCE_DIR)/docker-compose.yml --env-file $(FINANCE_DIR)/.env +# claudeweb: compose vive em deploy/compose.yml e o .env fica na RAIZ do repo. +DC_CLAUDEWEB := docker compose -f $(CLAUDEWEB_DIR)/deploy/compose.yml --env-file $(CLAUDEWEB_DIR)/.env help: @echo "Stacks: main (este repo) | gitea ($(GITEA_DIR)) | wedding ($(WEDDING_DIR))" + @echo " finance ($(FINANCE_DIR)) | claudeweb ($(CLAUDEWEB_DIR))" @echo "" - @echo " make up Sobe tudo na ordem (main -> gitea -> wedding)" + @echo " make up Sobe tudo (main -> gitea -> wedding -> finance -> claudeweb)" @echo " make down Desce tudo na ordem inversa" @echo " make restart down + up" @echo " make status ps de todas as stacks" @@ -29,18 +45,27 @@ help: @echo " make up-main Sobe só a stack main" @echo " make up-gitea Sobe só o gitea" @echo " make up-wedding Build + up do app wedding" + @echo " make up-finance Build + up do app finance" + @echo " make up-claudeweb Build (incl. worker-image) + up do claudeweb" @echo " make rebuild-wedding Force rebuild do app wedding" - @echo " make down-{main,gitea,wedding}" - @echo " make logs-{main,gitea,wedding}" - @echo " make pull-{main,gitea,wedding}" + @echo " make rebuild-finance Force rebuild do app finance" + @echo " make rebuild-claudeweb Force rebuild do claudeweb" + @echo " make down-{main,gitea,wedding,finance,claudeweb}" + @echo " make logs-{main,gitea,wedding,finance,claudeweb}" + @echo " make pull-{main,gitea,wedding,finance,claudeweb}" + @echo " make clone-claudeweb Clona $(CLAUDEWEB_REPO) em $(CLAUDEWEB_DIR)" @echo " make network Cria a network external '$(NET)' (idempotente)" + @echo " make network-claudeweb Cria a network external '$(NET_WORKERS)' (idempotente)" network: @./network.sh -up: network up-main up-gitea up-wedding +network-claudeweb: + @INFRA_NETWORK=$(NET_WORKERS) ./network.sh -down: down-wedding down-gitea down-main +up: network up-main up-gitea up-wedding up-finance up-claudeweb + +down: down-claudeweb down-finance down-wedding down-gitea down-main restart: down up @@ -48,6 +73,8 @@ status: @$(DC_MAIN) ps || true @$(DC_GITEA) ps || true @$(DC_WEDDING) ps || true + @$(DC_FINANCE) ps || true + @$(DC_CLAUDEWEB) ps || true up-main: network $(DC_MAIN) up -d @@ -58,10 +85,27 @@ up-gitea: network up-wedding: network $(DC_WEDDING) up -d --build +up-finance: network + $(DC_FINANCE) up -d --build + +# Delegado ao Makefile do repo: o `up` de lá builda antes a imagem do worker +# efêmero (fora do compose) que o backend instancia. +up-claudeweb: network network-claudeweb + $(MAKE) -C $(CLAUDEWEB_DIR) up + rebuild-wedding: network $(DC_WEDDING) build --no-cache $(DC_WEDDING) up -d +rebuild-finance: network + $(DC_FINANCE) build --no-cache + $(DC_FINANCE) up -d + +rebuild-claudeweb: network network-claudeweb + $(MAKE) -C $(CLAUDEWEB_DIR) worker-image + $(DC_CLAUDEWEB) build --no-cache + $(DC_CLAUDEWEB) up -d + down-main: $(DC_MAIN) down @@ -71,6 +115,12 @@ down-gitea: down-wedding: $(DC_WEDDING) down +down-finance: + $(DC_FINANCE) down + +down-claudeweb: + $(DC_CLAUDEWEB) down + logs-main: $(DC_MAIN) logs -f @@ -80,6 +130,12 @@ logs-gitea: logs-wedding: $(DC_WEDDING) logs -f +logs-finance: + $(DC_FINANCE) logs -f + +logs-claudeweb: + $(DC_CLAUDEWEB) logs -f + pull-main: $(DC_MAIN) pull @@ -88,3 +144,14 @@ pull-gitea: pull-wedding: $(DC_WEDDING) pull + +pull-finance: + $(DC_FINANCE) pull + +pull-claudeweb: + $(DC_CLAUDEWEB) pull + +clone-claudeweb: + @test -d $(CLAUDEWEB_DIR)/.git \ + && echo "$(CLAUDEWEB_DIR) já existe" \ + || git clone $(CLAUDEWEB_REPO) $(CLAUDEWEB_DIR)