Compare commits
1 Commits
main
...
claude/wip
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
380440f8e7 |
21
.env.example
21
.env.example
@ -29,6 +29,16 @@ GITEA_DB_USER=gitea
|
|||||||
GITEA_DB_PASSWORD=troque-essa-senha-forte
|
GITEA_DB_PASSWORD=troque-essa-senha-forte
|
||||||
GITEA_DB_NAME=gitea
|
GITEA_DB_NAME=gitea
|
||||||
|
|
||||||
|
# lronetto-finance (repo à parte, consome esta mesma instância de Postgres)
|
||||||
|
FINANCE_DB_USER=finance
|
||||||
|
FINANCE_DB_PASSWORD=troque-essa-senha-forte
|
||||||
|
FINANCE_DB_NAME=finance
|
||||||
|
|
||||||
|
# lronetto-claudeweb (repo à parte, consome esta mesma instância de Postgres)
|
||||||
|
CLAUDEWEB_DB_USER=claudeweb
|
||||||
|
CLAUDEWEB_DB_PASSWORD=troque-essa-senha-forte
|
||||||
|
CLAUDEWEB_DB_NAME=claudeweb
|
||||||
|
|
||||||
# ----- MinIO (root creds) -----
|
# ----- MinIO (root creds) -----
|
||||||
MINIO_ROOT_USER=minioadmin
|
MINIO_ROOT_USER=minioadmin
|
||||||
MINIO_ROOT_PASSWORD=troque-essa-senha-forte
|
MINIO_ROOT_PASSWORD=troque-essa-senha-forte
|
||||||
@ -36,6 +46,17 @@ MINIO_ROOT_PASSWORD=troque-essa-senha-forte
|
|||||||
# Bucket criado já no boot pra ser consumido pela stack wedding_photo
|
# Bucket criado já no boot pra ser consumido pela stack wedding_photo
|
||||||
WEDDING_BUCKET=wedding-media
|
WEDDING_BUCKET=wedding-media
|
||||||
|
|
||||||
|
# Bucket opcional pra artefatos do lronetto-claudeweb (diff + log de sessão,
|
||||||
|
# M3/RF-14). Só é usado se o claudeweb tiver S3_ENDPOINT preenchido no seu
|
||||||
|
# .env; sem isso o app funciona normal e só pula o upload. Ver minio/init.sh.
|
||||||
|
CLAUDEWEB_BUCKET=claudeweb-artifacts
|
||||||
|
|
||||||
# ----- pgAdmin (login web) -----
|
# ----- pgAdmin (login web) -----
|
||||||
PGADMIN_EMAIL=admin@localhost
|
PGADMIN_EMAIL=admin@localhost
|
||||||
PGADMIN_PASSWORD=troque-essa-senha-forte
|
PGADMIN_PASSWORD=troque-essa-senha-forte
|
||||||
|
|
||||||
|
# ----- scripts/vps-backup.sh (backup completo do host, opcional) -----
|
||||||
|
# Só precisa preencher se for usar `make backup-vps`. Todas com default sensato.
|
||||||
|
# BACKUP_DIR=./backups/vps
|
||||||
|
# BACKUP_RETENTION_DAYS=14
|
||||||
|
# BACKUP_REMOTE= # ex.: r2:meu-bucket/vps-backup (requer rclone configurado)
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@ -15,3 +15,6 @@ minio/data/
|
|||||||
pgadmin/data/
|
pgadmin/data/
|
||||||
caddy/data/
|
caddy/data/
|
||||||
caddy/config/
|
caddy/config/
|
||||||
|
|
||||||
|
# Destino do script de backup do VPS (contém dumps + segredos)
|
||||||
|
backups/
|
||||||
|
|||||||
195
CLAUDE.md
195
CLAUDE.md
@ -12,40 +12,51 @@ App web pro casamento de **Stefanie & Leandro**. Convidados escaneiam um QR Code
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2. Arquitetura: um repositório por stack Docker Compose
|
## 2. Arquitetura: 3 repositórios / 3 stacks Docker Compose
|
||||||
|
|
||||||
Cada stack é um repositório git separado, com seu próprio compose isolado. Todas compartilham uma **network Docker externa** chamada `infra-net`.
|
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`.
|
||||||
|
|
||||||
```
|
```
|
||||||
lronetto-main/ Postgres + Redis + MinIO + pgAdmin + Caddy (+ orquestrador)
|
lronetto-main/ Postgres + Redis + MinIO + pgAdmin + Caddy (+ orquestrador)
|
||||||
lronetto-gitea/ Gitea + Actions runner
|
lronetto-gitea/ Gitea + Actions runner
|
||||||
lronetto-wedding/ App FastAPI + sidecars de backup (+ deploy CI)
|
lronetto-wedding/ App FastAPI + sidecars de backup (+ deploy CI)
|
||||||
lronetto-finance/ App FastAPI (Pluggy / open finance) (+ deploy CI)
|
|
||||||
lronetto-bom-vizinho/ App FastAPI + mobile (bairro/vizinhança) (+ deploy CI)
|
|
||||||
lronetto-claudeweb/ API FastAPI + SPA + workers efêmeros (+ deploy CI)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
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=` / `BOMVIZINHO_DIR=` / `CLAUDEWEB_DIR=`.
|
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=`.
|
||||||
|
|
||||||
**Cada repo põe o compose e o `.env` num lugar diferente** — daí os `-f` / `--env-file` explícitos no Makefile orquestrador em vez de um padrão único:
|
|
||||||
|
|
||||||
| Repo | compose | `.env` |
|
|
||||||
|---|---|---|
|
|
||||||
| gitea, wedding, finance | `docker-compose.yml` (raiz) | raiz |
|
|
||||||
| bom-vizinho | `infra/docker-compose.yml` | `infra/.env` |
|
|
||||||
| claudeweb | `deploy/compose.yml` | raiz |
|
|
||||||
|
|
||||||
Mais duas pegadinhas do **claudeweb**, também já tratadas no orquestrador:
|
|
||||||
|
|
||||||
- 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.
|
|
||||||
- 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.
|
**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`, `wedding`, `finance`, `bom-vizinho` e `claudeweb` conectam ao Postgres/Redis/MinIO de lá pela `infra-net`, e são expostos pelo Caddy de lá.
|
**`lronetto-main` é o "platform layer"** que os consumidores usam. `gitea` e `wedding` conectam ao Postgres e MinIO de lá pela `infra-net`.
|
||||||
|
|
||||||
> 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).
|
> 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).
|
||||||
|
|
||||||
|
### `lronetto-main` é infra base compartilhada (não só do casamento)
|
||||||
|
|
||||||
|
`lronetto-main` não é infra dedicada ao casamento — é a **infra base** (Postgres + Redis + MinIO + pgAdmin + Caddy + `infra-net`) que **outros serviços independentes** também consomem, além de `gitea` e `wedding`. Todos rodam no mesmo VPS, todos hospedados no mesmo Gitea self-hosted sob o prefixo `lronetto-`:
|
||||||
|
|
||||||
|
| Repo | URL | Escopo | Orquestrado por este `Makefile`? |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `lronetto-main` | `https://gitea.lronetto.com/lronetto/lronetto-main.git` | Este repo — infra base (platform layer) + orquestrador | — |
|
||||||
|
| `lronetto-gitea` | `https://gitea.lronetto.com/lronetto/lronetto-gitea.git` | Git hosting + Actions, hospeda todos os repos `lronetto-*` (dogfooding) | Sim (`up-gitea`) |
|
||||||
|
| `lronetto-wedding` | `https://gitea.lronetto.com/lronetto/lronetto-wedding.git` | App do casamento (é o que este `CLAUDE.md` documenta em detalhe) | Sim (`up-wedding`) |
|
||||||
|
| `lronetto-finance` | `https://gitea.lronetto.com/lronetto/lronetto-finance.git` | Open Finance (Pluggy) — outro projeto, não relacionado ao casamento | Sim (`up-finance`) |
|
||||||
|
| `lronetto-claudeweb` | `https://gitea.lronetto.com/lronetto/lronetto-claudeweb.git` | Interface web pro Claude Code (Agent SDK), single-user — outro projeto, não relacionado ao casamento | Sim (`up-claudeweb`) |
|
||||||
|
|
||||||
|
`lronetto-finance` e `lronetto-claudeweb` **já estão provisionados e rodando em produção**, consumindo Postgres/Redis/MinIO/Caddy deste repo pela `infra-net` — assim como wedding e gitea. Cada um segue o mesmo padrão de "app self-contained, sem Postgres/Redis/Caddy próprios" já usado pela wedding: repo com `docker-compose.yml` (ou `deploy/compose.yml`) próprio, `infra-net` declarada como `external`, containers conectados por nome (`postgres`, `redis`, `minio`), sem porta pública (exposição só via Caddy do main).
|
||||||
|
|
||||||
|
**O que existe hoje neste repo pra suportar os dois:**
|
||||||
|
- `postgres/init/01-create-databases.sh`: cria roles/databases `finance` e `claudeweb` (além de `wedding`/`gitea`), a partir de `FINANCE_DB_*`/`CLAUDEWEB_DB_*` no `.env`
|
||||||
|
- `docker-compose.yml` (serviço `postgres`): repassa `FINANCE_DB_*`/`CLAUDEWEB_DB_*` pro init script
|
||||||
|
- `minio/init.sh`: cria também o bucket `claudeweb-artifacts` (privado, sem download anônimo — usado só se `lronetto-claudeweb` tiver `S3_ENDPOINT` preenchido, pra artefatos de sessão M3/RF-14); `lronetto-finance` não usa MinIO
|
||||||
|
- `caddy/Caddyfile`: roteia `finance.{DOMAIN_BASE}` → `finance_app:8000` e **`code.{DOMAIN_BASE}`** (não `claudeweb.{DOMAIN_BASE}`!) → `claudeweb-api:8300` (rotas `/api/*`, `/healthz`, `/ws/*`) ou `claudeweb-web:80` (resto, SPA estática)
|
||||||
|
- `Makefile`: targets `up-finance`/`down-finance`/`logs-finance`/`pull-finance`/`rebuild-finance` e os equivalentes `-claudeweb`, seguindo o padrão de `WEDDING_DIR=`/`GITEA_DIR=` (agora também `FINANCE_DIR=` / `CLAUDEWEB_DIR=`, default `../lronetto-finance` / `../lronetto-claudeweb`)
|
||||||
|
|
||||||
|
**Diferença importante**: `make up`/`down`/`restart`/`status` continuam cobrindo só o **core** (main + gitea + wedding — os 3 repos que este documento detalha). `finance` e `claudeweb` têm targets avulsos (`make up-finance`, `make up-claudeweb`, etc.) porque têm ciclo de vida e deploy CI próprios, independentes deste projeto — não entram no `up`/`down` agregado de propósito. `make status` já lista os dois (com `|| true`, então não quebra se não estiverem clonados/de pé).
|
||||||
|
|
||||||
|
**Gotcha extra do `lronetto-claudeweb`**: ele cria e gerencia por fora uma segunda network Docker, `claudeweb-workers` (não é a `infra-net`), e **conecta manualmente os containers `redis`, `gitea` e (opcionalmente) `minio` deste repo a ela** — é assim que os containers efêmeros de worker (Agent SDK) do claudeweb falam com Redis/Gitea/MinIO sem entrar na `infra-net` (isolamento de egress). Isso significa que `redis`/`gitea`/`minio` ficam com **duas networks anexadas** por fora do `docker-compose.yml` deste repo — um `docker network disconnect` acidental, um recreate de container, ou uma limpeza de networks (`docker network prune`) pode quebrar essa conexão sem avisar aqui. Ver `README.md` do `lronetto-claudeweb` pra recriar (`docker network connect claudeweb-workers <container>`).
|
||||||
|
|
||||||
|
> Nota sobre backup: o `scripts/vps-backup.sh` (seção 8) já cobre `finance`/`claudeweb` de graça — o `pg_dumpall` do passo 1 dumpa **todos** os bancos da instância, e o script agora também copia o `.env` de `lronetto-finance`/`lronetto-claudeweb` (via `FINANCE_DIR=`/`CLAUDEWEB_DIR=`) se estiverem clonados como irmãos.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3. Stack técnica
|
## 3. Stack técnica
|
||||||
@ -79,7 +90,7 @@ Três repos irmãos no mesmo diretório pai:
|
|||||||
```
|
```
|
||||||
lronetto-main/ # PLATFORM LAYER + ORQUESTRADOR (este repo)
|
lronetto-main/ # PLATFORM LAYER + ORQUESTRADOR (este repo)
|
||||||
├── .gitignore
|
├── .gitignore
|
||||||
├── Makefile # Orquestra as stacks (refs ../lronetto-{gitea,wedding,finance,claudeweb})
|
├── Makefile # Orquestra as 3 stacks (refs ../lronetto-{gitea,wedding})
|
||||||
├── network.sh # Cria infra-net (idempotente)
|
├── network.sh # Cria infra-net (idempotente)
|
||||||
├── CLAUDE.md # Este arquivo
|
├── CLAUDE.md # Este arquivo
|
||||||
├── docker-compose.yml
|
├── docker-compose.yml
|
||||||
@ -87,7 +98,9 @@ lronetto-main/ # PLATFORM LAYER + ORQUESTRADOR (este repo)
|
|||||||
├── caddy/Caddyfile # hostname-based routing
|
├── caddy/Caddyfile # hostname-based routing
|
||||||
├── postgres/init/01-create-databases.sh # cria DBs wedding + gitea
|
├── postgres/init/01-create-databases.sh # cria DBs wedding + gitea
|
||||||
├── minio/{init.sh, cors.json} # cria bucket wedding-media
|
├── minio/{init.sh, cors.json} # cria bucket wedding-media
|
||||||
└── pgadmin/servers.json # postgres pré-conectado
|
├── pgadmin/servers.json # postgres pré-conectado
|
||||||
|
├── scripts/vps-backup.sh # backup completo do host (make backup-vps)
|
||||||
|
└── backups/vps/ # destino do vps-backup.sh (gitignored)
|
||||||
|
|
||||||
lronetto-gitea/ # GIT + CI
|
lronetto-gitea/ # GIT + CI
|
||||||
├── .gitignore
|
├── .gitignore
|
||||||
@ -95,7 +108,7 @@ lronetto-gitea/ # GIT + CI
|
|||||||
├── .env.example
|
├── .env.example
|
||||||
└── runner/Dockerfile # act_runner + docker-cli
|
└── runner/Dockerfile # act_runner + docker-cli
|
||||||
|
|
||||||
lronetto-wedding/ # APLICAÇÃO (fotos do casamento)
|
lronetto-wedding/ # APLICAÇÃO
|
||||||
├── .gitignore
|
├── .gitignore
|
||||||
├── docker-compose.yml # app + postgres-backup + media-backup
|
├── docker-compose.yml # app + postgres-backup + media-backup
|
||||||
├── .env.example
|
├── .env.example
|
||||||
@ -127,76 +140,39 @@ lronetto-wedding/ # APLICAÇÃO (fotos do casamento)
|
|||||||
└── backups/ # destino dos sidecars (gitignored)
|
└── backups/ # destino dos sidecars (gitignored)
|
||||||
├── postgres/
|
├── postgres/
|
||||||
└── media/
|
└── 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-bom-vizinho/ # APLICAÇÃO (bairro / vizinhança)
|
|
||||||
├── infra/
|
|
||||||
│ ├── docker-compose.yml # stack "plataforma" (api, plugada na infra-net)
|
|
||||||
│ ├── docker-compose.dev.yml # stack dev standalone (pg+redis+minio próprios)
|
|
||||||
│ └── .env.example # o .env vive AQUI, não na raiz
|
|
||||||
├── Makefile # up/down/deploy + up-dev standalone
|
|
||||||
├── backend/ # FastAPI + alembic (migrations)
|
|
||||||
├── mobile/ # app mobile
|
|
||||||
└── docs/DEPLOY.md # runbook de deploy e pré-requisitos da plataforma
|
|
||||||
|
|
||||||
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
|
## 5. Network e roteamento
|
||||||
|
|
||||||
### Networks
|
### Network
|
||||||
`infra-net` é **external**. Criada pelo `network.sh` (chamada por `make network`). Containers de stacks diferentes se enxergam por nome via DNS interno do Docker.
|
`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
|
### Container names fixos
|
||||||
- `postgres`, `redis`, `minio`, `pgadmin`, `caddy` (stack main)
|
- `postgres`, `redis`, `minio`, `pgadmin`, `caddy` (stack main)
|
||||||
- `gitea`, `gitea_runner` (stack gitea)
|
- `gitea`, `gitea_runner` (stack gitea)
|
||||||
- `wedding_app`, `wedding_pg_backup`, `wedding_media_backup` (stack wedding)
|
- `wedding_app`, `wedding_pg_backup`, `wedding_media_backup` (stack wedding_photo)
|
||||||
- `finance_app` (stack finance)
|
- `finance_app` (stack `lronetto-finance`, repo à parte)
|
||||||
- `bomvizinho_api` (stack bom-vizinho)
|
- `claudeweb-api`, `claudeweb-web` (stack `lronetto-claudeweb`, repo à parte)
|
||||||
- `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`)
|
### URLs (com `DOMAIN_BASE`)
|
||||||
|
|
||||||
| Hostname | Serve |
|
| Hostname | Serve |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `https://wedding.{DOMAIN_BASE}` | Site dos noivos (uploads + galeria + admin) |
|
| `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://api.bomvizinho.{DOMAIN_BASE}` | API do bom-vizinho — 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://gitea.{DOMAIN_BASE}` | Git hosting + Actions |
|
||||||
| `https://pgadmin.{DOMAIN_BASE}` | Web UI dos bancos |
|
| `https://pgadmin.{DOMAIN_BASE}` | Web UI dos bancos |
|
||||||
| `https://minio.{DOMAIN_BASE}` | Console admin do MinIO |
|
| `https://minio.{DOMAIN_BASE}` | Console admin do MinIO |
|
||||||
| `https://media.{DOMAIN_BASE}` | S3 API pública do MinIO (uploads/downloads) |
|
| `https://media.{DOMAIN_BASE}` | S3 API pública do MinIO (uploads/downloads) |
|
||||||
| `ssh://git@gitea.{DOMAIN_BASE}:2222` | Git via SSH |
|
| `ssh://git@gitea.{DOMAIN_BASE}:2222` | Git via SSH |
|
||||||
|
| `https://finance.{DOMAIN_BASE}` | `lronetto-finance` (Open Finance/Pluggy) — repo à parte, não relacionado ao casamento |
|
||||||
|
| `https://code.{DOMAIN_BASE}` | `lronetto-claudeweb` (interface web pro Claude Code) — repo à parte, subdomínio é `code`, não `claudeweb` |
|
||||||
|
|
||||||
### `DOMAIN_BASE`
|
### `DOMAIN_BASE`
|
||||||
- **Dev local**: `localhost` → Caddy emite cert interno automático pra `*.localhost`
|
- **Dev local**: `localhost` → Caddy emite cert interno automático pra `*.localhost`
|
||||||
- **Produção**: domínio real (ex.: `lronetto.com`) → Let's Encrypt automático
|
- **Produção**: domínio real (ex.: `lronetto.com`) → Let's Encrypt automático
|
||||||
- Mudar `DOMAIN_BASE` requer **down + up** de todas as stacks (envs lidos no boot)
|
- Mudar `DOMAIN_BASE` requer **down + up** das 3 stacks (envs lidos no boot)
|
||||||
|
|
||||||
### Hairpin / `extra_hosts`
|
### 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).
|
`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).
|
||||||
@ -206,32 +182,43 @@ docker network connect claudeweb-workers minio
|
|||||||
## 6. Comandos
|
## 6. Comandos
|
||||||
|
|
||||||
### Orquestrador (`lronetto-main/Makefile`)
|
### Orquestrador (`lronetto-main/Makefile`)
|
||||||
Sobe/derruba todas as stacks de uma vez. Precisa que os outros repos estejam
|
`make up`/`down`/`restart`/`status` cobrem só o **core do casamento** (main +
|
||||||
como diretórios irmãos (ou ajuste `GITEA_DIR=` / `WEDDING_DIR=` /
|
gitea + wedding — os 3 repos que este documento detalha). Precisa que
|
||||||
`FINANCE_DIR=` / `CLAUDEWEB_DIR=`).
|
`lronetto-gitea` e `lronetto-wedding` estejam como diretórios irmãos (ou
|
||||||
|
ajuste `GITEA_DIR=` / `WEDDING_DIR=`).
|
||||||
|
|
||||||
|
`finance` e `claudeweb` (seção 2) têm targets avulsos (`up-finance`,
|
||||||
|
`up-claudeweb`, etc.) — de propósito **não** entram no `up`/`down` agregado,
|
||||||
|
porque têm ciclo de vida e deploy CI próprios. Ajuste via `FINANCE_DIR=` /
|
||||||
|
`CLAUDEWEB_DIR=` se não estiverem como diretórios irmãos.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
make help # lista tudo
|
make help # lista tudo
|
||||||
make up # network + main + gitea + wedding + finance + bomvizinho + claudeweb
|
|
||||||
|
# ----- core (main + gitea + wedding) -----
|
||||||
|
make up # network + main + gitea + wedding (na ordem)
|
||||||
make down # inverso
|
make down # inverso
|
||||||
make restart # down + up
|
make restart # down + up
|
||||||
make status # ps de todas as stacks
|
make status # ps do core + finance/claudeweb (se de pé)
|
||||||
|
|
||||||
make up-main # só infra base (este repo)
|
make up-main # só infra base (este repo)
|
||||||
make up-gitea
|
make up-gitea
|
||||||
make up-wedding # rebuilda imagem do app
|
make up-wedding # rebuilda imagem do app
|
||||||
make up-finance # rebuilda imagem do app
|
make rebuild-wedding # build --no-cache + up
|
||||||
make up-bomvizinho # rebuilda imagem do app (compose e .env em infra/)
|
make down-{main,gitea,wedding}
|
||||||
make up-claudeweb # delega pro Makefile do repo (builda o worker-image antes)
|
make logs-{main,gitea,wedding}
|
||||||
|
make pull-{main,gitea,wedding}
|
||||||
|
|
||||||
make rebuild-{wedding,finance,bomvizinho,claudeweb} # build --no-cache + up
|
# ----- outros consumidores da infra base (targets avulsos) -----
|
||||||
make down-{main,gitea,wedding,finance,bomvizinho,claudeweb}
|
make up-finance # build + up do app finance
|
||||||
make logs-{main,gitea,wedding,finance,bomvizinho,claudeweb}
|
make up-claudeweb # build da imagem do worker + up do claudeweb (api+web)
|
||||||
make pull-{main,gitea,wedding,finance,bomvizinho,claudeweb}
|
make rebuild-{finance,claudeweb}
|
||||||
|
make down-{finance,claudeweb}
|
||||||
|
make logs-{finance,claudeweb}
|
||||||
|
make pull-{finance,claudeweb}
|
||||||
|
|
||||||
make network # cria infra-net
|
make backup-vps # roda scripts/vps-backup.sh (backup completo do host,
|
||||||
make network-claudeweb # cria claudeweb-workers
|
# inclui finance/claudeweb se clonados como irmãos)
|
||||||
make clone-claudeweb # clona o repo do claudeweb como irmão
|
|
||||||
make clone-bomvizinho # idem pro bom-vizinho
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### App wedding (`lronetto-wedding/Makefile`)
|
### App wedding (`lronetto-wedding/Makefile`)
|
||||||
@ -327,10 +314,23 @@ make deploy # git reset --hard + up (chamado pelo CI)
|
|||||||
- `DELETE /api/admin/event/cover` — remove a foto de capa
|
- `DELETE /api/admin/event/cover` — remove a foto de capa
|
||||||
|
|
||||||
### Backup
|
### Backup
|
||||||
|
|
||||||
|
**Nível stack (`lronetto-wedding`, sidecars sempre ativos)**
|
||||||
- **Postgres**: `prodrigestivill/postgres-backup-local` daily, retenção dias/semanas/meses, escreve em `./backups/postgres/` (bind mount do host)
|
- **Postgres**: `prodrigestivill/postgres-backup-local` daily, retenção dias/semanas/meses, escreve em `./backups/postgres/` (bind mount do host)
|
||||||
- **MinIO**: alpine + mc cron-driven, `mc mirror` (incremental) pra `./backups/media/`
|
- **MinIO**: alpine + mc cron-driven, `mc mirror` (incremental) pra `./backups/media/`
|
||||||
- **Backup remoto opcional**: configurar `BACKUP_REMOTE_*` no `.env` da wedding → espelha pra outro endpoint S3 (R2/B2/etc.)
|
- **Backup remoto opcional**: configurar `BACKUP_REMOTE_*` no `.env` da wedding → espelha pra outro endpoint S3 (R2/B2/etc.)
|
||||||
|
|
||||||
|
**Nível host (`lronetto-main/scripts/vps-backup.sh`, `make backup-vps`)**
|
||||||
|
- Script único que cobre o que os sidecars da wedding **não** cobrem: dump lógico completo do Postgres (`pg_dumpall`, todos os bancos + roles, não só o da wedding), snapshot RDB do Redis, tar do diretório de dados do Gitea (repos + config), `.env` das 3 stacks e os certs do Caddy (evita reemissão no Let's Encrypt após um restore)
|
||||||
|
- Empacota tudo num único `.tar.gz` com permissão `600` (tem segredo dentro — os `.env`) em `backups/vps/`, com rotação por `BACKUP_RETENTION_DAYS` (default 14 dias)
|
||||||
|
- Envio offsite opcional via `rclone` se `BACKUP_REMOTE` estiver setado (ex.: `r2:meu-bucket/vps-backup`)
|
||||||
|
- Roda **no host**, fora de containers (usa `docker exec`/`docker cp` pra falar com `postgres`/`redis`, e lê os diretórios dos repos irmãos via `GITEA_DIR=`/`WEDDING_DIR=`, mesma convenção do Makefile orquestrador)
|
||||||
|
- Pensado pra cron diário (fora de horário de pico):
|
||||||
|
```cron
|
||||||
|
0 3 * * * cd /opt/lronetto-main && ./scripts/vps-backup.sh >> backups/vps/cron.log 2>&1
|
||||||
|
```
|
||||||
|
- Restore é manual (não tem script de restore automático — cada peça volta do seu jeito): `gunzip -c postgres-all.sql.gz | docker exec -i postgres psql -U postgres`, `tar -xzf gitea-data.tar.gz -C ../lronetto-gitea/`, etc.
|
||||||
|
|
||||||
### Gitea bootstrap (1ª vez)
|
### Gitea bootstrap (1ª vez)
|
||||||
1. `make up-main` (precisa estar de pé pro postgres + redis)
|
1. `make up-main` (precisa estar de pé pro postgres + redis)
|
||||||
2. `make up-gitea` (runner falha porque ainda não tem token, ok)
|
2. `make up-gitea` (runner falha porque ainda não tem token, ok)
|
||||||
@ -380,23 +380,6 @@ Setup (1ª vez):
|
|||||||
|
|
||||||
## 9. Gotchas conhecidos
|
## 9. Gotchas conhecidos
|
||||||
|
|
||||||
### O platform layer ainda não conhece finance, bom-vizinho 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. Falta, por app:
|
|
||||||
|
|
||||||
**finance** — snippets prontos no próprio repo:
|
|
||||||
- `../lronetto-finance/infra-snippets/caddy-finance.snippet` → `caddy/Caddyfile`
|
|
||||||
- `../lronetto-finance/infra-snippets/postgres-finance-db.snippet.sh` → `postgres/init/01-create-databases.sh`
|
|
||||||
|
|
||||||
**claudeweb**:
|
|
||||||
- `../lronetto-claudeweb/deploy/Caddyfile.snippet` → `caddy/Caddyfile`
|
|
||||||
|
|
||||||
**bom-vizinho** — não traz snippet pronto; ver `../lronetto-bom-vizinho/docs/DEPLOY.md`. Precisa de:
|
|
||||||
- bloco `api.bomvizinho.{DOMAIN_BASE}` → `bomvizinho_api:8000` no `caddy/Caddyfile`
|
|
||||||
- role + DB `bomvizinho` **com PostGIS** — e a imagem atual (`postgres:16-alpine`) **não traz PostGIS**: exige trocar por `postgis/postgis:16-x`, o que é troca de imagem com `PGDATA` já populado (fazer com backup na mão)
|
|
||||||
- bucket `bomvizinho-media` no MinIO (`minio/init.sh`)
|
|
||||||
|
|
||||||
Enquanto não forem aplicados, `make up-finance` / `make up-bomvizinho` / `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 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":
|
`postgres/init/01-create-databases.sh` (neste repo, `lronetto-main`) é executado pelo entrypoint do postgres **apenas quando `PGDATA` está vazio**. Pra "rerodar":
|
||||||
```bash
|
```bash
|
||||||
@ -470,10 +453,8 @@ 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`.
|
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.
|
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), `lronetto-bom-vizinho` (bairro/vizinhança, precisa de PostGIS) e `lronetto-claudeweb` (Claude Code via web, com workers efêmeros em rede isolada). As três entraram no Makefile orquestrador; a integração delas com Caddy/Postgres/MinIO deste repo ainda não foi feita (§9).
|
|
||||||
|
|
||||||
Repos / branches:
|
Repos / branches:
|
||||||
- `lronetto-main`, `lronetto-gitea`, `lronetto-wedding`, `lronetto-finance`, `lronetto-bom-vizinho`, `lronetto-claudeweb` (atuais; default branch `main`)
|
- `lronetto-main`, `lronetto-gitea`, `lronetto-wedding` (atuais; default branch `main`; hospedados no Gitea self-hosted da própria stack, prefixo `lronetto-*`)
|
||||||
- Arquivados no monorepo `wedding-app`: `claude/wedding-qrcode-photos-C0PQt` (Cloudflare original), `claude/docker-vps-migration` (1ª migração Docker Node)
|
- Arquivados no monorepo `wedding-app`: `claude/wedding-qrcode-photos-C0PQt` (Cloudflare original), `claude/docker-vps-migration` (1ª migração Docker Node)
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -488,7 +469,7 @@ Repos / branches:
|
|||||||
| Novo bucket no MinIO | `lronetto-main`: `minio/init.sh` + variável no `.env.example` |
|
| Novo bucket no MinIO | `lronetto-main`: `minio/init.sh` + variável no `.env.example` |
|
||||||
| Outro DB no postgres | `lronetto-main`: `postgres/init/01-create-databases.sh` + role nova |
|
| Outro DB no postgres | `lronetto-main`: `postgres/init/01-create-databases.sh` + role nova |
|
||||||
| Novo subdomínio Caddy | `lronetto-main`: `caddy/Caddyfile` + container_name correspondente |
|
| Novo subdomínio Caddy | `lronetto-main`: `caddy/Caddyfile` + container_name correspondente |
|
||||||
| Nova app na rede | novo repo com `docker-compose.yml`, declarar `infra-net` como external, conectar a `postgres`/`redis`/`minio` por nome, e referenciar no Makefile orquestrador |
|
| Nova app na rede | novo repo com `docker-compose.yml`, declarar `infra-net` como external, conectar a `postgres`/`redis`/`minio` por nome, e referenciar no Makefile orquestrador. Exemplos reais já rodando assim: `lronetto-finance` e `lronetto-claudeweb` (seção 2) |
|
||||||
| Nova tela no front | `apps/web/src/routes/` + rota em `App.tsx` |
|
| Nova tela no front | `apps/web/src/routes/` + rota em `App.tsx` |
|
||||||
| Schema compartilhado front-back | duplica: Zod em `packages/shared/src/schemas.ts` (TS) + Pydantic em `apps/api/app/schemas/api.py` (Python). **Camelo nos dois** |
|
| Schema compartilhado front-back | duplica: Zod em `packages/shared/src/schemas.ts` (TS) + Pydantic em `apps/api/app/schemas/api.py` (Python). **Camelo nos dois** |
|
||||||
| Workflow CI no Gitea | `.gitea/workflows/*.yml` no repo alvo (sintaxe GitHub Actions) — runner já registrado. Ex.: deploy do app em `lronetto-wedding` |
|
| Workflow CI no Gitea | `.gitea/workflows/*.yml` no repo alvo (sintaxe GitHub Actions) — runner já registrado. Ex.: deploy do app em `lronetto-wedding` |
|
||||||
|
|||||||
149
Makefile
149
Makefile
@ -1,81 +1,67 @@
|
|||||||
.PHONY: help network network-claudeweb up down restart status \
|
.PHONY: help network up down restart status \
|
||||||
up-main up-gitea up-wedding up-finance up-bomvizinho up-claudeweb \
|
up-main up-gitea up-wedding up-finance up-claudeweb \
|
||||||
down-main down-gitea down-wedding down-finance down-bomvizinho down-claudeweb \
|
down-main down-gitea down-wedding down-finance down-claudeweb \
|
||||||
logs-main logs-gitea logs-wedding logs-finance logs-bomvizinho logs-claudeweb \
|
logs-main logs-gitea logs-wedding logs-finance logs-claudeweb \
|
||||||
pull-main pull-gitea pull-wedding pull-finance pull-bomvizinho pull-claudeweb \
|
pull-main pull-gitea pull-wedding pull-finance pull-claudeweb \
|
||||||
rebuild-wedding rebuild-finance rebuild-bomvizinho rebuild-claudeweb \
|
rebuild-wedding rebuild-finance rebuild-claudeweb backup-vps
|
||||||
clone-claudeweb clone-bomvizinho
|
|
||||||
|
|
||||||
# Orquestrador das stacks. `lronetto-main` é o "platform layer"
|
# Orquestrador do "core" das stacks do casamento (main + gitea + wedding, os 3
|
||||||
# (postgres + redis + minio + pgadmin + caddy). Os demais repos são clonados
|
# repos que este CLAUDE.md documenta em detalhe). `lronetto-main` é o
|
||||||
# como diretórios IRMÃOS e referenciados aqui. Ajuste os caminhos abaixo se
|
# "platform layer" (postgres + redis + minio + pgadmin + caddy) e também serve
|
||||||
# usar outro layout no disco.
|
# de infra base pra OUTROS consumidores não relacionados ao casamento
|
||||||
|
# (lronetto-finance, lronetto-claudeweb) — ver seção 2 do CLAUDE.md.
|
||||||
#
|
#
|
||||||
# lronetto-gitea https://gitea.lronetto.com/lronetto/lronetto-gitea.git
|
# `make up`/`down`/`restart`/`status` cobrem só o core (main+gitea+wedding),
|
||||||
# lronetto-wedding https://gitea.lronetto.com/lronetto/lronetto-wedding.git
|
# de propósito: finance/claudeweb têm ciclo de vida e deploy CI próprios,
|
||||||
# lronetto-finance https://gitea.lronetto.com/lronetto/lronetto-finance.git
|
# independentes deste projeto. Os targets up-finance/up-claudeweb existem só
|
||||||
# lronetto-bom-vizinho https://gitea.lronetto.com/lronetto/lronetto-bom-vizinho.git
|
# de conveniência operacional (ex.: subir tudo depois de um reboot do VPS).
|
||||||
# lronetto-claudeweb https://gitea.lronetto.com/lronetto/lronetto-claudeweb.git
|
|
||||||
#
|
#
|
||||||
# Cada repo põe o compose e o .env num lugar diferente — daí os -f/--env-file
|
# Todos os repos são clonados como diretórios IRMÃOS e referenciados aqui.
|
||||||
# explícitos abaixo em vez de um padrão único.
|
# Ajuste os caminhos abaixo se usar outro layout no disco.
|
||||||
|
|
||||||
NET := infra-net
|
NET := infra-net
|
||||||
# Rede isolada dos workers efêmeros do claudeweb (declarada external no compose dele).
|
WEDDING_DIR ?= ../lronetto-wedding
|
||||||
NET_WORKERS := claudeweb-workers
|
GITEA_DIR ?= ../lronetto-gitea
|
||||||
|
FINANCE_DIR ?= ../lronetto-finance
|
||||||
|
CLAUDEWEB_DIR ?= ../lronetto-claudeweb
|
||||||
|
|
||||||
WEDDING_DIR ?= ../lronetto-wedding
|
DC_MAIN := docker compose -f docker-compose.yml --env-file .env
|
||||||
GITEA_DIR ?= ../lronetto-gitea
|
DC_GITEA := docker compose -f $(GITEA_DIR)/docker-compose.yml --env-file $(GITEA_DIR)/.env
|
||||||
FINANCE_DIR ?= ../lronetto-finance
|
DC_WEDDING := docker compose -f $(WEDDING_DIR)/docker-compose.yml --env-file $(WEDDING_DIR)/.env
|
||||||
BOMVIZINHO_DIR ?= ../lronetto-bom-vizinho
|
DC_FINANCE := docker compose -f $(FINANCE_DIR)/docker-compose.yml --env-file $(FINANCE_DIR)/.env
|
||||||
CLAUDEWEB_DIR ?= ../lronetto-claudeweb
|
|
||||||
|
|
||||||
CLAUDEWEB_REPO ?= https://gitea.lronetto.com/lronetto/lronetto-claudeweb.git
|
|
||||||
BOMVIZINHO_REPO ?= https://gitea.lronetto.com/lronetto/lronetto-bom-vizinho.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
|
|
||||||
# bom-vizinho: compose E .env vivem em infra/.
|
|
||||||
DC_BOMVIZINHO := docker compose -f $(BOMVIZINHO_DIR)/infra/docker-compose.yml --env-file $(BOMVIZINHO_DIR)/infra/.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
|
DC_CLAUDEWEB := docker compose -f $(CLAUDEWEB_DIR)/deploy/compose.yml --env-file $(CLAUDEWEB_DIR)/.env
|
||||||
|
CLAUDEWEB_WORKER_IMAGE ?= claudeweb-worker
|
||||||
|
|
||||||
help:
|
help:
|
||||||
@echo "Stacks: main (este repo) | gitea ($(GITEA_DIR)) | wedding ($(WEDDING_DIR))"
|
@echo "Core (orquestrado por make up/down/restart/status):"
|
||||||
@echo " finance ($(FINANCE_DIR)) | bomvizinho ($(BOMVIZINHO_DIR))"
|
@echo " main (este repo) | gitea ($(GITEA_DIR)) | wedding ($(WEDDING_DIR))"
|
||||||
@echo " claudeweb ($(CLAUDEWEB_DIR))"
|
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo " make up Sobe tudo (main -> gitea -> wedding -> finance -> bomvizinho -> claudeweb)"
|
@echo "Outros consumidores da infra base (targets avulsos, ciclo de vida próprio):"
|
||||||
@echo " make down Desce tudo na ordem inversa"
|
@echo " finance ($(FINANCE_DIR)) | claudeweb ($(CLAUDEWEB_DIR))"
|
||||||
@echo " make restart down + up"
|
|
||||||
@echo " make status ps de todas as stacks"
|
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo " make up-main Sobe só a stack main"
|
@echo " make up Sobe o core na ordem (main -> gitea -> wedding)"
|
||||||
@echo " make up-gitea Sobe só o gitea"
|
@echo " make down Desce o core na ordem inversa"
|
||||||
@echo " make up-wedding Build + up do app wedding"
|
@echo " make restart down + up"
|
||||||
@echo " make up-finance Build + up do app finance"
|
@echo " make status ps do core + finance/claudeweb (se de pé)"
|
||||||
@echo " make up-bomvizinho Build + up do app bom-vizinho"
|
@echo ""
|
||||||
@echo " make up-claudeweb Build (incl. worker-image) + up do claudeweb"
|
@echo " make up-main Sobe só a stack main"
|
||||||
@echo " make rebuild-{wedding,finance,bomvizinho,claudeweb}"
|
@echo " make up-gitea Sobe só o gitea"
|
||||||
@echo " make down-{main,gitea,wedding,finance,bomvizinho,claudeweb}"
|
@echo " make up-wedding Build + up do app wedding"
|
||||||
@echo " make logs-{main,gitea,wedding,finance,bomvizinho,claudeweb}"
|
@echo " make up-finance Build + up do app finance"
|
||||||
@echo " make pull-{main,gitea,wedding,finance,bomvizinho,claudeweb}"
|
@echo " make up-claudeweb Build da imagem do worker + up do claudeweb (api+web)"
|
||||||
@echo " make clone-claudeweb Clona $(CLAUDEWEB_REPO)"
|
@echo " make rebuild-{wedding,finance,claudeweb} Force rebuild"
|
||||||
@echo " make clone-bomvizinho Clona $(BOMVIZINHO_REPO)"
|
@echo " make down-{main,gitea,wedding,finance,claudeweb}"
|
||||||
@echo " make network Cria a network external '$(NET)' (idempotente)"
|
@echo " make logs-{main,gitea,wedding,finance,claudeweb}"
|
||||||
@echo " make network-claudeweb Cria a network external '$(NET_WORKERS)' (idempotente)"
|
@echo " make pull-{main,gitea,wedding,finance,claudeweb}"
|
||||||
|
@echo " make network Cria a network external '$(NET)' (idempotente)"
|
||||||
|
@echo " make backup-vps Backup completo do host (postgres+redis+gitea+envs+caddy certs)"
|
||||||
|
|
||||||
network:
|
network:
|
||||||
@./network.sh
|
@./network.sh
|
||||||
|
|
||||||
network-claudeweb:
|
up: network up-main up-gitea up-wedding
|
||||||
@INFRA_NETWORK=$(NET_WORKERS) ./network.sh
|
|
||||||
|
|
||||||
up: network up-main up-gitea up-wedding up-finance up-bomvizinho up-claudeweb
|
down: down-wedding down-gitea down-main
|
||||||
|
|
||||||
down: down-claudeweb down-bomvizinho down-finance down-wedding down-gitea down-main
|
|
||||||
|
|
||||||
restart: down up
|
restart: down up
|
||||||
|
|
||||||
@ -84,7 +70,6 @@ status:
|
|||||||
@$(DC_GITEA) ps || true
|
@$(DC_GITEA) ps || true
|
||||||
@$(DC_WEDDING) ps || true
|
@$(DC_WEDDING) ps || true
|
||||||
@$(DC_FINANCE) ps || true
|
@$(DC_FINANCE) ps || true
|
||||||
@$(DC_BOMVIZINHO) ps || true
|
|
||||||
@$(DC_CLAUDEWEB) ps || true
|
@$(DC_CLAUDEWEB) ps || true
|
||||||
|
|
||||||
up-main: network
|
up-main: network
|
||||||
@ -99,13 +84,9 @@ up-wedding: network
|
|||||||
up-finance: network
|
up-finance: network
|
||||||
$(DC_FINANCE) up -d --build
|
$(DC_FINANCE) up -d --build
|
||||||
|
|
||||||
up-bomvizinho: network
|
up-claudeweb: network
|
||||||
$(DC_BOMVIZINHO) up -d --build
|
docker build -t $(CLAUDEWEB_WORKER_IMAGE) -f $(CLAUDEWEB_DIR)/worker/Dockerfile $(CLAUDEWEB_DIR)
|
||||||
|
$(DC_CLAUDEWEB) 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
|
rebuild-wedding: network
|
||||||
$(DC_WEDDING) build --no-cache
|
$(DC_WEDDING) build --no-cache
|
||||||
@ -115,12 +96,8 @@ rebuild-finance: network
|
|||||||
$(DC_FINANCE) build --no-cache
|
$(DC_FINANCE) build --no-cache
|
||||||
$(DC_FINANCE) up -d
|
$(DC_FINANCE) up -d
|
||||||
|
|
||||||
rebuild-bomvizinho: network
|
rebuild-claudeweb: network
|
||||||
$(DC_BOMVIZINHO) build --no-cache
|
docker build -t $(CLAUDEWEB_WORKER_IMAGE) -f $(CLAUDEWEB_DIR)/worker/Dockerfile $(CLAUDEWEB_DIR)
|
||||||
$(DC_BOMVIZINHO) up -d
|
|
||||||
|
|
||||||
rebuild-claudeweb: network network-claudeweb
|
|
||||||
$(MAKE) -C $(CLAUDEWEB_DIR) worker-image
|
|
||||||
$(DC_CLAUDEWEB) build --no-cache
|
$(DC_CLAUDEWEB) build --no-cache
|
||||||
$(DC_CLAUDEWEB) up -d
|
$(DC_CLAUDEWEB) up -d
|
||||||
|
|
||||||
@ -136,9 +113,6 @@ down-wedding:
|
|||||||
down-finance:
|
down-finance:
|
||||||
$(DC_FINANCE) down
|
$(DC_FINANCE) down
|
||||||
|
|
||||||
down-bomvizinho:
|
|
||||||
$(DC_BOMVIZINHO) down
|
|
||||||
|
|
||||||
down-claudeweb:
|
down-claudeweb:
|
||||||
$(DC_CLAUDEWEB) down
|
$(DC_CLAUDEWEB) down
|
||||||
|
|
||||||
@ -154,9 +128,6 @@ logs-wedding:
|
|||||||
logs-finance:
|
logs-finance:
|
||||||
$(DC_FINANCE) logs -f
|
$(DC_FINANCE) logs -f
|
||||||
|
|
||||||
logs-bomvizinho:
|
|
||||||
$(DC_BOMVIZINHO) logs -f
|
|
||||||
|
|
||||||
logs-claudeweb:
|
logs-claudeweb:
|
||||||
$(DC_CLAUDEWEB) logs -f
|
$(DC_CLAUDEWEB) logs -f
|
||||||
|
|
||||||
@ -172,18 +143,8 @@ pull-wedding:
|
|||||||
pull-finance:
|
pull-finance:
|
||||||
$(DC_FINANCE) pull
|
$(DC_FINANCE) pull
|
||||||
|
|
||||||
pull-bomvizinho:
|
|
||||||
$(DC_BOMVIZINHO) pull
|
|
||||||
|
|
||||||
pull-claudeweb:
|
pull-claudeweb:
|
||||||
$(DC_CLAUDEWEB) pull
|
$(DC_CLAUDEWEB) pull
|
||||||
|
|
||||||
clone-claudeweb:
|
backup-vps:
|
||||||
@test -d $(CLAUDEWEB_DIR)/.git \
|
@GITEA_DIR=$(GITEA_DIR) WEDDING_DIR=$(WEDDING_DIR) FINANCE_DIR=$(FINANCE_DIR) CLAUDEWEB_DIR=$(CLAUDEWEB_DIR) ./scripts/vps-backup.sh
|
||||||
&& echo "$(CLAUDEWEB_DIR) já existe" \
|
|
||||||
|| git clone $(CLAUDEWEB_REPO) $(CLAUDEWEB_DIR)
|
|
||||||
|
|
||||||
clone-bomvizinho:
|
|
||||||
@test -d $(BOMVIZINHO_DIR)/.git \
|
|
||||||
&& echo "$(BOMVIZINHO_DIR) já existe" \
|
|
||||||
|| git clone $(BOMVIZINHO_REPO) $(BOMVIZINHO_DIR)
|
|
||||||
|
|||||||
@ -29,6 +29,34 @@ wedding.{$DOMAIN_BASE} {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ----- Finance (lronetto-finance, repo à parte) -----
|
||||||
|
finance.{$DOMAIN_BASE} {
|
||||||
|
encode gzip zstd
|
||||||
|
header {
|
||||||
|
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
|
||||||
|
X-Content-Type-Options "nosniff"
|
||||||
|
Referrer-Policy "strict-origin-when-cross-origin"
|
||||||
|
Permissions-Policy "geolocation=(), microphone=(), camera=()"
|
||||||
|
Content-Security-Policy "default-src 'self'; script-src 'self' https://cdn.pluggy.ai; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; connect-src 'self' https://api.pluggy.ai; frame-src https://connect.pluggy.ai; frame-ancestors 'self'; base-uri 'self'; form-action 'self'"
|
||||||
|
-Server
|
||||||
|
}
|
||||||
|
reverse_proxy finance_app:8000
|
||||||
|
}
|
||||||
|
|
||||||
|
# ----- Claudeweb (lronetto-claudeweb, repo à parte) — subdomínio é "code", não "claudeweb" -----
|
||||||
|
code.{$DOMAIN_BASE} {
|
||||||
|
encode zstd gzip
|
||||||
|
|
||||||
|
@backend path /api/* /healthz /ws/*
|
||||||
|
handle @backend {
|
||||||
|
reverse_proxy claudeweb-api:8300
|
||||||
|
}
|
||||||
|
|
||||||
|
handle {
|
||||||
|
reverse_proxy claudeweb-web:80
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# ----- pgAdmin -----
|
# ----- pgAdmin -----
|
||||||
pgadmin.{$DOMAIN_BASE} {
|
pgadmin.{$DOMAIN_BASE} {
|
||||||
encode gzip
|
encode gzip
|
||||||
|
|||||||
@ -14,6 +14,12 @@ services:
|
|||||||
GITEA_DB_USER: ${GITEA_DB_USER:-gitea}
|
GITEA_DB_USER: ${GITEA_DB_USER:-gitea}
|
||||||
GITEA_DB_PASSWORD: ${GITEA_DB_PASSWORD}
|
GITEA_DB_PASSWORD: ${GITEA_DB_PASSWORD}
|
||||||
GITEA_DB_NAME: ${GITEA_DB_NAME:-gitea}
|
GITEA_DB_NAME: ${GITEA_DB_NAME:-gitea}
|
||||||
|
FINANCE_DB_USER: ${FINANCE_DB_USER:-finance}
|
||||||
|
FINANCE_DB_PASSWORD: ${FINANCE_DB_PASSWORD}
|
||||||
|
FINANCE_DB_NAME: ${FINANCE_DB_NAME:-finance}
|
||||||
|
CLAUDEWEB_DB_USER: ${CLAUDEWEB_DB_USER:-claudeweb}
|
||||||
|
CLAUDEWEB_DB_PASSWORD: ${CLAUDEWEB_DB_PASSWORD}
|
||||||
|
CLAUDEWEB_DB_NAME: ${CLAUDEWEB_DB_NAME:-claudeweb}
|
||||||
volumes:
|
volumes:
|
||||||
- ./postgres/data:/var/lib/postgresql/data
|
- ./postgres/data:/var/lib/postgresql/data
|
||||||
- ./postgres/init:/docker-entrypoint-initdb.d:ro
|
- ./postgres/init:/docker-entrypoint-initdb.d:ro
|
||||||
@ -69,6 +75,7 @@ services:
|
|||||||
MINIO_ROOT_USER: ${MINIO_ROOT_USER}
|
MINIO_ROOT_USER: ${MINIO_ROOT_USER}
|
||||||
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
|
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
|
||||||
WEDDING_BUCKET: ${WEDDING_BUCKET:-wedding-media}
|
WEDDING_BUCKET: ${WEDDING_BUCKET:-wedding-media}
|
||||||
|
CLAUDEWEB_BUCKET: ${CLAUDEWEB_BUCKET:-claudeweb-artifacts}
|
||||||
volumes:
|
volumes:
|
||||||
- ./minio/init.sh:/init.sh:ro
|
- ./minio/init.sh:/init.sh:ro
|
||||||
- ./minio/cors.json:/cors.json:ro
|
- ./minio/cors.json:/cors.json:ro
|
||||||
|
|||||||
@ -1,13 +1,20 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# Inicializa o bucket usado pela stack wedding_photo. Roda como container
|
# Inicializa os buckets consumidos pelas stacks. Roda como container one-shot
|
||||||
# one-shot depois que o MinIO ficou healthy.
|
# depois que o MinIO ficou healthy.
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
mc alias set --quiet local http://minio:9000 "$MINIO_ROOT_USER" "$MINIO_ROOT_PASSWORD"
|
mc alias set --quiet local http://minio:9000 "$MINIO_ROOT_USER" "$MINIO_ROOT_PASSWORD"
|
||||||
|
|
||||||
|
# ----- wedding: bucket público (download anônimo) pra fotos/vídeos dos convidados -----
|
||||||
mc mb --ignore-existing "local/$WEDDING_BUCKET"
|
mc mb --ignore-existing "local/$WEDDING_BUCKET"
|
||||||
mc anonymous set download "local/$WEDDING_BUCKET"
|
mc anonymous set download "local/$WEDDING_BUCKET"
|
||||||
mc cors set "local/$WEDDING_BUCKET" /cors.json 2>/dev/null || \
|
mc cors set "local/$WEDDING_BUCKET" /cors.json 2>/dev/null || \
|
||||||
echo "[minio-init] cors set ignorado (versão antiga do mc?)"
|
echo "[minio-init] cors set ignorado (versão antiga do mc?)"
|
||||||
|
|
||||||
echo "[minio-init] bucket '$WEDDING_BUCKET' pronto (anonymous download + CORS)"
|
echo "[minio-init] bucket '$WEDDING_BUCKET' pronto (anonymous download + CORS)"
|
||||||
|
|
||||||
|
# ----- claudeweb: bucket privado pra artefatos de sessão (diff + log, M3/RF-14).
|
||||||
|
# Opcional: o app só sobe artefatos se S3_ENDPOINT estiver preenchido no seu
|
||||||
|
# .env; sem isso este bucket fica criado mas sem uso. Sem download anônimo
|
||||||
|
# (diferente do wedding-media) porque o conteúdo não é público.
|
||||||
|
mc mb --ignore-existing "local/${CLAUDEWEB_BUCKET:-claudeweb-artifacts}"
|
||||||
|
echo "[minio-init] bucket '${CLAUDEWEB_BUCKET:-claudeweb-artifacts}' pronto (privado)"
|
||||||
|
|||||||
@ -12,6 +12,14 @@ psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-E
|
|||||||
CREATE ROLE "${GITEA_DB_USER}" WITH LOGIN PASSWORD '${GITEA_DB_PASSWORD}';
|
CREATE ROLE "${GITEA_DB_USER}" WITH LOGIN PASSWORD '${GITEA_DB_PASSWORD}';
|
||||||
CREATE DATABASE "${GITEA_DB_NAME}" OWNER "${GITEA_DB_USER}";
|
CREATE DATABASE "${GITEA_DB_NAME}" OWNER "${GITEA_DB_USER}";
|
||||||
GRANT ALL PRIVILEGES ON DATABASE "${GITEA_DB_NAME}" TO "${GITEA_DB_USER}";
|
GRANT ALL PRIVILEGES ON DATABASE "${GITEA_DB_NAME}" TO "${GITEA_DB_USER}";
|
||||||
|
|
||||||
|
CREATE ROLE "${FINANCE_DB_USER}" WITH LOGIN PASSWORD '${FINANCE_DB_PASSWORD}';
|
||||||
|
CREATE DATABASE "${FINANCE_DB_NAME}" OWNER "${FINANCE_DB_USER}";
|
||||||
|
GRANT ALL PRIVILEGES ON DATABASE "${FINANCE_DB_NAME}" TO "${FINANCE_DB_USER}";
|
||||||
|
|
||||||
|
CREATE ROLE "${CLAUDEWEB_DB_USER}" WITH LOGIN PASSWORD '${CLAUDEWEB_DB_PASSWORD}';
|
||||||
|
CREATE DATABASE "${CLAUDEWEB_DB_NAME}" OWNER "${CLAUDEWEB_DB_USER}";
|
||||||
|
GRANT ALL PRIVILEGES ON DATABASE "${CLAUDEWEB_DB_NAME}" TO "${CLAUDEWEB_DB_USER}";
|
||||||
EOSQL
|
EOSQL
|
||||||
|
|
||||||
echo "[postgres-init] roles + databases criados para wedding (${WEDDING_DB_NAME}) e gitea (${GITEA_DB_NAME})"
|
echo "[postgres-init] roles + databases criados para wedding (${WEDDING_DB_NAME}), gitea (${GITEA_DB_NAME}), finance (${FINANCE_DB_NAME}) e claudeweb (${CLAUDEWEB_DB_NAME})"
|
||||||
|
|||||||
146
scripts/vps-backup.sh
Executable file
146
scripts/vps-backup.sh
Executable file
@ -0,0 +1,146 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Backup completo do VPS (nível host, fora dos sidecars de cada stack).
|
||||||
|
#
|
||||||
|
# Cobre o que os sidecars de `lronetto-wedding` (postgres-backup-local +
|
||||||
|
# media-backup) NÃO cobrem sozinhos: Redis, dados do Gitea (repos + config),
|
||||||
|
# .env de todos os consumidores da infra base (wedding, gitea, finance,
|
||||||
|
# claudeweb) e certs do Caddy. Pensado pra rodar via cron no host, fora de
|
||||||
|
# qualquer container.
|
||||||
|
#
|
||||||
|
# Nota: o dump do Postgres é `pg_dumpall` (passo 1) — cobre TODOS os bancos da
|
||||||
|
# instância de uma vez (wedding, gitea, finance, claudeweb), não só o da
|
||||||
|
# wedding. Não precisa de um passo por app.
|
||||||
|
#
|
||||||
|
# Uso:
|
||||||
|
# ./scripts/vps-backup.sh
|
||||||
|
#
|
||||||
|
# Cron sugerido (diário às 3h, log em backups/vps/cron.log):
|
||||||
|
# 0 3 * * * cd /opt/lronetto-main && ./scripts/vps-backup.sh >> backups/vps/cron.log 2>&1
|
||||||
|
#
|
||||||
|
# Env vars (todas opcionais, com default):
|
||||||
|
# BACKUP_DIR destino local dos tarballs (default: ./backups/vps)
|
||||||
|
# BACKUP_RETENTION_DAYS dias de retenção local (default: 14)
|
||||||
|
# BACKUP_REMOTE remote do rclone pra cópia offsite, ex.: r2:meu-bucket/vps-backup
|
||||||
|
# (vazio = não envia offsite)
|
||||||
|
# GITEA_DIR caminho do repo lronetto-gitea (default: ../lronetto-gitea)
|
||||||
|
# WEDDING_DIR caminho do repo lronetto-wedding (default: ../lronetto-wedding)
|
||||||
|
# FINANCE_DIR caminho do repo lronetto-finance (default: ../lronetto-finance)
|
||||||
|
# CLAUDEWEB_DIR caminho do repo lronetto-claudeweb (default: ../lronetto-claudeweb)
|
||||||
|
# MINIO_ROOT_USER / MINIO_ROOT_PASSWORD só necessários se quiser o mirror
|
||||||
|
# direto do MinIO por aqui (ver passo 4)
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
MAIN_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||||
|
|
||||||
|
BACKUP_DIR="${BACKUP_DIR:-$MAIN_DIR/backups/vps}"
|
||||||
|
BACKUP_RETENTION_DAYS="${BACKUP_RETENTION_DAYS:-14}"
|
||||||
|
BACKUP_REMOTE="${BACKUP_REMOTE:-}"
|
||||||
|
GITEA_DIR="${GITEA_DIR:-$MAIN_DIR/../lronetto-gitea}"
|
||||||
|
WEDDING_DIR="${WEDDING_DIR:-$MAIN_DIR/../lronetto-wedding}"
|
||||||
|
FINANCE_DIR="${FINANCE_DIR:-$MAIN_DIR/../lronetto-finance}"
|
||||||
|
CLAUDEWEB_DIR="${CLAUDEWEB_DIR:-$MAIN_DIR/../lronetto-claudeweb}"
|
||||||
|
|
||||||
|
TS="$(date +%Y%m%d-%H%M%S)"
|
||||||
|
WORK_DIR="$(mktemp -d)"
|
||||||
|
STAGE="$WORK_DIR/vps-backup-$TS"
|
||||||
|
mkdir -p "$STAGE"
|
||||||
|
|
||||||
|
log() { echo "[vps-backup] $(date '+%Y-%m-%d %H:%M:%S') $*"; }
|
||||||
|
cleanup() { rm -rf "$WORK_DIR"; }
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
container_up() {
|
||||||
|
docker ps --format '{{.Names}}' | grep -qx "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 1. Postgres: dump lógico de TODOS os bancos + roles (pg_dumpall)
|
||||||
|
if container_up postgres; then
|
||||||
|
log "Dump do Postgres (pg_dumpall)..."
|
||||||
|
docker exec -i postgres pg_dumpall -U postgres | gzip > "$STAGE/postgres-all.sql.gz"
|
||||||
|
else
|
||||||
|
log "AVISO: container 'postgres' não está rodando — pulando dump, backup incompleto"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 2. Redis: snapshot RDB (BGSAVE + copia o dump.rdb gerado)
|
||||||
|
if container_up redis; then
|
||||||
|
log "Snapshot do Redis (BGSAVE)..."
|
||||||
|
docker exec redis redis-cli BGSAVE >/dev/null
|
||||||
|
for _ in $(seq 1 30); do
|
||||||
|
sleep 1
|
||||||
|
docker exec redis redis-cli INFO persistence 2>/dev/null | grep -q 'rdb_bgsave_in_progress:0' && break
|
||||||
|
done
|
||||||
|
docker cp redis:/data/dump.rdb "$STAGE/redis-dump.rdb" 2>/dev/null \
|
||||||
|
|| log "AVISO: não consegui copiar dump.rdb do redis"
|
||||||
|
else
|
||||||
|
log "AVISO: container 'redis' não está rodando — pulando snapshot"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 3. Gitea: repos + config + dados (tudo que o docker-compose do gitea monta em bind mount)
|
||||||
|
if [ -d "$GITEA_DIR" ]; then
|
||||||
|
if [ -d "$GITEA_DIR/gitea/data" ]; then
|
||||||
|
log "Compactando dados do Gitea ($GITEA_DIR/gitea/data)..."
|
||||||
|
tar -czf "$STAGE/gitea-data.tar.gz" -C "$GITEA_DIR" gitea/data
|
||||||
|
else
|
||||||
|
log "AVISO: $GITEA_DIR/gitea/data não encontrado (confira o bind mount no docker-compose.yml do gitea)"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log "AVISO: $GITEA_DIR não encontrado — pulando backup do Gitea (ajuste GITEA_DIR= se o caminho for outro)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 4. MinIO: mirror incremental do bucket de mídia via mc (opcional — a stack wedding já
|
||||||
|
# tem o sidecar media-backup fazendo isso continuamente; isso aqui é um extra/fallback
|
||||||
|
# se você rodar esse script num host que não tem o sidecar, ou quiser um snapshot avulso)
|
||||||
|
if command -v mc >/dev/null 2>&1 && container_up minio; then
|
||||||
|
log "Mirror do MinIO (bucket ${WEDDING_BUCKET:-wedding-media})..."
|
||||||
|
mc alias set vps-backup-src "http://localhost:9000" \
|
||||||
|
"${MINIO_ROOT_USER:?defina MINIO_ROOT_USER pra fazer o mirror do MinIO, ou remova o binário mc do PATH pra pular essa etapa}" \
|
||||||
|
"${MINIO_ROOT_PASSWORD:?defina MINIO_ROOT_PASSWORD pra fazer o mirror do MinIO}" >/dev/null
|
||||||
|
mkdir -p "$STAGE/minio-media"
|
||||||
|
mc mirror --quiet "vps-backup-src/${WEDDING_BUCKET:-wedding-media}" "$STAGE/minio-media" \
|
||||||
|
|| log "AVISO: mc mirror falhou"
|
||||||
|
mc alias remove vps-backup-src >/dev/null 2>&1 || true
|
||||||
|
else
|
||||||
|
log "mc indisponível (ou minio parado) — pulando mirror direto; confie no sidecar media-backup da stack wedding"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 5. .env de todos os consumidores da infra base (segredos!) — o tarball final
|
||||||
|
# fica com permissão 600. Cobre os repos "core" (wedding/gitea) e os demais
|
||||||
|
# consumidores do platform layer (finance/claudeweb), se estiverem clonados.
|
||||||
|
log "Copiando .env de todos os repos..."
|
||||||
|
mkdir -p "$STAGE/envs"
|
||||||
|
[ -f "$MAIN_DIR/.env" ] && cp "$MAIN_DIR/.env" "$STAGE/envs/lronetto-main.env"
|
||||||
|
[ -f "$GITEA_DIR/.env" ] && cp "$GITEA_DIR/.env" "$STAGE/envs/lronetto-gitea.env"
|
||||||
|
[ -f "$WEDDING_DIR/.env" ] && cp "$WEDDING_DIR/.env" "$STAGE/envs/lronetto-wedding.env"
|
||||||
|
[ -f "$FINANCE_DIR/.env" ] && cp "$FINANCE_DIR/.env" "$STAGE/envs/lronetto-finance.env"
|
||||||
|
[ -f "$CLAUDEWEB_DIR/.env" ] && cp "$CLAUDEWEB_DIR/.env" "$STAGE/envs/lronetto-claudeweb.env"
|
||||||
|
|
||||||
|
# 6. Certs do Caddy (evita reemissão no Let's Encrypt depois de um restore)
|
||||||
|
if [ -d "$MAIN_DIR/caddy/data" ]; then
|
||||||
|
log "Compactando certs do Caddy..."
|
||||||
|
tar -czf "$STAGE/caddy-data.tar.gz" -C "$MAIN_DIR/caddy" data
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 7. Empacota tudo num único tarball final, permissão restrita (tem segredo dentro)
|
||||||
|
mkdir -p "$BACKUP_DIR"
|
||||||
|
FINAL="$BACKUP_DIR/vps-backup-$TS.tar.gz"
|
||||||
|
log "Gerando tarball final: $FINAL"
|
||||||
|
tar -czf "$FINAL" -C "$WORK_DIR" "vps-backup-$TS"
|
||||||
|
chmod 600 "$FINAL"
|
||||||
|
|
||||||
|
# 8. Envia offsite via rclone, se configurado (BACKUP_REMOTE + rclone instalado)
|
||||||
|
if [ -n "$BACKUP_REMOTE" ]; then
|
||||||
|
if command -v rclone >/dev/null 2>&1; then
|
||||||
|
log "Enviando offsite pra $BACKUP_REMOTE..."
|
||||||
|
rclone copy "$FINAL" "$BACKUP_REMOTE" || log "AVISO: rclone copy falhou"
|
||||||
|
else
|
||||||
|
log "AVISO: BACKUP_REMOTE definido mas rclone não está instalado — pulando envio offsite"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 9. Rotação: apaga tarballs locais mais velhos que a retenção configurada
|
||||||
|
log "Rotacionando backups locais (> $BACKUP_RETENTION_DAYS dias)..."
|
||||||
|
find "$BACKUP_DIR" -name 'vps-backup-*.tar.gz' -mtime "+$BACKUP_RETENTION_DAYS" -print -delete
|
||||||
|
|
||||||
|
log "Backup concluído: $FINAL ($(du -h "$FINAL" | cut -f1))"
|
||||||
Loading…
Reference in New Issue
Block a user