docs: revisa a documentação com base no que a aplicação faz hoje
- README: o que a aplicação faz, migrations, BP_WEB_PORT e testes com
go.sum/package-lock.json (sem go mod tidy)
- ARQUITETURA: esquema real (00001 a 00003), rotas que faltavam, Compose
e imagens atuais, cadeia de proxies, retenção, situação dos testes,
decisões 30 a 33 e estado da implementação
- DEPLOY: cópia por tar, BP_WEB_PORT em todas as etapas e atualização
para a versão com exclusão de contas
- MANUAL: papéis do owner e navegação por ano nos feriados
- openapi.yaml: DELETE /accounts/{id} e regras da conta restrita
- Dockerfiles: comentários sobre go.sum e package-lock.json
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -6,7 +6,9 @@ Passo a passo para colocar o Bot de Pontos no ar no servidor de produção:
|
||||
- **Acesso ao painel:** pelo **Nginx Proxy Manager (NPM)** que já existe em outra máquina da rede, com **certificado interno**.
|
||||
- **Endereço do painel:** `https://botpontos.lan` (troque pelo nome que você usar).
|
||||
|
||||
> O código **ainda não foi compilado nem testado**. A etapa 6 faz essa validação no próprio servidor antes de subir tudo. Se algo falhar, guarde a saída do comando para correção.
|
||||
> O backend compila e passa nos testes, e o painel passa na checagem de tipos. A etapa 6 repete essa validação no próprio servidor antes de subir tudo. Se algo falhar, guarde a saída do comando para correção.
|
||||
>
|
||||
> A porta do painel no servidor é **3000** por padrão. Se ela já estiver em uso, defina `BP_WEB_PORT` no `.env` (etapa 5.1) e use essa porta onde este guia diz 3000 (etapas 7, 8 e 9).
|
||||
|
||||
## Visão geral
|
||||
|
||||
@@ -28,7 +30,7 @@ Navegador ──HTTPS──► NPM (outra máquina) ──HTTP :3000──► Se
|
||||
| 5 | Criar `.env` e segredos | servidor |
|
||||
| 6 | Validar o código (testes) | servidor |
|
||||
| 7 | Subir os containers | servidor |
|
||||
| 8 | Firewall da porta 3000 | servidor |
|
||||
| 8 | Firewall da porta do painel | servidor |
|
||||
| 9 | DNS, certificado e Proxy Host | rede / NPM |
|
||||
| 10 | Primeiro acesso e primeiro admin | navegador / Telegram |
|
||||
| 11 | Backup fora da máquina | servidor |
|
||||
@@ -171,18 +173,24 @@ No servidor:
|
||||
mkdir -p /opt/botpontos
|
||||
```
|
||||
|
||||
No **Windows**, no PowerShell, dentro de `C:\Users\BrunoSantos\Documents\Codex\projeto prl3`, envie a pasta (troque usuário e IP):
|
||||
No **Windows**, no PowerShell, dentro da pasta que contém `bot-pontos-v2` (ex.: `E:\Bruno\GIT`), gere um pacote sem os arquivos locais. O `tar` já vem no Windows 10/11:
|
||||
|
||||
```powershell
|
||||
scp -r .\bot-pontos-v2 usuario@192.168.18.50:/tmp/
|
||||
tar -czf bot-pontos-v2.tgz --exclude=node_modules --exclude=.next --exclude=.git --exclude=.env --exclude=backups --exclude=tsconfig.tsbuildinfo bot-pontos-v2
|
||||
```
|
||||
|
||||
> A pasta `secrets/` deve ter só o `README.md` neste momento: os segredos são criados direto no servidor (etapa 5). Não é preciso enviar `node_modules` ou `.next`, se existirem.
|
||||
Envie para o servidor (troque usuário e IP):
|
||||
|
||||
De volta ao servidor, mova para o lugar final:
|
||||
```powershell
|
||||
scp .\bot-pontos-v2.tgz usuario@192.168.18.50:/tmp/
|
||||
```
|
||||
|
||||
> O pacote não leva `.env`, `backups/`, `node_modules`, `.next` nem o histórico do Git. A pasta `secrets/` deve ter só o `README.md`: os segredos são criados direto no servidor (etapa 5).
|
||||
|
||||
De volta ao servidor, extraia no lugar final:
|
||||
|
||||
```bash
|
||||
cp -r /tmp/bot-pontos-v2/. /opt/botpontos/ && rm -rf /tmp/bot-pontos-v2
|
||||
tar -xzf /tmp/bot-pontos-v2.tgz -C /opt/botpontos --strip-components=1 && rm /tmp/bot-pontos-v2.tgz
|
||||
```
|
||||
|
||||
```bash
|
||||
@@ -217,12 +225,24 @@ Ajuste:
|
||||
|
||||
```env
|
||||
BP_HOST_LAN_IP=192.168.18.50 # IP fixo do servidor
|
||||
BP_WEB_PORT=3000 # porta do painel no servidor; troque se a 3000 estiver em uso
|
||||
BP_PUBLIC_URL=https://botpontos.lan # exatamente o endereço que o navegador usa
|
||||
BP_NPM_IP=192.168.18.10 # IP do Nginx Proxy Manager
|
||||
BP_COOKIE_SECURE=true
|
||||
BP_LOG_LEVEL=info
|
||||
BP_DEFAULT_TIMEZONE=America/Sao_Paulo
|
||||
BP_HOLIDAY_LOCATION=3106200 # código IBGE da cidade dos feriados (3106200 = Belo Horizonte)
|
||||
BP_ENCRYPTION_KEY_VERSION=1
|
||||
```
|
||||
|
||||
Para saber se a 3000 já está ocupada no servidor:
|
||||
|
||||
```bash
|
||||
ss -ltn 'sport = :3000'
|
||||
```
|
||||
|
||||
Se aparecer alguma linha além do cabeçalho, escolha outra porta (ex.: `BP_WEB_PORT=3010`).
|
||||
|
||||
### 5.2 Segredos
|
||||
|
||||
```bash
|
||||
@@ -247,7 +267,7 @@ Token do bot (cole o seu entre as aspas simples):
|
||||
printf '%s' 'COLE_O_TOKEN_DO_BOTFATHER' > secrets/telegram_token
|
||||
```
|
||||
|
||||
Chave da feriadosapi.com, ou arquivo vazio se não tiver:
|
||||
Chave da feriadosapi.com (enviada como `Authorization: Bearer`), ou arquivo vazio se não tiver. A cidade dos feriados é o código IBGE em `BP_HOLIDAY_LOCATION` no `.env` (padrão `3106200`, Belo Horizonte):
|
||||
|
||||
```bash
|
||||
printf '%s' 'COLE_A_CHAVE' > secrets/holiday_api_key
|
||||
@@ -275,24 +295,24 @@ cat secrets/encryption_key
|
||||
|
||||
## 6. Validar o código (testes)
|
||||
|
||||
O código nunca foi compilado. Rode a validação no servidor antes de subir. Esses comandos usam containers temporários e não instalam Go nem Node na máquina.
|
||||
Rode a validação no servidor antes de subir, para confirmar que o código copiado compila nesta máquina. Esses comandos usam containers temporários e não instalam Go nem Node na máquina.
|
||||
|
||||
Backend — gera o `go.sum`, roda `go vet` e os testes:
|
||||
Backend — roda `go vet` e os testes com as versões fixadas no `go.sum`:
|
||||
|
||||
```bash
|
||||
docker run --rm -v "$PWD/backend:/src" -w /src golang:1.25-alpine sh -c "go mod tidy && go vet ./... && go test ./..."
|
||||
docker run --rm -v "$PWD/backend:/src" -w /src golang:1.25-alpine sh -c "go vet ./... && go test ./..."
|
||||
```
|
||||
|
||||
Painel — gera o `package-lock.json` e checa os tipos:
|
||||
Painel — instala as versões do `package-lock.json` e checa os tipos:
|
||||
|
||||
```bash
|
||||
docker run --rm -v "$PWD/web:/app" -w /app node:22-alpine sh -c "npm install && npx tsc --noEmit"
|
||||
docker run --rm -v "$PWD/web:/app" -w /app node:22-alpine sh -c "npm ci && npx tsc --noEmit"
|
||||
```
|
||||
|
||||
- Tudo passou: siga para a etapa 7.
|
||||
- Algo falhou: **pare aqui**, salve a saída completa e traga para correção.
|
||||
|
||||
> Os arquivos `go.sum` e `package-lock.json` gerados ficam no projeto e tornam os próximos builds reproduzíveis. Copie-os de volta para a pasta do Windows também.
|
||||
> Os arquivos `go.sum` e `package-lock.json` fazem parte do projeto e fixam as versões das dependências. Não rode `go mod tidy` no servidor: com Go 1.25 ele tenta baixar versões novas que exigem Go 1.26 e o build quebra.
|
||||
|
||||
---
|
||||
|
||||
@@ -327,7 +347,7 @@ docker compose logs --tail=100 migrate api worker
|
||||
|
||||
O worker deve registrar `liderança obtida; worker ativo` e `bot do Telegram iniciado`.
|
||||
|
||||
Teste local da porta (no próprio servidor):
|
||||
Teste local da porta (no próprio servidor; troque 3000 se usou outro `BP_WEB_PORT`):
|
||||
|
||||
```bash
|
||||
curl -s http://192.168.18.50:3000/healthz
|
||||
@@ -337,16 +357,24 @@ Deve responder `{"status":"ok"}`.
|
||||
|
||||
---
|
||||
|
||||
## 8. Firewall da porta 3000
|
||||
## 8. Firewall da porta do painel
|
||||
|
||||
Portas publicadas pelo Docker **ignoram** regras comuns de `ufw`/`iptables INPUT`. A regra vai na cadeia `DOCKER-USER`, aplicada por um serviço do systemd.
|
||||
|
||||
> **Outra porta:** se definiu `BP_WEB_PORT` (por exemplo `3010`), use essa porta no lugar de 3000 nesta etapa, no `WEB_PORT` do serviço de firewall e no Forward Port do NPM (etapa 9). Dentro do Docker o painel continua na 3000.
|
||||
|
||||
Coloque o IP do NPM no arquivo:
|
||||
|
||||
```bash
|
||||
sed -i 's/IP_DO_NPM/192.168.18.10/' deploy/botpontos-firewall.service
|
||||
```
|
||||
|
||||
Só se `BP_WEB_PORT` não for 3000, ajuste também a porta (troque 3010 pela sua):
|
||||
|
||||
```bash
|
||||
sed -i 's/WEB_PORT=3000/WEB_PORT=3010/' deploy/botpontos-firewall.service
|
||||
```
|
||||
|
||||
Instale e ative:
|
||||
|
||||
```bash
|
||||
@@ -363,7 +391,7 @@ Confira a regra:
|
||||
iptables -S DOCKER-USER
|
||||
```
|
||||
|
||||
Deve aparecer uma linha com `--ctorigdstport 3000` e `! -s 192.168.18.10/32 -j DROP`.
|
||||
Deve aparecer uma linha com `--ctorigdstport 3000` (ou a sua porta) e `! -s 192.168.18.10/32 -j DROP`.
|
||||
|
||||
**Teste de aceite:** de um computador da rede que **não** seja o NPM, o acesso direto precisa falhar (timeout):
|
||||
|
||||
@@ -398,7 +426,7 @@ O certificado raiz da CA interna precisa estar instalado nos computadores que ac
|
||||
| Details | Domain Names | `botpontos.lan` |
|
||||
| Details | Scheme | `http` |
|
||||
| Details | Forward Hostname / IP | `192.168.18.50` |
|
||||
| Details | Forward Port | `3000` |
|
||||
| Details | Forward Port | `3000` (ou o valor de `BP_WEB_PORT`) |
|
||||
| Details | Block Common Exploits | ligado |
|
||||
| Details | Websockets Support | desligado |
|
||||
| Details | Access List | uma lista que permita só a rede local (ex.: `192.168.18.0/24`) |
|
||||
@@ -504,7 +532,7 @@ A `encryption_key` usada no restore precisa ser a mesma da época do backup.
|
||||
|
||||
- [ ] `docker compose ps -a` com todos saudáveis e `migrate` em `exited (0)`.
|
||||
- [ ] `timedatectl` mostra o relógio sincronizado.
|
||||
- [ ] Acesso direto à porta 3000 bloqueado para quem não é o NPM.
|
||||
- [ ] Acesso direto à porta do painel (3000 ou `BP_WEB_PORT`) bloqueado para quem não é o NPM.
|
||||
- [ ] `https://botpontos.lan` abre sem alerta de certificado.
|
||||
- [ ] Login no painel funciona; conta owner criada.
|
||||
- [ ] Admin do Telegram recebe aviso ao surgir um novo `/cadastrar`.
|
||||
@@ -523,7 +551,7 @@ A `encryption_key` usada no restore precisa ser a mesma da época do backup.
|
||||
docker compose exec backup sh -c 'PGPASSWORD=$(cat /run/secrets/pg_password) pg_dump -h postgres -U botpontos -d botpontos -Fc -f /backups/antes-da-atualizacao.dump'
|
||||
```
|
||||
|
||||
2. Copie a nova versão do código para `/opt/botpontos` (como na etapa 4), **sem** sobrescrever `.env`, `secrets/` e `backups/`.
|
||||
2. Copie a nova versão do código para `/opt/botpontos` como na etapa 4. O pacote não leva `.env` nem `backups/`, e `secrets/` só tem o `README.md`, então os arquivos do servidor são mantidos.
|
||||
3. Reconstrua e suba (as migrations rodam sozinhas no serviço `migrate`):
|
||||
|
||||
```bash
|
||||
@@ -532,6 +560,25 @@ A `encryption_key` usada no restore precisa ser a mesma da época do backup.
|
||||
|
||||
4. Confira com `docker compose ps -a` e os logs.
|
||||
|
||||
**Versão com feriadosapi.com e conta de leitura restrita.** Ao atualizar de uma versão anterior (que usava a feriados.dev):
|
||||
|
||||
- Troque o conteúdo de `secrets/holiday_api_key` pela chave da feriadosapi.com (a chave antiga não serve).
|
||||
- No `.env`, troque `BP_HOLIDAY_LOCATION` de `MG-belo-horizonte` para `3106200` (código IBGE). Se esquecer, os feriados não sincronizam e vale segunda a sexta, com aviso aos admins.
|
||||
- A migration `00002` roda sozinha no serviço `migrate`. Ela só amplia o `CHECK` de `holidays.source`; os feriados já gravados continuam valendo, e o ano atual não é baixado de novo.
|
||||
- Para corrigir o ano com a nova API, use **Feriados → Sincronizar**: só entram datas que ainda não estão na tabela.
|
||||
- A conta de leitura restrita (10.4) não exige configuração extra, mas backend e painel precisam subir juntos.
|
||||
|
||||
**Versão com exclusão de contas e porta configurável.**
|
||||
|
||||
- A migration `00003` roda sozinha. Ela cria `audit_logs.actor_account_name` (preenchida para os eventos antigos) e ajusta as chaves estrangeiras para permitir **Contas → Excluir** sem perder a auditoria.
|
||||
- `BP_WEB_PORT` é opcional: sem ela, o painel continua na 3000. Se for trocar a porta, ajuste o `.env`, o `WEB_PORT` do firewall e o Forward Port do NPM. A regra antiga continua no `iptables` até o próximo boot; para aplicar a nova na hora:
|
||||
|
||||
```bash
|
||||
cp deploy/botpontos-firewall.service /etc/systemd/system/ && systemctl daemon-reload && systemctl restart botpontos-firewall
|
||||
```
|
||||
|
||||
Lembre de pôr de novo o IP do NPM (e a porta) no arquivo antes de copiar, como na etapa 8, porque a nova versão do arquivo volta com `IP_DO_NPM`.
|
||||
|
||||
Atualize também o sistema e as imagens base de tempos em tempos:
|
||||
|
||||
```bash
|
||||
@@ -549,6 +596,7 @@ docker compose pull postgres backup && docker compose up -d --build
|
||||
| Sintoma | Causa provável | O que fazer |
|
||||
| --- | --- | --- |
|
||||
| `docker compose up` reclama de `BP_HOST_LAN_IP` | `.env` ausente ou sem a variável | etapa 5.1 |
|
||||
| `web` não sobe: `address already in use` / `port is already allocated` | outra aplicação usa a porta do painel | defina outro `BP_WEB_PORT` (etapa 5.1) e ajuste firewall e NPM |
|
||||
| `secret ... file not found` | algum arquivo de `secrets/` não existe | etapa 5.2 (o `holiday_api_key` pode ser vazio, mas precisa existir) |
|
||||
| `migrate` termina com erro de senha | senhas do banco trocadas depois da primeira subida | as senhas só valem na 1ª inicialização do volume; veja `secrets/README.md` |
|
||||
| `api`/`worker` saem com `BP_ENCRYPTION_KEY ... obrigatório` | chave ausente ou com menos de 32 caracteres | refaça `secrets/encryption_key` |
|
||||
|
||||
Reference in New Issue
Block a user