merge: unify dev into main with mcp postgres support
This commit is contained in:
commit
d64e38a610
16 changed files with 1378 additions and 615 deletions
78
README.md
78
README.md
|
|
@ -1,52 +1,54 @@
|
|||
# Infracloud - Infraestrutura Rede5
|
||||
|
||||
Documentacao de infraestrutura como codigo (IaC) da Rede5.
|
||||
Este repositorio contem a documentacao e os manifestos de Infraestrutura como Codigo (IaC) da Rede5.
|
||||
|
||||
## Scripts
|
||||
## Estrutura do Projeto
|
||||
|
||||
| Script | Funcao |
|
||||
|--------|--------|
|
||||
| `scripts/check-connections.py` | Verifica todas as conexoes |
|
||||
| `scripts/sync-vault.js` | Sincroniza credenciais entre `~/.ssh/` e object storage |
|
||||
### Kubernetes (K3s)
|
||||
|
||||
## Estrutura
|
||||
Clusters Kubernetes gerenciados via K3s (Lightweight Kubernetes).
|
||||
|
||||
```text
|
||||
infracloud/
|
||||
|-- CONNECTIONS.md
|
||||
|-- OBJECT-STORAGE.md
|
||||
|-- containers/
|
||||
|-- inventcloud/
|
||||
| `-- invista/nexus/
|
||||
| |-- OCI.md
|
||||
| `-- azure-devops/
|
||||
|-- scripts/
|
||||
| |-- check-connections.py
|
||||
| `-- sync-vault.js
|
||||
`-- vps/
|
||||
```
|
||||
- [**Documentacao Geral K3s**](./k3s/README.md)
|
||||
- [Arquitetura](./k3s/architecture.md)
|
||||
- [Inventario de Servicos](./k3s/services_inventory.md)
|
||||
|
||||
## Acesso rapido
|
||||
### VPS (Virtual Private Servers)
|
||||
|
||||
| Servidor | Endereco | Plataforma | Documentacao |
|
||||
|----------|----------|------------|--------------|
|
||||
| Redbull | 185.194.141.70 | Coolify v4 | [vps/redbull](./vps/redbull/) |
|
||||
| Echo | 152.53.120.181 | Dokku | [vps/echo](./vps/echo/) |
|
||||
| Absam DB | db-60604.dc-us-1.absamcloud.com:11985 | PostgreSQL 17 | [vps/absam-db](./vps/absam-db/) |
|
||||
Servidores standalone gerenciados individualmente.
|
||||
|
||||
## Conexoes
|
||||
- [**Redbull**](./vps/redbull/README.md): Servidor de Desenvolvimento (Coolify PaaS). IP: 185.194.141.70
|
||||
- [**Echo**](./vps/echo/README.md): VPS Civo usada para workloads em Docker puro. IP: 152.53.120.181
|
||||
- [**Vim**](./vps/vim/README.md): Servidor de Producao (Dokku PaaS). IP: 38.19.201.52
|
||||
- [**NC1**](./vps/nc1/README.md): Servidor de Producao (Podman + Systemd). IP: 185.194.141.70
|
||||
|
||||
- [Guia de Conexoes](./CONNECTIONS.md)
|
||||
- [Status Nexus](./invista/nexus/CONNECTION-STATUS.md)
|
||||
### Cloud Databases
|
||||
|
||||
## Ultima auditoria
|
||||
Bancos de dados gerenciados.
|
||||
|
||||
- Data: 2026-03-05
|
||||
- Comando: `python scripts/check-connections.py`
|
||||
- Resultado: `14/20` OK (6 erros)
|
||||
- OCI: OK (namespace `grbb7qzeuoag`)
|
||||
- Kubernetes/OKE: falha na verificacao de `kubectl cluster-info`
|
||||
- [**Absam Cloud DB**](./databases/absam-cloud-db/README.md): PostgreSQL 17 (Absam.io). vpsID: 60604
|
||||
- **CloudClusters**: PostgreSQL 16 externo para GoHorseJobs
|
||||
|
||||
---
|
||||
### Containers
|
||||
|
||||
*Atualizado em: 2026-03-05*
|
||||
Definicoes de containers compartilhados entre servidores.
|
||||
|
||||
- [**Containers**](./containers/): manifests e units de Podman/Systemd
|
||||
- [**Forgejo**](./containers/forgejo.md): Git self-hosted e CI/CD
|
||||
|
||||
### Scripts
|
||||
|
||||
Automacoes e utilitarios do ecossistema.
|
||||
|
||||
- [**scripts/auto-organized**](./scripts/auto-organized/): scripts PowerShell e Shell existentes
|
||||
|
||||
### MCP
|
||||
|
||||
Servidor MCP para sustentacao do repo.
|
||||
|
||||
- [**Infracloud MCP**](./mcp/README.md): FastMCP baseado no layout real do repositorio
|
||||
|
||||
## Notas Operacionais
|
||||
|
||||
- O repo atual usa `scripts/auto-organized`, nao `dev-scripts`.
|
||||
- O repo atual nao possui `docs/openproject`.
|
||||
- `AGENT.md` nao deve ser usado como fonte de runtime porque contem segredos em plaintext.
|
||||
|
|
|
|||
110
containers/forgejo.md
Normal file
110
containers/forgejo.md
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
# Forgejo (Gitea) - pipe.gohorsejobs.com
|
||||
|
||||
Instância Forgejo self-hosted para mirror e CI/CD do projeto GoHorseJobs.
|
||||
|
||||
## Informacoes do Servico
|
||||
|
||||
| Campo | Valor |
|
||||
|-------|-------|
|
||||
| URL | https://pipe.gohorsejobs.com |
|
||||
| Usuario | yamamoto (admin) |
|
||||
| Email | yamamoto@rede5.com.br |
|
||||
| Organizacao | bohessefm |
|
||||
| Token | `~/.ssh/forgejo-token` |
|
||||
|
||||
## Autenticacao
|
||||
|
||||
### API Token
|
||||
```bash
|
||||
TOKEN=$(cat ~/.ssh/forgejo-token | grep FORGEJO_TOKEN | cut -d= -f2)
|
||||
curl -H "Authorization: token $TOKEN" "https://pipe.gohorsejobs.com/api/v1/user"
|
||||
```
|
||||
|
||||
### SSH
|
||||
```bash
|
||||
git clone git@pipe.gohorsejobs.com:bohessefm/gohorsejobs.git
|
||||
```
|
||||
|
||||
## Repositorios
|
||||
|
||||
| Repositorio | Mirror de | Branch Principal |
|
||||
|-------------|-----------|------------------|
|
||||
| bohessefm/gohorsejobs | github.com/rede5/gohorsejobs | dev |
|
||||
|
||||
## CI/CD
|
||||
|
||||
O Forgejo roda workflows do `.forgejo/workflows/` para:
|
||||
- Build e push de imagens Docker
|
||||
- Deploy no K3s via kubectl
|
||||
|
||||
### Secrets e Variables
|
||||
|
||||
Configurados em Settings → Secrets and Variables:
|
||||
|
||||
**Secrets:**
|
||||
- `FORGEJO_TOKEN` - Token de acesso ao registry
|
||||
- `KUBE_CONFIG` - Configuracao kubectl
|
||||
- `RSA_PRIVATE_KEY_BASE64` - Chave RSA privada
|
||||
|
||||
**Variables:**
|
||||
- `DATABASE_URL` - String de conexao PostgreSQL
|
||||
- `AMQP_URL` - URL RabbitMQ
|
||||
- `JWT_SECRET` - Secret JWT
|
||||
- `S3_BUCKET`, `AWS_*` - Credenciais S3
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### Usuario
|
||||
```bash
|
||||
curl -H "Authorization: token $TOKEN" "https://pipe.gohorsejobs.com/api/v1/user"
|
||||
```
|
||||
|
||||
### Repositorios
|
||||
```bash
|
||||
curl -H "Authorization: token $TOKEN" "https://pipe.gohorsejobs.com/api/v1/user/repos"
|
||||
curl -H "Authorization: token $TOKEN" "https://pipe.gohorsejobs.com/api/v1/repos/bohessefm/gohorsejobs"
|
||||
```
|
||||
|
||||
### Issues
|
||||
```bash
|
||||
curl -H "Authorization: token $TOKEN" "https://pipe.gohorsejobs.com/api/v1/repos/bohessefm/gohorsejobs/issues"
|
||||
```
|
||||
|
||||
### Webhooks
|
||||
```bash
|
||||
# Listar webhooks
|
||||
curl -H "Authorization: token $TOKEN" "https://pipe.gohorsejobs.com/api/v1/repos/bohessefm/gohorsejobs/hooks"
|
||||
|
||||
# Criar webhook
|
||||
curl -X POST -H "Authorization: token $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
"https://pipe.gohorsejobs.com/api/v1/repos/bohessefm/gohorsejobs/hooks" \
|
||||
-d '{
|
||||
"type": "gitea",
|
||||
"config": {
|
||||
"url": "https://redbull.rede5.com.br/api/v1/webhooks/deploy?uuid=iw4sow8s0kkg4cccsk08gsoo",
|
||||
"content_type": "json"
|
||||
},
|
||||
"events": ["push"],
|
||||
"active": true
|
||||
}'
|
||||
```
|
||||
|
||||
## Docker Registry
|
||||
|
||||
O Forgejo inclui um registry Docker integrado:
|
||||
|
||||
```bash
|
||||
# Login
|
||||
echo $TOKEN | docker login pipe.gohorsejobs.com -u bohessefm --password-stdin
|
||||
|
||||
# Pull imagem
|
||||
docker pull pipe.gohorsejobs.com/bohessefm/gohorsejobs:latest
|
||||
docker pull pipe.gohorsejobs.com/bohessefm/backoffice:latest
|
||||
```
|
||||
|
||||
## Links
|
||||
|
||||
- Console: https://pipe.gohorsejobs.com
|
||||
- API Docs: https://pipe.gohorsejobs.com/api/swagger
|
||||
- Credenciais: `~/.ssh/forgejo-token`
|
||||
130
databases/absam-cloud-db/README.md
Normal file
130
databases/absam-cloud-db/README.md
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
# Absam Cloud DB - PostgreSQL Gerenciado
|
||||
|
||||
Cloud Database gerenciado pela Absam.io (ID: 60604). Hospeda múltiplos bancos de dados para os projetos da Rede5.
|
||||
|
||||
## Informacoes do Servidor
|
||||
|
||||
| Campo | Valor |
|
||||
|-------|-------|
|
||||
| vpsID | 60604 |
|
||||
| Nome | novo-cloud-database |
|
||||
| OS | PostgreSQL 17 |
|
||||
| Provedor | Absam.io |
|
||||
|
||||
## Conectividade
|
||||
|
||||
### SSH
|
||||
|
||||
| Campo | Valor |
|
||||
|-------|-------|
|
||||
| Host | db-60604.dc-us-1.absamcloud.com |
|
||||
| Porta | 18863 |
|
||||
| Usuario | admin |
|
||||
| Senha | `~/.ssh/absam-db-novo` |
|
||||
|
||||
### PostgreSQL
|
||||
|
||||
| Tipo | Host | Porta |
|
||||
|------|------|-------|
|
||||
| Privado (interno) | 10.0.9.219 | 5432 |
|
||||
| Publico | db-60604.dc-us-1.absamcloud.com | 11985 |
|
||||
|
||||
### Credenciais do Banco
|
||||
|
||||
| Campo | Valor |
|
||||
|-------|-------|
|
||||
| Database | saveinmed |
|
||||
| Usuario | saveinmed |
|
||||
| Senha | `8ljys1jlnfmu` |
|
||||
|
||||
> Credenciais SSH completas em `~/.ssh/absam-db-novo`
|
||||
|
||||
## Configuracao SSH
|
||||
|
||||
Adicionar ao `~/.ssh/config`:
|
||||
|
||||
```
|
||||
Host absam-db
|
||||
HostName db-60604.dc-us-1.absamcloud.com
|
||||
User admin
|
||||
Port 18863
|
||||
PreferredAuthentications password
|
||||
PubkeyAuthentication no
|
||||
```
|
||||
|
||||
## Uso
|
||||
|
||||
### Conectar via SSH
|
||||
|
||||
```bash
|
||||
ssh absam-db
|
||||
# Senha: ver ~/.ssh/absam-db-novo
|
||||
```
|
||||
|
||||
### Conectar ao PostgreSQL (via tunel SSH)
|
||||
|
||||
```bash
|
||||
# Criar tunel SSH
|
||||
ssh -L 15432:10.0.9.219:5432 absam-db -N
|
||||
|
||||
# Conectar ao banco
|
||||
psql -h localhost -p 15432 -U saveinmed -d saveinmed
|
||||
```
|
||||
|
||||
### Conectar ao PostgreSQL (porta publica)
|
||||
|
||||
```bash
|
||||
psql -h db-60604.dc-us-1.absamcloud.com -p 11985 -U saveinmed -d saveinmed
|
||||
```
|
||||
|
||||
## Databases Disponiveis
|
||||
|
||||
| Database | Proprietario |
|
||||
|----------|--------------|
|
||||
| saveinmed | postgres |
|
||||
| gohorsejobs | postgres |
|
||||
| rodiziosdaqui | postgres |
|
||||
| ghj_codex | postgres |
|
||||
| postgres | postgres |
|
||||
|
||||
## Projetos que utilizam este servidor
|
||||
|
||||
- [saveinmed](../../saveinmed/) - Backend Medusa v2
|
||||
|
||||
---
|
||||
|
||||
# CloudClusters Database (Externo)
|
||||
|
||||
Banco PostgreSQL externo hospedado no CloudClusters, utilizado pelo projeto GoHorseJobs.
|
||||
|
||||
## Informacoes do Servidor
|
||||
|
||||
| Campo | Valor |
|
||||
|-------|-------|
|
||||
| Host | postgresql-207755-0.cloudclusters.net |
|
||||
| Porta | 10078 |
|
||||
| Database | gohorsejobs |
|
||||
| Usuario | gohorse |
|
||||
| Senha | `wwc9dD04WAE44zX` |
|
||||
| SSL | Desabilitado |
|
||||
| Versao | PostgreSQL 16.0 |
|
||||
|
||||
## Connection String
|
||||
|
||||
```
|
||||
postgres://gohorse:wwc9dD04WAE44zX@postgresql-207755-0.cloudclusters.net:10078/gohorsejobs?sslmode=disable
|
||||
```
|
||||
|
||||
## Testar Conexao
|
||||
|
||||
```bash
|
||||
# Via VPS (echo)
|
||||
ssh echo "psql 'postgres://gohorse:wwc9dD04WAE44zX@postgresql-207755-0.cloudclusters.net:10078/gohorsejobs?sslmode=disable' -c 'SELECT version();'"
|
||||
|
||||
# Via psql local (se disponivel)
|
||||
psql "postgres://gohorse:wwc9dD04WAE44zX@postgresql-207755-0.cloudclusters.net:10078/gohorsejobs?sslmode=disable" -c "SELECT version();"
|
||||
```
|
||||
|
||||
## Projetos que utilizam este servidor
|
||||
|
||||
- [gohorsejobs](../../gohorsejobs/) - Plataforma de empregos
|
||||
|
|
@ -81,6 +81,7 @@ oci os object put \
|
|||
- **Arquivo**: `~/.ssh/cloudflare-token`
|
||||
- **Email**: yamamoto@rede5.com.br
|
||||
- **Zone ID (gohorsejobs.com)**: `5e7e9286849525abf7f30b451b7964ac`
|
||||
- **Zone ID (q1food.com)**: `70cdac5cc9787719d548ac6d74c98896`
|
||||
|
||||
### Coolify (Redbull)
|
||||
- **Arquivo**: `~/.ssh/coolify-redbull-token`
|
||||
|
|
@ -227,3 +228,44 @@ curl -s -H "Authorization: Bearer $(cat ~/.ssh/coolify-redbull-token)" "https://
|
|||
curl -s -H "Authorization: Bearer $(cat ~/.ssh/coolify-redbull-token)" "https://redbull.rede5.com.br/api/v1/deploy?uuid=s4kskw08400wcw8g40ossggo" # Backoffice
|
||||
curl -s -H "Authorization: Bearer $(cat ~/.ssh/coolify-redbull-token)" "https://redbull.rede5.com.br/api/v1/deploy?uuid=ko0kkw4kw8g80scksg8sk0wc" # Seeder
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Q1Food (Coolify - Redbull)
|
||||
|
||||
### URLs
|
||||
- Frontend: https://dev.q1food.com
|
||||
- Backend: https://api-dev.q1food.com
|
||||
|
||||
### DNS Cloudflare (Zone ID: 70cdac5cc9787719d548ac6d74c98896)
|
||||
| Record | Tipo | IP |
|
||||
|--------|------|-----|
|
||||
| q1food.com | A | 185.194.141.70 |
|
||||
| dev.q1food.com | A | 185.194.141.70 |
|
||||
| api-dev.q1food.com | A | 185.194.141.70 |
|
||||
|
||||
### UUIDs Coolify
|
||||
|
||||
| Serviço | UUID |
|
||||
|---------|------|
|
||||
| Backend | eosgwscc4g044c884k0ws4gc |
|
||||
| Frontend | g8w440g0w0oowo8skss440wk |
|
||||
|
||||
### Webhooks GitHub
|
||||
|
||||
| Serviço | Webhook Secret |
|
||||
|---------|----------------|
|
||||
| Backend | d66bac276faa04631124559d77199d0e |
|
||||
| Frontend | c512dc54933829d1cde381e2c9bf394a |
|
||||
|
||||
### Deploy
|
||||
|
||||
```bash
|
||||
# Deploy backend
|
||||
curl -s -H "Authorization: Bearer $(cat ~/.ssh/coolify-redbull-token)" "http://185.194.141.70:8000/api/v1/deploy?uuid=eosgwscc4g044c884k0ws4gc"
|
||||
|
||||
# Deploy frontend
|
||||
curl -s -H "Authorization: Bearer $(cat ~/.ssh/coolify-redbull-token)" "http://185.194.141.70:8000/api/v1/deploy?uuid=g8w440g0w0oowo8skss440wk"
|
||||
```
|
||||
|
||||
**Deploy automático:** Push na branch `dev` dispara webhook do GitHub → Coolify
|
||||
|
|
|
|||
2
mcp/.gitignore
vendored
Normal file
2
mcp/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
__pycache__/
|
||||
*.pyc
|
||||
45
mcp/README.md
Normal file
45
mcp/README.md
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
# Infracloud MCP
|
||||
|
||||
MCP server for the actual `infracloud` repository layout.
|
||||
|
||||
## Scope
|
||||
|
||||
- Reads `vps/*/services_inventory.md` and `k3s/services_inventory.md`
|
||||
- Lists and reads `containers/*.container` and `containers/*.service`
|
||||
- Lists scripts in `scripts/auto-organized`
|
||||
- Executes only scripts classified as read-only diagnostics
|
||||
- Provides repo grep and safe document reads
|
||||
- Supports optional Postgres-backed notes and read-only SQL diagnostics
|
||||
|
||||
## Install
|
||||
|
||||
```powershell
|
||||
pip install -r C:\dev\infracloud\mcp\requirements.txt
|
||||
```
|
||||
|
||||
## Run
|
||||
|
||||
```powershell
|
||||
python C:\dev\infracloud\mcp\server.py
|
||||
```
|
||||
|
||||
## Postgres
|
||||
|
||||
Set `INFRA_MCP_POSTGRES_DSN` if you want the server to use Postgres for notes and SQL diagnostics.
|
||||
|
||||
Example:
|
||||
|
||||
```powershell
|
||||
$env:INFRA_MCP_POSTGRES_DSN="postgresql://user:password@127.0.0.1:5432/infracloud_mcp"
|
||||
python C:\dev\infracloud\mcp\server.py
|
||||
```
|
||||
|
||||
## Claude Desktop
|
||||
|
||||
Use `claude_desktop_config.infracloud.json` as a base and merge it into your Claude Desktop MCP config.
|
||||
|
||||
## Notes
|
||||
|
||||
- This repo currently uses `scripts/auto-organized`, not `dev-scripts`.
|
||||
- This repo currently does not have `docs/openproject`.
|
||||
- `AGENT.md` includes secrets in plaintext. The MCP server does not expose that file.
|
||||
7
mcp/bootstrap.sql
Normal file
7
mcp/bootstrap.sql
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
CREATE TABLE IF NOT EXISTS infra_mcp_notes (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
scope TEXT NOT NULL,
|
||||
title TEXT NOT NULL,
|
||||
body TEXT NOT NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
14
mcp/claude_desktop_config.infracloud.json
Normal file
14
mcp/claude_desktop_config.infracloud.json
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"mcpServers": {
|
||||
"infracloud-sustentacao": {
|
||||
"command": "python",
|
||||
"args": [
|
||||
"C:\\dev\\infracloud\\mcp\\server.py"
|
||||
],
|
||||
"cwd": "C:\\dev\\infracloud",
|
||||
"env": {
|
||||
"INFRA_MCP_POSTGRES_DSN": "postgresql://user:password@127.0.0.1:5432/infracloud_mcp"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2
mcp/requirements.txt
Normal file
2
mcp/requirements.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
mcp>=1.6.0
|
||||
psycopg[binary]>=3.2.0
|
||||
536
mcp/server.py
Normal file
536
mcp/server.py
Normal file
|
|
@ -0,0 +1,536 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from mcp.server.fastmcp import FastMCP
|
||||
import psycopg
|
||||
from psycopg.rows import dict_row
|
||||
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[1]
|
||||
SCRIPTS_ROOT = REPO_ROOT / "scripts" / "auto-organized"
|
||||
VPS_ROOT = REPO_ROOT / "vps"
|
||||
CONTAINERS_ROOT = REPO_ROOT / "containers"
|
||||
DATABASES_ROOT = REPO_ROOT / "databases"
|
||||
K3S_ROOT = REPO_ROOT / "k3s"
|
||||
POSTGRES_DSN_ENV = "INFRA_MCP_POSTGRES_DSN"
|
||||
DOC_ALLOWLIST = (
|
||||
REPO_ROOT / "README.md",
|
||||
VPS_ROOT,
|
||||
CONTAINERS_ROOT,
|
||||
DATABASES_ROOT,
|
||||
K3S_ROOT,
|
||||
)
|
||||
|
||||
READ_ONLY_SCRIPT_PREFIXES = (
|
||||
"check_",
|
||||
"fetch_",
|
||||
"get_",
|
||||
"inspect_",
|
||||
"verify_",
|
||||
"final_status",
|
||||
"watch_",
|
||||
)
|
||||
MUTATING_SCRIPT_PREFIXES = (
|
||||
"approve_",
|
||||
"complete_",
|
||||
"fix_",
|
||||
"merge_",
|
||||
"retrigger_",
|
||||
"revert_",
|
||||
)
|
||||
|
||||
mcp = FastMCP(
|
||||
"infracloud-sustentacao",
|
||||
instructions=(
|
||||
"Use the real infracloud repository as the source of truth. "
|
||||
"Prefer inventory markdown, container unit files, and existing scripts. "
|
||||
"Do not assume paths like dev-scripts or docs/openproject if they do not exist. "
|
||||
"If Postgres is configured, prefer the MCP Postgres helpers for server-side persistence and diagnostics."
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ScriptInfo:
|
||||
path: Path
|
||||
relative_path: str
|
||||
is_read_only: bool
|
||||
kind: str
|
||||
|
||||
|
||||
def _postgres_dsn() -> str | None:
|
||||
value = os.getenv(POSTGRES_DSN_ENV, "").strip()
|
||||
return value or None
|
||||
|
||||
|
||||
def _postgres_enabled() -> bool:
|
||||
return _postgres_dsn() is not None
|
||||
|
||||
|
||||
def _get_pg_connection():
|
||||
dsn = _postgres_dsn()
|
||||
if not dsn:
|
||||
raise ValueError(f"{POSTGRES_DSN_ENV} is not configured")
|
||||
return psycopg.connect(dsn, row_factory=dict_row)
|
||||
|
||||
|
||||
def _ensure_mcp_tables() -> None:
|
||||
if not _postgres_enabled():
|
||||
return
|
||||
|
||||
with _get_pg_connection() as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS infra_mcp_notes (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
scope TEXT NOT NULL,
|
||||
title TEXT NOT NULL,
|
||||
body TEXT NOT NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
)
|
||||
"""
|
||||
)
|
||||
conn.commit()
|
||||
|
||||
|
||||
def _ensure_in_repo(path: Path) -> Path:
|
||||
resolved = path.resolve()
|
||||
if REPO_ROOT not in resolved.parents and resolved != REPO_ROOT:
|
||||
raise ValueError(f"path escapes repository root: {path}")
|
||||
return resolved
|
||||
|
||||
|
||||
def _script_kind(name: str) -> str:
|
||||
lower = name.lower()
|
||||
if lower.endswith(".ps1"):
|
||||
return "powershell"
|
||||
if lower.endswith(".sh"):
|
||||
return "shell"
|
||||
return "other"
|
||||
|
||||
|
||||
def _is_read_only_script(name: str) -> bool:
|
||||
lower = name.lower()
|
||||
if lower.endswith((".json", ".yaml", ".yml", ".txt", ".pem")):
|
||||
return False
|
||||
if lower.startswith(MUTATING_SCRIPT_PREFIXES):
|
||||
return False
|
||||
return lower.startswith(READ_ONLY_SCRIPT_PREFIXES)
|
||||
|
||||
|
||||
def _list_scripts() -> list[ScriptInfo]:
|
||||
if not SCRIPTS_ROOT.exists():
|
||||
return []
|
||||
|
||||
results: list[ScriptInfo] = []
|
||||
for path in sorted(SCRIPTS_ROOT.rglob("*")):
|
||||
if not path.is_file():
|
||||
continue
|
||||
relative = path.relative_to(REPO_ROOT).as_posix()
|
||||
results.append(
|
||||
ScriptInfo(
|
||||
path=path,
|
||||
relative_path=relative,
|
||||
is_read_only=_is_read_only_script(path.name),
|
||||
kind=_script_kind(path.name),
|
||||
)
|
||||
)
|
||||
return results
|
||||
|
||||
|
||||
def _resolve_script(script_name: str) -> ScriptInfo:
|
||||
script_name = script_name.replace("\\", "/").strip()
|
||||
candidates = _list_scripts()
|
||||
|
||||
exact = [item for item in candidates if item.relative_path == script_name or item.path.name == script_name]
|
||||
if len(exact) == 1:
|
||||
return exact[0]
|
||||
if len(exact) > 1:
|
||||
raise ValueError(f"multiple scripts matched '{script_name}', use a repo-relative path")
|
||||
|
||||
fuzzy = [item for item in candidates if script_name.lower() in item.relative_path.lower()]
|
||||
if len(fuzzy) == 1:
|
||||
return fuzzy[0]
|
||||
if len(fuzzy) > 1:
|
||||
names = ", ".join(item.relative_path for item in fuzzy[:10])
|
||||
raise ValueError(f"multiple scripts matched '{script_name}': {names}")
|
||||
|
||||
raise ValueError(f"script not found: {script_name}")
|
||||
|
||||
|
||||
def _read_text(path: Path, max_chars: int = 20000) -> str:
|
||||
resolved = _ensure_in_repo(path)
|
||||
text = resolved.read_text(encoding="utf-8", errors="replace")
|
||||
if len(text) > max_chars:
|
||||
return text[:max_chars] + "\n... [truncated]"
|
||||
return text
|
||||
|
||||
|
||||
def _parse_markdown_table(lines: list[str], start_index: int) -> tuple[list[dict[str, str]], int]:
|
||||
header_line = lines[start_index].strip()
|
||||
separator_index = start_index + 1
|
||||
if separator_index >= len(lines):
|
||||
return [], start_index + 1
|
||||
|
||||
separator_line = lines[separator_index].strip()
|
||||
if "|" not in header_line or "|" not in separator_line:
|
||||
return [], start_index + 1
|
||||
|
||||
headers = [part.strip(" `") for part in header_line.strip("|").split("|")]
|
||||
rows: list[dict[str, str]] = []
|
||||
index = start_index + 2
|
||||
while index < len(lines):
|
||||
line = lines[index].rstrip()
|
||||
if "|" not in line or not line.strip().startswith("|"):
|
||||
break
|
||||
values = [part.strip() for part in line.strip().strip("|").split("|")]
|
||||
if len(values) == len(headers):
|
||||
rows.append(dict(zip(headers, values)))
|
||||
index += 1
|
||||
|
||||
return rows, index
|
||||
|
||||
|
||||
def _parse_inventory_file(path: Path) -> dict[str, Any]:
|
||||
lines = _read_text(path, max_chars=120000).splitlines()
|
||||
parsed: dict[str, Any] = {"file": path.relative_to(REPO_ROOT).as_posix(), "sections": {}}
|
||||
current_section = "root"
|
||||
parsed["sections"][current_section] = {"tables": [], "paragraphs": []}
|
||||
|
||||
index = 0
|
||||
while index < len(lines):
|
||||
line = lines[index].rstrip()
|
||||
if line.startswith("#"):
|
||||
current_section = line.lstrip("#").strip()
|
||||
parsed["sections"].setdefault(current_section, {"tables": [], "paragraphs": []})
|
||||
index += 1
|
||||
continue
|
||||
|
||||
if line.strip().startswith("|"):
|
||||
rows, next_index = _parse_markdown_table(lines, index)
|
||||
if rows:
|
||||
parsed["sections"][current_section]["tables"].append(rows)
|
||||
index = next_index
|
||||
continue
|
||||
|
||||
if line.strip():
|
||||
parsed["sections"][current_section]["paragraphs"].append(line.strip())
|
||||
index += 1
|
||||
|
||||
return parsed
|
||||
|
||||
|
||||
def _iter_inventory_files() -> list[Path]:
|
||||
return sorted(VPS_ROOT.rglob("services_inventory.md")) + sorted(K3S_ROOT.rglob("services_inventory.md"))
|
||||
|
||||
|
||||
def _match_service(query: str, row: dict[str, str]) -> bool:
|
||||
haystack = " ".join(str(value) for value in row.values()).lower()
|
||||
return query.lower() in haystack
|
||||
|
||||
|
||||
def _safe_doc_path(relative_path: str) -> Path:
|
||||
relative = Path(relative_path)
|
||||
candidate = _ensure_in_repo(REPO_ROOT / relative)
|
||||
for allowed in DOC_ALLOWLIST:
|
||||
allowed_resolved = allowed.resolve()
|
||||
if candidate == allowed_resolved or allowed_resolved in candidate.parents:
|
||||
return candidate
|
||||
raise ValueError(f"path not allowed: {relative_path}")
|
||||
|
||||
|
||||
def _ensure_read_only_sql(sql: str) -> str:
|
||||
normalized = sql.strip().lstrip("(").strip().lower()
|
||||
if not normalized.startswith("select"):
|
||||
raise ValueError("only SELECT queries are allowed")
|
||||
forbidden = ("insert ", "update ", "delete ", "drop ", "alter ", "truncate ", "create ", "grant ", "revoke ")
|
||||
if any(token in normalized for token in forbidden):
|
||||
raise ValueError("query contains non-read-only statements")
|
||||
return sql
|
||||
|
||||
|
||||
@mcp.tool(
|
||||
description="List scripts available in scripts/auto-organized, including whether each one is safe for read-only execution.",
|
||||
)
|
||||
def list_repo_scripts(name_filter: str | None = None) -> list[dict[str, Any]]:
|
||||
scripts = _list_scripts()
|
||||
if name_filter:
|
||||
scripts = [item for item in scripts if name_filter.lower() in item.relative_path.lower()]
|
||||
|
||||
return [
|
||||
{
|
||||
"name": item.path.name,
|
||||
"relative_path": item.relative_path,
|
||||
"kind": item.kind,
|
||||
"read_only": item.is_read_only,
|
||||
}
|
||||
for item in scripts
|
||||
]
|
||||
|
||||
|
||||
@mcp.tool(
|
||||
description="Run an existing repo script from scripts/auto-organized. Only read-only diagnostic scripts are executable.",
|
||||
)
|
||||
def run_repo_script(script_name: str, args: list[str] | None = None, timeout_seconds: int = 60) -> dict[str, Any]:
|
||||
script = _resolve_script(script_name)
|
||||
if not script.is_read_only:
|
||||
raise ValueError(
|
||||
f"script '{script.relative_path}' is not classified as read-only and cannot be executed by this tool"
|
||||
)
|
||||
|
||||
args = args or []
|
||||
if script.kind == "powershell":
|
||||
command = [
|
||||
"powershell",
|
||||
"-NoProfile",
|
||||
"-ExecutionPolicy",
|
||||
"Bypass",
|
||||
"-File",
|
||||
str(script.path),
|
||||
*args,
|
||||
]
|
||||
elif script.kind == "shell":
|
||||
command = ["bash", str(script.path), *args]
|
||||
else:
|
||||
raise ValueError(f"unsupported script type: {script.kind}")
|
||||
|
||||
completed = subprocess.run(
|
||||
command,
|
||||
cwd=REPO_ROOT,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=timeout_seconds,
|
||||
check=False,
|
||||
)
|
||||
return {
|
||||
"script": script.relative_path,
|
||||
"exit_code": completed.returncode,
|
||||
"stdout": completed.stdout[-12000:],
|
||||
"stderr": completed.stderr[-12000:],
|
||||
}
|
||||
|
||||
|
||||
@mcp.tool(
|
||||
description="Parse one services_inventory.md file into structured JSON. Server examples: redbull, vim, nc1, k3s.",
|
||||
)
|
||||
def read_services_inventory(server: str) -> dict[str, Any]:
|
||||
inventory_files = {path.parent.name.lower(): path for path in _iter_inventory_files()}
|
||||
server_key = server.lower().strip()
|
||||
if server_key not in inventory_files:
|
||||
raise ValueError(f"inventory not found for '{server}'. Available: {', '.join(sorted(inventory_files))}")
|
||||
return _parse_inventory_file(inventory_files[server_key])
|
||||
|
||||
|
||||
@mcp.tool(
|
||||
description="Search all inventory files for an app, UUID, domain, server, or other service text.",
|
||||
)
|
||||
def find_service(query: str) -> list[dict[str, Any]]:
|
||||
matches: list[dict[str, Any]] = []
|
||||
for inventory_path in _iter_inventory_files():
|
||||
parsed = _parse_inventory_file(inventory_path)
|
||||
for section_name, section in parsed["sections"].items():
|
||||
for table in section["tables"]:
|
||||
for row in table:
|
||||
if _match_service(query, row):
|
||||
matches.append(
|
||||
{
|
||||
"inventory": parsed["file"],
|
||||
"section": section_name,
|
||||
"row": row,
|
||||
}
|
||||
)
|
||||
return matches
|
||||
|
||||
|
||||
@mcp.tool(
|
||||
description="List Podman/Systemd unit files under containers/ and optionally filter by app name.",
|
||||
)
|
||||
def list_container_units(name_filter: str | None = None) -> list[dict[str, str]]:
|
||||
results: list[dict[str, str]] = []
|
||||
for path in sorted(CONTAINERS_ROOT.iterdir()):
|
||||
if not path.is_file():
|
||||
continue
|
||||
if path.suffix not in {".container", ".service"}:
|
||||
continue
|
||||
relative = path.relative_to(REPO_ROOT).as_posix()
|
||||
if name_filter and name_filter.lower() not in relative.lower():
|
||||
continue
|
||||
results.append({"name": path.name, "relative_path": relative, "kind": path.suffix.lstrip(".")})
|
||||
return results
|
||||
|
||||
|
||||
@mcp.tool(
|
||||
description="Read a container unit file from containers/ for Podman/Systemd runtime analysis.",
|
||||
)
|
||||
def read_container_unit(name: str) -> dict[str, str]:
|
||||
candidates = [
|
||||
path
|
||||
for path in CONTAINERS_ROOT.iterdir()
|
||||
if path.is_file() and path.suffix in {".container", ".service"} and (path.name == name or name.lower() in path.name.lower())
|
||||
]
|
||||
if not candidates:
|
||||
raise ValueError(f"container unit not found: {name}")
|
||||
if len(candidates) > 1:
|
||||
names = ", ".join(path.name for path in candidates)
|
||||
raise ValueError(f"multiple container units matched '{name}': {names}")
|
||||
|
||||
path = candidates[0]
|
||||
return {
|
||||
"relative_path": path.relative_to(REPO_ROOT).as_posix(),
|
||||
"content": _read_text(path, max_chars=16000),
|
||||
}
|
||||
|
||||
|
||||
@mcp.tool(
|
||||
description="Read a repo document from README, vps, databases, k3s, or containers paths.",
|
||||
)
|
||||
def read_repo_document(relative_path: str, max_chars: int = 12000) -> dict[str, str]:
|
||||
path = _safe_doc_path(relative_path)
|
||||
return {
|
||||
"relative_path": path.relative_to(REPO_ROOT).as_posix(),
|
||||
"content": _read_text(path, max_chars=max_chars),
|
||||
}
|
||||
|
||||
|
||||
@mcp.tool(
|
||||
description="Search the repo for infrastructure terms such as app names, domains, env keys, or container names.",
|
||||
)
|
||||
def grep_repo(query: str, glob: str | None = None) -> dict[str, Any]:
|
||||
command = ["rg", "-n", query, str(REPO_ROOT)]
|
||||
if glob:
|
||||
command.extend(["-g", glob])
|
||||
|
||||
completed = subprocess.run(
|
||||
command,
|
||||
cwd=REPO_ROOT,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=30,
|
||||
check=False,
|
||||
)
|
||||
results = completed.stdout.splitlines()
|
||||
return {
|
||||
"exit_code": completed.returncode,
|
||||
"matches": results[:200],
|
||||
"truncated": len(results) > 200,
|
||||
"stderr": completed.stderr[-4000:],
|
||||
}
|
||||
|
||||
|
||||
@mcp.tool(
|
||||
description="Return a compact summary of the actual infracloud repo layout so agents do not assume missing folders like dev-scripts or docs/openproject.",
|
||||
)
|
||||
def repo_layout_summary() -> dict[str, Any]:
|
||||
return {
|
||||
"repo_root": str(REPO_ROOT),
|
||||
"present_top_level_dirs": sorted(path.name for path in REPO_ROOT.iterdir() if path.is_dir()),
|
||||
"scripts_root": SCRIPTS_ROOT.relative_to(REPO_ROOT).as_posix() if SCRIPTS_ROOT.exists() else None,
|
||||
"inventory_files": [path.relative_to(REPO_ROOT).as_posix() for path in _iter_inventory_files()],
|
||||
"container_units": [path.name for path in CONTAINERS_ROOT.iterdir() if path.is_file() and path.suffix in {".container", ".service"}],
|
||||
"notes": [
|
||||
"The repo uses scripts/auto-organized instead of dev-scripts.",
|
||||
"The repo does not currently include docs/openproject.",
|
||||
"AGENT.md contains secrets and should not be used as a runtime configuration source.",
|
||||
f"Optional Postgres integration is enabled through {POSTGRES_DSN_ENV}.",
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@mcp.tool(
|
||||
description="Return the configured Postgres status for the MCP server and basic connectivity details.",
|
||||
)
|
||||
def postgres_healthcheck() -> dict[str, Any]:
|
||||
dsn = _postgres_dsn()
|
||||
if not dsn:
|
||||
return {"configured": False, "env_var": POSTGRES_DSN_ENV}
|
||||
|
||||
with _get_pg_connection() as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute("SELECT current_database() AS database, current_user AS user, version() AS version")
|
||||
row = cur.fetchone()
|
||||
return {
|
||||
"configured": True,
|
||||
"env_var": POSTGRES_DSN_ENV,
|
||||
"database": row["database"],
|
||||
"user": row["user"],
|
||||
"version": row["version"],
|
||||
}
|
||||
|
||||
|
||||
@mcp.tool(
|
||||
description="Execute a read-only SELECT query against the MCP Postgres database.",
|
||||
)
|
||||
def postgres_query(sql: str, limit: int = 100) -> dict[str, Any]:
|
||||
if limit < 1 or limit > 500:
|
||||
raise ValueError("limit must be between 1 and 500")
|
||||
|
||||
safe_sql = _ensure_read_only_sql(sql)
|
||||
wrapped = f"SELECT * FROM ({safe_sql.rstrip().rstrip(';')}) AS q LIMIT {limit}"
|
||||
|
||||
with _get_pg_connection() as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(wrapped)
|
||||
rows = cur.fetchall()
|
||||
return {
|
||||
"row_count": len(rows),
|
||||
"rows": rows,
|
||||
}
|
||||
|
||||
|
||||
@mcp.tool(
|
||||
description="Store a short operational note in the MCP Postgres database for future support sessions.",
|
||||
)
|
||||
def add_operational_note(scope: str, title: str, body: str) -> dict[str, Any]:
|
||||
if not scope.strip() or not title.strip() or not body.strip():
|
||||
raise ValueError("scope, title, and body are required")
|
||||
|
||||
_ensure_mcp_tables()
|
||||
with _get_pg_connection() as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"""
|
||||
INSERT INTO infra_mcp_notes (scope, title, body)
|
||||
VALUES (%s, %s, %s)
|
||||
RETURNING id, scope, title, body, created_at
|
||||
""",
|
||||
(scope.strip(), title.strip(), body.strip()),
|
||||
)
|
||||
row = cur.fetchone()
|
||||
conn.commit()
|
||||
return row
|
||||
|
||||
|
||||
@mcp.tool(
|
||||
description="List recent operational notes stored in the MCP Postgres database.",
|
||||
)
|
||||
def list_operational_notes(scope: str | None = None, limit: int = 20) -> list[dict[str, Any]]:
|
||||
if limit < 1 or limit > 200:
|
||||
raise ValueError("limit must be between 1 and 200")
|
||||
|
||||
_ensure_mcp_tables()
|
||||
query = """
|
||||
SELECT id, scope, title, body, created_at
|
||||
FROM infra_mcp_notes
|
||||
"""
|
||||
params: list[Any] = []
|
||||
if scope and scope.strip():
|
||||
query += " WHERE scope = %s"
|
||||
params.append(scope.strip())
|
||||
query += " ORDER BY created_at DESC LIMIT %s"
|
||||
params.append(limit)
|
||||
|
||||
with _get_pg_connection() as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(query, params)
|
||||
return cur.fetchall()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
_ensure_mcp_tables()
|
||||
mcp.run()
|
||||
|
|
@ -1,121 +1,37 @@
|
|||
# Echo - Servidor de Producao
|
||||
# VPS Echo
|
||||
|
||||
Servidor de producao utilizando a plataforma Dokku para deploy de aplicacoes.
|
||||
Servidor VPS gerenciado pela Rede5 hospedado na Civo.
|
||||
|
||||
## Visao Geral
|
||||
## Informacoes de Conexao
|
||||
|
||||
O servidor Echo e uma infraestrutura de producao que hospeda multiplas aplicacoes web, seguindo uma arquitetura baseada em containers. A plataforma Dokku serve como camada de gerenciamento de aplicacoes, similar a um Heroku self-hosted, permitindo deploys rapidos atraves de Git pushes. O Nginx atua como proxy reverso, roteando o trafego baseado em dominios para as aplicacoes corretas.
|
||||
- **Nome**: echo
|
||||
- **IP Publico**: 152.53.120.181
|
||||
- **Usuario**: root
|
||||
- **Chave SSH**: `~/.ssh/civo`
|
||||
|
||||
## Especificacoes do Servidor
|
||||
|
||||
| Recurso | Especificacao |
|
||||
|---------|---------------|
|
||||
| **Hostname** | v2202501247812309542 |
|
||||
| **IP Publico** | 152.53.120.181 |
|
||||
| **OS** | Ubuntu 24.04.3 LTS (Noble Numbat) |
|
||||
| **Kernel** | 6.8.0-90-generic |
|
||||
| **CPU** | AMD EPYC (Virtual) |
|
||||
| **RAM** | 7.8 GB |
|
||||
| **Disco** | 251 GB (7.1 GB usado) |
|
||||
| **Uptime** | 19+ dias |
|
||||
| **Plataforma** | Dokku (PaaS self-hosted) |
|
||||
| **Container Runtime** | Docker |
|
||||
| **Proxy Reverso** | Nginx |
|
||||
|
||||
## Dominios
|
||||
|
||||
| Dominio | Uso |
|
||||
|---------|-----|
|
||||
| echo.rede5.com.br | Dominio global |
|
||||
| photum.rede5.com.br | Photum API |
|
||||
| api-hml.q1food.com | Food Backend |
|
||||
|
||||
## Projetos Hospedados
|
||||
|
||||
| Aplicacao | Porta | Dominio | Status |
|
||||
|-----------|:-----:|---------|:------:|
|
||||
| **photum** | 5000 | photum.rede5.com.br | Running |
|
||||
| **food-backend** | 8000 | api-hml.q1food.com | Running |
|
||||
| **q1agenda-backend** | 8000 | 152.53.120.181 | Running |
|
||||
|
||||
## Bancos de Dados
|
||||
|
||||
| Servico | Versao | Container | Porta |
|
||||
|---------|:------:|-----------|:-----:|
|
||||
| **photum-db** | PostgreSQL 18.1 | dokku.postgres.photum-db | 5432 |
|
||||
| **q1agenda-db** | PostgreSQL 18.1 | dokku.postgres.q1agenda-db | 5432 |
|
||||
|
||||
## Acesso SSH
|
||||
## Como Conectar
|
||||
|
||||
```bash
|
||||
# Conectar via SSH
|
||||
ssh echo
|
||||
|
||||
# Ou diretamente
|
||||
ssh -i C:\Users\Administrator\.ssh\civo root@152.53.120.181
|
||||
```
|
||||
|
||||
## Comandos Dokku
|
||||
## Estado Atual Observado
|
||||
|
||||
```bash
|
||||
# Listar aplicacoes
|
||||
dokku apps:list
|
||||
- Runtime principal: Docker puro
|
||||
- Repositorios presentes em `/root`:
|
||||
- `/root/gohorsejobs`
|
||||
- `/root/infracloud`
|
||||
- Containers Postgres ativos observados:
|
||||
- `ghj-db-dev`
|
||||
- `sim-db-dev`
|
||||
- `saveinmed-postgres`
|
||||
|
||||
# Listar bancos PostgreSQL
|
||||
dokku postgres:list
|
||||
## Uso no Contexto do Infracloud MCP
|
||||
|
||||
# Ver logs de uma app
|
||||
dokku logs photum
|
||||
- O clone do repo fica em `/root/infracloud`
|
||||
- O MCP pode usar um banco Postgres da propria VPS via variavel `INFRA_MCP_POSTGRES_DSN`
|
||||
- Preferir banco dedicado `infracloud_mcp` em vez de reutilizar schemas de aplicacao
|
||||
|
||||
# Deploy de uma app
|
||||
git remote add dokku dokku@echo.rede5.com.br:photum
|
||||
git push dokku main:master
|
||||
## Servicos e Finalidade
|
||||
|
||||
# Ver config de uma app
|
||||
dokku config:show photum
|
||||
|
||||
# Adicionar variavel de ambiente
|
||||
dokku config:set photum KEY=VALUE
|
||||
|
||||
# Restart app
|
||||
dokku ps:restart photum
|
||||
```
|
||||
|
||||
## Detalhes das Aplicacoes
|
||||
|
||||
### Photum
|
||||
- **Dominio**: photum.rede5.com.br
|
||||
- **Porta**: 5000
|
||||
- **Banco**: photum-db (PostgreSQL 18.1)
|
||||
- **Storage**: Civo Object Storage (ver ~/.ssh/civo-object-storage)
|
||||
- **Stack**: Go
|
||||
|
||||
**Pastas do bucket rede5:**
|
||||
- `vault/ssh/` - Backup credenciais SSH
|
||||
- `ghorsejobs-dev/` - Resumes GoHorseJobs
|
||||
- `photum-dev/` - Imagens Photum
|
||||
- `obramarket-dev/` - Uploads ObraMarket
|
||||
- `rodiziosdaqui-dev/` - Uploads Rodizios
|
||||
- `q1-dev/`, `q1-hml/`, `q1/` - Uploads Q1
|
||||
- `virtual-fashion-dev/` - Uploads Virtual Fashion
|
||||
|
||||
### Food Backend
|
||||
- **Dominio**: api-hml.q1food.com
|
||||
- **Porta**: 8000
|
||||
- **Banco**: Supabase (externo)
|
||||
- **Stack**: Python/FastAPI
|
||||
|
||||
### Q1 Agenda Backend
|
||||
- **Dominio**: 152.53.120.181
|
||||
- **Porta**: 8000
|
||||
- **Banco**: q1agenda-db (PostgreSQL 18.1)
|
||||
- **Stack**: Python/FastAPI
|
||||
- **Integracao**: Appwrite
|
||||
|
||||
## Comparacao com Outros Servidores
|
||||
|
||||
| Servidor | Uso | Plataforma |
|
||||
|----------|-----|------------|
|
||||
| **Redbull** | Desenvolvimento (DEV) | Coolify |
|
||||
| **Echo** | Producao (PROD) | Dokku |
|
||||
| **Vim** | Producao (PROD) | Dokku |
|
||||
Workloads de desenvolvimento e sustentacao operando fora de Dokku/Coolify, com compose e containers dedicados.
|
||||
|
|
|
|||
|
|
@ -10,8 +10,11 @@ O servidor Redbull é uma infraestrutura de desenvolvimento que hospeda múltipl
|
|||
|
||||
| Recurso | Especificação |
|
||||
|---------|---------------|
|
||||
| **Hostname** | redbull.rede5.com.br |
|
||||
| **Hostname** | redbull |
|
||||
| **IP Público** | 185.194.141.70 |
|
||||
| **Domínio** | redbull.rede5.com.br |
|
||||
| **Coolify Dashboard** | https://redbull.rede5.com.br |
|
||||
| **API** | https://redbull.rede5.com.br/api/v1 |
|
||||
| **Plataforma** | VPS Ubuntu/Debian |
|
||||
| **Orquestrador** | Coolify v4 (PaaS self-hosted) |
|
||||
| **Container Runtime** | Docker |
|
||||
|
|
@ -20,18 +23,18 @@ O servidor Redbull é uma infraestrutura de desenvolvimento que hospeda múltipl
|
|||
|
||||
## Projetos Hospedados
|
||||
|
||||
### GoHorse Jobs (LOCAL)
|
||||
| Serviço | UUID | Porta | Domínio | CI/CD | Status |
|
||||
|---------|------|:-----:|---------|-------|:------:|
|
||||
| Backend | `iw4sow8s0kkg4cccsk08gsoo` | 8521 | test2.q1agenda.com.br | ✅ GitHub | ✅ |
|
||||
| Frontend | `ao8g40scws0w4cgo8coc8o40` | 3000 | local.gohorsejobs.com | ✅ GitHub | ✅ |
|
||||
| Backoffice | `hg48wkw4wggwsswcwc8sooo4` | 3001 | b-local.gohorsejobs.com | ✅ GitHub | ✅ |
|
||||
| Seeder | `q4w48gos8cgssso00o8w8gck` | 8080 | s-local.gohorsejobs.com | ✅ GitHub | ✅ Healthy |
|
||||
| Database | `bgws48os8wgwk08o48wg8k80` | 5432 | Internal | - | ✅ Healthy |
|
||||
### GoHorse Jobs (DEV)
|
||||
| Serviço | UUID | Porta | Domínio |
|
||||
|---------|------|:-----:|---------|
|
||||
| Backend | `iw4sow8s0kkg4cccsk08gsoo` | 8521 | coolify-dev.gohorsejobs.com |
|
||||
| Frontend | `ao8g40scws0w4cgo8coc8o40` | 3000 | local.gohorsejobs.com |
|
||||
| Backoffice | `hg48wkw4wggwsswcwc8sooo4` | 3001 | backoffice-dev.gohorsejobs.com |
|
||||
| Seeder | `q4w48gos8cgssso00o8w8gck` | 8080 | seeder-dev.gohorsejobs.com |
|
||||
| Database | `bgws48os8wgwk08o48wg8k80` | 5432 | Internal |
|
||||
|
||||
### Subdomínios Locais (Cloudflare)
|
||||
|
||||
指向 Coolify (redbull.rede5.com.br / 185.194.141.70):
|
||||
指向 Coolify (185.194.141.70):
|
||||
|
||||
| Subdomínio | Tipo | UUID App |
|
||||
|------------|------|----------|
|
||||
|
|
@ -43,45 +46,32 @@ O servidor Redbull é uma infraestrutura de desenvolvimento que hospeda múltipl
|
|||
> **Cloudflare Zone**: gohorsejobs.com (Zone ID: 5e7e9286849525abf7f30b451b7964ac)
|
||||
|
||||
### Rodizios Daqui (DEV)
|
||||
| Serviço | UUID | Porta | Domínio | CI/CD | Status |
|
||||
|---------|------|:-----:|---------|-------|:------:|
|
||||
| Backend | `ecso4woo4woo0ks84888k8ck` | 8080 | api.rodiziosdaqui.rede5.com.br | ✅ GitHub | ✅ |
|
||||
| Frontend | `l4g4cc884gc04kg8s480gs48` | 3000 | rodiziosdaqui.rede5.com.br | ✅ GitHub | ✅ |
|
||||
| Backoffice | `s4kskw08400wcw8g40ossggo` | 8082 | backoffice.rodiziosdaqui.rede5.com.br | ✅ GitHub | ✅ |
|
||||
| Seeder | `ko0kkw4kw8g80scksg8sk0wc` | 8081 | seeder.rodiziosdaqui.rede5.com.br | ✅ GitHub | ✅ Healthy |
|
||||
|
||||
### Q1 Agenda (DEV/HML)
|
||||
| Serviço | UUID | Domínio | CI/CD | Status |
|
||||
|---------|------|---------|-------|:------:|
|
||||
| backend-dev | `h8kkc0gw04sow8oo08ccg00s` | sem domínio | ❌ | ❌ Exited |
|
||||
| backend-hml | `bk0kcosgo0s8cogww8s4so0w` | sem domínio | ❌ | ❌ Exited |
|
||||
| frontend-dev | `wwgccg0o8g4ogowgowcw4gcg` | sem domínio | ❌ | ❌ Exited |
|
||||
| frontend-hml | `es0gg4gokssw8c88o4kg0c08` | sem domínio | ❌ | ❌ Exited |
|
||||
|
||||
### Q1 Food (DEV)
|
||||
| Serviço | UUID | Domínio | CI/CD | Status |
|
||||
|---------|------|---------|-------|:------:|
|
||||
| Backend | `eosgwscc4g044c884k0ws4gc` | api-dev.q1food.com | ✅ GitHub | ❌ Exited |
|
||||
| Frontend | `g8w440g0w0oowo8skss440wk` | dev.q1food.com | ✅ GitHub | ✅ Running |
|
||||
|
||||
### Sextando (DEV)
|
||||
| Serviço | UUID | Domínio | CI/CD | Status |
|
||||
|---------|------|---------|-------|:------:|
|
||||
| Backend | `h8c4sg0sg80c4o8kkcw4ogcg` | api-dev.sextando.com.br | ❌ | ❌ Exited |
|
||||
| Backoffice | `nsc0gw0og40g0c88soc0o0wc` | backoffice-dev.sextando.com.br | ❌ | ❌ Exited |
|
||||
| Frontend | `vggkcs880o8go0ws84wcggco` | dev.sextando.com.br | ❌ | ✅ Running |
|
||||
|
||||
### ObraMarket (DEV) — ⚠️ 4 duplicatas, todas paradas
|
||||
> Ver `services_inventory.md` para detalhe. Ação: limpar e manter apenas 1.
|
||||
| Serviço | UUID | Porta | Domínio |
|
||||
|---------|------|:-----:|---------|
|
||||
| Backend | `ecso4woo4woo0ks84888k8ck` | 8080 | api.rodiziosdaqui.rede5.com.br |
|
||||
| Frontend | `l4g4cc884gc04kg8s480gs48` | 3000 | rodiziosdaqui.rede5.com.br |
|
||||
| Backoffice | `s4kskw08400wcw8g40ossggo` | 8082 | backoffice.rodiziosdaqui.rede5.com.br |
|
||||
| Seeder | `ko0kkw4kw8g80scksg8sk0wc` | 8081 | seeder.rodiziosdaqui.rede5.com.br |
|
||||
|
||||
> **DNS Zone**: rede5.com.br (Zone ID: 7eb6587a2c867bb9743719a8fabcd455)
|
||||
|
||||
> **Banco de Dados**: PostgreSQL externo (Absam Cloud) - db-60604.dc-us-1.absamcloud.com:11985
|
||||
|
||||
### Q1Food (DEV)
|
||||
| Serviço | UUID | Porta | Domínio |
|
||||
|---------|------|:-----:|---------|
|
||||
| Backend | `eosgwscc4g044c884k0ws4gc` | 8000 | api-dev.q1food.com |
|
||||
| Frontend | `g8w440g0w0oowo8skss440wk` | 3000 | dev.q1food.com |
|
||||
|
||||
> **DNS Zone**: q1food.com (Zone ID: 70cdac5cc9787719d548ac6d74c98896)
|
||||
|
||||
> **Banco de Dados**: Supabase (externo)
|
||||
|
||||
## Documentação
|
||||
|
||||
- [**Resumo de Projetos**](./projetos-resumo.md): Status, URLs, CI/CD e webhooks
|
||||
- [Inventário de Serviços](./services_inventory.md): Tabela completa de apps, bancos, portas e domínios
|
||||
- [Guia de Deploy](./deployment_guide.md): Instruções passo a passo para deployment e manutenção
|
||||
- [API Coolify](./coolify-api.md): Endpoints e comandos da API
|
||||
|
||||
## Quick Start
|
||||
|
||||
|
|
@ -89,7 +79,7 @@ O servidor Redbull é uma infraestrutura de desenvolvimento que hospeda múltipl
|
|||
|
||||
```bash
|
||||
# Token de autenticação
|
||||
TOKEN="fzz2xL0UUwpeVB1mObEwxE9GO8sTV8z2OHiOojmdf0e428be"
|
||||
TOKEN="2|tjaxz6z6osQUz6whMvNMw23kcBqgToQAvMjSLos347164da9"
|
||||
URL="https://redbull.rede5.com.br/api/v1"
|
||||
|
||||
# Deploy de uma aplicação
|
||||
|
|
@ -135,15 +125,29 @@ curl -s -X DELETE -H "X-Auth-Email: $CF_AUTH_EMAIL" -H "X-Auth-Key: $CF_AUTH_KEY
|
|||
-d '{"purge_everything":true}'
|
||||
```
|
||||
|
||||
### CI/CD Automático via Webhook
|
||||
Os webhooks GitHub estão configurados para deploy automático:
|
||||
- Push na branch `dev` → Deploy automático no Coolify
|
||||
- URL do webhook: `https://redbull.rede5.com.br/api/v1/webhook/github?uuid=<APP_UUID>&secret=<SECRET>`
|
||||
### CI/CD Automático via Webhook do Coolify
|
||||
|
||||
O Coolify recebe webhooks do GitHub para deploy automático. Configure no repositório GitHub (Settings → Webhooks):
|
||||
|
||||
| App | Webhook URL | Secret |
|
||||
|-----|-------------|--------|
|
||||
| Backend | `https://redbull.rede5.com.br/api/v1/webhooks/deploy?uuid=iw4sow8s0kkg4cccsk08gsoo` | `oRTKAwXgHrIzIcXdVqa7BXPkzXVQAhwS` |
|
||||
| Frontend | `https://redbull.rede5.com.br/api/v1/webhooks/deploy?uuid=ao8g40scws0w4cgo8coc8o40` | `H3CfQuM9Jnpv9Tl37WKupEMlaaIWFlU5` |
|
||||
| Backoffice | `https://redbull.rede5.com.br/api/v1/webhooks/deploy?uuid=hg48wkw4wggwsswcwc8sooo4` | `wvREqj94RRX60113cYb2nMCZf0pmg662` |
|
||||
| Seeder | `https://redbull.rede5.com.br/api/v1/webhooks/deploy?uuid=q4w48gos8cgssso00o8w8gck` | `sa08PAj2RwyjW5VNmqKX0Ac9s7zIMyH2` |
|
||||
| q1food-backend | `http://185.194.141.70:8000/api/v1/webhooks/deploy?uuid=eosgwscc4g044c884k0ws4gc` | `d66bac276faa04631124559d77199d0e` |
|
||||
| q1food-frontend | `http://185.194.141.70:8000/api/v1/webhooks/deploy?uuid=g8w440g0w0oowo8skss440wk` | `c512dc54933829d1cde381e2c9bf394a` |
|
||||
|
||||
Configuração do webhook no GitHub:
|
||||
- Payload URL: URL do webhook acima
|
||||
- Content type: `application/json`
|
||||
- Secret: webhook secret da app
|
||||
- Events: `Push events` (branch `dev`)
|
||||
|
||||
## Acesso SSH
|
||||
|
||||
```bash
|
||||
# Conexão SSH (HostName aponta para 185.194.141.70 direto)
|
||||
# Conexão SSH
|
||||
ssh redbull
|
||||
|
||||
# Verificar containers
|
||||
|
|
@ -153,9 +157,6 @@ docker ps --format 'table {{.Names}}\t{{.Status}}'
|
|||
docker logs coolify -f
|
||||
```
|
||||
|
||||
> ⚠️ **Nota:** `redbull.rede5.com.br` está atrás do Cloudflare — porta 22 bloqueada.
|
||||
> O SSH config usa o IP `185.194.141.70` direto para contornar isso.
|
||||
|
||||
## Boas Práticas
|
||||
|
||||
1. **Variáveis de Ambiente**: Configure todas as variáveis antes do deploy
|
||||
|
|
|
|||
|
|
@ -5,177 +5,99 @@
|
|||
https://redbull.rede5.com.br/api/v1
|
||||
```
|
||||
|
||||
## Authorization
|
||||
|
||||
A API requer um token `Bearer` no header `Authorization`.
|
||||
|
||||
### Gerar Token
|
||||
1. Acesse `Keys & Tokens` / `API tokens` no painel Coolify
|
||||
2. Defina um nome para o token e clique em `Create New Token`
|
||||
3. Copie o token (so aparece uma vez)
|
||||
|
||||
### Token Atual
|
||||
```
|
||||
fzz2xL0UUwpeVB1mObEwxE9GO8sTV8z2OHiOojmdf0e428be
|
||||
```
|
||||
> Salvo em `~/.ssh/coolify-redbull-token`
|
||||
|
||||
### Permissoes
|
||||
- `read-only` (default): apenas leitura
|
||||
- `read:sensitive`: leitura + dados sensiveis
|
||||
- `view:sensitive`: visualizar dados sensiveis
|
||||
- `*`: acesso total
|
||||
|
||||
## Endpoints Principais
|
||||
|
||||
### Applications
|
||||
| Metodo | Endpoint | Descricao |
|
||||
|--------|----------|-----------|
|
||||
| GET | `/applications` | Listar aplicacoes |
|
||||
| GET | `/applications/{uuid}` | Obter aplicacao |
|
||||
| GET | `/applications/{uuid}/start` | Iniciar aplicacao |
|
||||
| GET | `/applications/{uuid}/stop` | Parar aplicacao |
|
||||
| GET | `/applications/{uuid}/restart` | Reiniciar aplicacao |
|
||||
| DELETE | `/applications/{uuid}` | Deletar aplicacao |
|
||||
| PATCH | `/applications/{uuid}` | Atualizar aplicacao |
|
||||
|
||||
### Databases
|
||||
| Metodo | Endpoint | Descricao |
|
||||
|--------|----------|-----------|
|
||||
| GET | `/databases` | Listar bancos |
|
||||
| GET | `/databases/{uuid}` | Obter banco |
|
||||
| POST | `/databases/postgresql` | Criar PostgreSQL |
|
||||
| POST | `/databases/mysql` | Criar MySQL |
|
||||
| POST | `/databases/mariadb` | Criar MariaDB |
|
||||
| POST | `/databases/mongodb` | Criar MongoDB |
|
||||
| POST | `/databases/redis` | Criar Redis |
|
||||
| GET | `/databases/{uuid}/start` | Iniciar banco |
|
||||
| GET | `/databases/{uuid}/stop` | Parar banco |
|
||||
| DELETE | `/databases/{uuid}` | Deletar banco |
|
||||
|
||||
### Deployments
|
||||
| Metodo | Endpoint | Descricao |
|
||||
|--------|----------|-----------|
|
||||
| GET | `/deployments` | Listar deployments |
|
||||
| GET | `/deploy?uuid={uuid}` | Deploy por UUID |
|
||||
| GET | `/deploy?tag={tag}` | Deploy por tag |
|
||||
|
||||
### Projects
|
||||
| Metodo | Endpoint | Descricao |
|
||||
|--------|----------|-----------|
|
||||
| GET | `/projects` | Listar projetos |
|
||||
| POST | `/projects` | Criar projeto |
|
||||
| GET | `/projects/{uuid}` | Obter projeto |
|
||||
| PATCH | `/projects/{uuid}` | Atualizar projeto |
|
||||
| DELETE | `/projects/{uuid}` | Deletar projeto |
|
||||
|
||||
### Servers
|
||||
| Metodo | Endpoint | Descricao |
|
||||
|--------|----------|-----------|
|
||||
| GET | `/servers` | Listar servidores |
|
||||
| GET | `/servers/{uuid}` | Obter servidor |
|
||||
| GET | `/servers/{uuid}/domains` | Listar dominios |
|
||||
|
||||
## Exemplos
|
||||
|
||||
### Listar Aplicacoes
|
||||
## Authentication
|
||||
Use Bearer token authentication:
|
||||
```bash
|
||||
curl -s -H "Authorization: Bearer $TOKEN" \
|
||||
"https://redbull.rede5.com.br/api/v1/applications"
|
||||
curl -H "Authorization: Bearer $TOKEN" ...
|
||||
```
|
||||
|
||||
### Criar PostgreSQL Database
|
||||
Token: `2|tjaxz6z6osQUz6whMvNMw23kcBqgToQAvMjSLos347164da9`
|
||||
|
||||
## Quick Commands
|
||||
|
||||
### List all applications
|
||||
```bash
|
||||
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
"https://redbull.rede5.com.br/api/v1/databases/postgresql" \
|
||||
-d '{
|
||||
"name": "my-database",
|
||||
"description": "PostgreSQL database",
|
||||
"project_uuid": "t0c4ss0wkcgwg48g088wkwgs",
|
||||
"environment_name": "production",
|
||||
"server_uuid": "m844o4gkwkwcc0k48swgs8c8",
|
||||
"destination_uuid": "e0ggcws4gsw4w4wkgggkg8ow",
|
||||
"postgres_user": "myuser",
|
||||
"postgres_password": "mypassword",
|
||||
"postgres_db": "mydb",
|
||||
"image": "postgres:16-alpine",
|
||||
"instant_deploy": true
|
||||
}'
|
||||
curl -s -H "Authorization: Bearer $(cat ~/.ssh/coolify-redbull-token)" "https://redbull.rede5.com.br/api/v1/applications"
|
||||
```
|
||||
|
||||
### Deploy por UUID
|
||||
### Deploy by UUID
|
||||
```bash
|
||||
curl -s -H "Authorization: Bearer $TOKEN" \
|
||||
"https://redbull.rede5.com.br/api/v1/deploy?uuid={UUID}"
|
||||
# Frontend
|
||||
curl -s -X GET -H "Authorization: Bearer $TOKEN" "https://redbull.rede5.com.br/api/v1/deploy?uuid=ao8g40scws0w4cgo8coc8o40"
|
||||
|
||||
# Backend
|
||||
curl -s -X GET -H "Authorization: Bearer $TOKEN" "https://redbull.rede5.com.br/api/v1/deploy?uuid=iw4sow8s0kkg4cccsk08gsoo"
|
||||
```
|
||||
|
||||
### Atualizar Dominio
|
||||
### Check deployment status
|
||||
```bash
|
||||
curl -s -X PATCH -H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
"https://redbull.rede5.com.br/api/v1/applications/{UUID}" \
|
||||
-d '{"domains":"https://meu-dominio.com"}'
|
||||
curl -s -H "Authorization: Bearer $TOKEN" "https://redbull.rede5.com.br/api/v1/deployments/{deployment_uuid}"
|
||||
```
|
||||
|
||||
## UUIDs Importantes
|
||||
|
||||
### Server
|
||||
| Nome | UUID |
|
||||
|------|------|
|
||||
| localhost | `m844o4gkwkwcc0k48swgs8c8` |
|
||||
|
||||
### Destination (Docker Network)
|
||||
| Nome | UUID |
|
||||
|------|------|
|
||||
| coolify | `e0ggcws4gsw4w4wkgggkg8ow` |
|
||||
|
||||
### Projects
|
||||
| Nome | UUID |
|
||||
|------|------|
|
||||
| Infraestrutura | `t0c4ss0wkcgwg48g088wkwgs` |
|
||||
| gohorsejobs | `gkgksco0ow4kgwo8ow4cgs8c` |
|
||||
| rodiziosdaqui | `iooos0488ww0coccosc0sk4c` |
|
||||
| obramarket | `scwgsc8k0w84gkc88c080ck4` |
|
||||
| q1food | `x0os8c40o00ssoo84sokwosk` |
|
||||
| q1agenda | `ews8s8o40wkok0cgc8w4wc04` |
|
||||
| sextando | `xk40w0s88wkcoco0css8c8kk` |
|
||||
| q1total | `e0gg00w4sksk88cwksgc4cwo` |
|
||||
| openproject | `dc40gww0gg4kw88k4gk88sws` |
|
||||
| saveinmed | `lgko4gcg0okk48k04kcww0gs` |
|
||||
| zeus-suplementos | `xwkcw80w0sgk8g84wo08s8ks` |
|
||||
|
||||
### Applications (Importantes)
|
||||
| Nome | UUID |
|
||||
|------|------|
|
||||
| q1site-frontend | `y0wccwwsko4socokk804s0ww` |
|
||||
| q1total-backend | `e8w040ow8skssoscookowgck` |
|
||||
| q1food-backend-dev | `eosgwscc4g044c884k0ws4gc` |
|
||||
| q1food-frontend-dev | `g8w440g0w0oowo8skss440wk` |
|
||||
| q1fit-dev | `fk8wswsk8ssswggcsoc0kgcc` |
|
||||
| zeus-frontend | `t4c8w08ocg8socoo8cg00c48` |
|
||||
|
||||
### Environments (Infraestrutura)
|
||||
| Nome | UUID |
|
||||
|------|------|
|
||||
| production | `sw4ckcgkgs0wssgs40os8s0g` |
|
||||
|
||||
## Variaveis de Ambiente
|
||||
### Start/Stop/Restart application
|
||||
```bash
|
||||
export COOLIFY_TOKEN="fzz2xL0UUwpeVB1mObEwxE9GO8sTV8z2OHiOojmdf0e428be"
|
||||
export COOLIFY_URL="https://redbull.rede5.com.br/api/v1"
|
||||
export COOLIFY_SERVER="m844o4gkwkwcc0k48swgs8c8"
|
||||
export COOLIFY_DESTINATION="e0ggcws4gsw4w4wkgggkg8ow"
|
||||
# Start
|
||||
curl -s -H "Authorization: Bearer $TOKEN" "https://redbull.rede5.com.br/api/v1/applications/{uuid}/start"
|
||||
|
||||
# Stop
|
||||
curl -s -H "Authorization: Bearer $TOKEN" "https://redbull.rede5.com.br/api/v1/applications/{uuid}/stop"
|
||||
|
||||
# Restart
|
||||
curl -s -H "Authorization: Bearer $TOKEN" "https://redbull.rede5.com.br/api/v1/applications/{uuid}/restart"
|
||||
```
|
||||
|
||||
## Script de Health Check
|
||||
## Application UUIDs
|
||||
|
||||
| App | UUID |
|
||||
|-----|------|
|
||||
| gohorsejobs-backend-dev | iw4sow8s0kkg4cccsk08gsoo |
|
||||
| gohorsejobs-backoffice-dev | hg48wkw4wggwsswcwc8sooo4 |
|
||||
| gohorsejobs-frontend-dev | ao8g40scws0w4cgo8coc8o40 |
|
||||
| gohorsejobs-seeder-dev | q4w48gos8cgssso00o8w8gck |
|
||||
| rodiziosdaqui-backend-dev | ecso4woo4woo0ks84888k8ck |
|
||||
| rodiziosdaqui-backoffice-dev | s4kskw08400wcw8g40ossggo |
|
||||
| rodiziosdaqui-frontend-dev | l4g4cc884gc04kg8s480gs48 |
|
||||
| rodiziosdaqui-seeder-dev | ko0kkw4kw8g80scksg8sk0wc |
|
||||
| q1food-backend-dev | eosgwscc4g044c884k0ws4gc |
|
||||
| q1food-frontend-dev | g8w440g0w0oowo8skss440wk |
|
||||
|
||||
## Scripts
|
||||
|
||||
### Health Check Script
|
||||
```bash
|
||||
#!/bin/bash
|
||||
TOKEN="fzz2xL0UUwpeVB1mObEwxE9GO8sTV8z2OHiOojmdf0e428be"
|
||||
curl -s -H "Authorization: Bearer $TOKEN" \
|
||||
"https://redbull.rede5.com.br/api/v1/applications" | jq -r '.[] | "\(.name): \(.status)"'
|
||||
TOKEN=$(cat ~/.ssh/coolify-redbull-token | tr -d '\n')
|
||||
echo "=== Coolify Health Check ==="
|
||||
curl -s -H "Authorization: Bearer $TOKEN" "http://185.194.141.70:8000/api/v1/applications" | python -c "
|
||||
import json,sys
|
||||
d = json.load(sys.stdin)
|
||||
for a in d:
|
||||
status = a.get('status','unknown')
|
||||
icon = '✅' if 'running' in status else '❌'
|
||||
print(f'{icon} {a[\"name\"]}: {status}')
|
||||
"
|
||||
```
|
||||
|
||||
## Links
|
||||
- [Coolify API Docs](https://coolify.io/docs/api-reference/authorization)
|
||||
- [GitHub Issues](https://github.com/coollabsio/coolify/issues)
|
||||
### Restart All Services
|
||||
```bash
|
||||
#!/bin/bash
|
||||
TOKEN=$(cat ~/.ssh/coolify-redbull-token | tr -d '\n')
|
||||
UUIDS=(
|
||||
"ao8g40scws0w4cgo8coc8o40"
|
||||
"q4w48gos8cgssso00o8w8gck"
|
||||
"iw4sow8s0kkg4cccsk08gsoo"
|
||||
"hg48wkw4wggwsswcwc8sooo4"
|
||||
"ecso4woo4woo0ks84888k8ck"
|
||||
"s4kskw08400wcw8g40ossggo"
|
||||
"l4g4cc884gc04kg8s480gs48"
|
||||
"ko0kkw4kw8g80scksg8sk0wc"
|
||||
)
|
||||
for uuid in "${UUIDS[@]}"; do
|
||||
echo "Deploying $uuid..."
|
||||
curl -s -X GET -H "Authorization: Bearer $TOKEN" "http://185.194.141.70:8000/api/v1/deploy?uuid=$uuid"
|
||||
done
|
||||
```
|
||||
|
||||
## Useful Links
|
||||
- Coolify Docs: https://coolify.io/docs
|
||||
- API Reference: https://coolify.io/docs/api-reference/authorization
|
||||
|
|
|
|||
173
vps/redbull/projetos-resumo.md
Normal file
173
vps/redbull/projetos-resumo.md
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
# Resumo de Projetos - Redbull (Coolify DEV)
|
||||
|
||||
> Atualizado: 2026-02-18
|
||||
|
||||
## Status Geral
|
||||
|
||||
| Projeto | Ambiente | Status | CI/CD | Webhook |
|
||||
|---------|----------|:------:|:-----:|:-------:|
|
||||
| GoHorseJobs | DEV | ✅ Running | ✅ GitHub Actions | ✅ Configurado |
|
||||
| RodiziosDaqui | DEV | ✅ Running | ❌ Sem pipeline | ✅ Configurado |
|
||||
| Q1Food | DEV | ❌ Unhealthy | ❌ Sem pipeline | ✅ Configurado |
|
||||
| Obramarket | DEV | ❌ Unhealthy | ❌ Sem pipeline | ❌ Não configurado |
|
||||
|
||||
---
|
||||
|
||||
## GoHorseJobs DEV
|
||||
|
||||
### URLs
|
||||
| Serviço | URL |
|
||||
|---------|-----|
|
||||
| Frontend | https://local.gohorsejobs.com |
|
||||
| Backend | https://api-local.gohorsejobs.com |
|
||||
| Backoffice | https://b-local.gohorsejobs.com |
|
||||
| Seeder | sslip.io (interno) |
|
||||
|
||||
### CI/CD
|
||||
| Workflow | Status | Trigger |
|
||||
|----------|--------|---------|
|
||||
| Deploy to Coolify DEV | ✅ Ativo | Push dev |
|
||||
| Validate RSA and Run Migrations | ❌ Falhando | Push dev |
|
||||
| Deploy Backend (Dev) | ✅ Ativo | Manual |
|
||||
|
||||
### Webhooks (Coolify)
|
||||
| Serviço | UUID | Secret |
|
||||
|---------|------|--------|
|
||||
| Backend | `iw4sow8s0kkg4cccsk08gsoo` | `oRTKAwXgHrIzIcXdVqa7BXPkzXVQAhwS` |
|
||||
| Frontend | `ao8g40scws0w4cgo8coc8o40` | `H3CfQuM9Jnpv9Tl37WKupEMlaaIWFlU5` |
|
||||
| Backoffice | `hg48wkw4wggwsswcwc8sooo4` | `wvREqj94RRX60113cYb2nMCZf0pmg662` |
|
||||
| Seeder | `q4w48gos8cgssso00o8w8gck` | `sa08PAj2RwyjW5VNmqKX0Ac9s7zIMyH2` |
|
||||
|
||||
### Repositórios
|
||||
- GitHub: https://github.com/rede5/gohorsejobs
|
||||
- Forgejo (mirror): https://pipe.gohorsejobs.com/bohessefm/gohorsejobs
|
||||
- Branch: `dev`
|
||||
|
||||
---
|
||||
|
||||
## RodiziosDaqui DEV
|
||||
|
||||
### URLs
|
||||
| Serviço | URL |
|
||||
|---------|-----|
|
||||
| Frontend | http://rodiziosdaqui.rede5.com.br |
|
||||
| Backend | http://api.rodiziosdaqui.rede5.com.br |
|
||||
| Backoffice | http://backoffice.rodiziosdaqui.rede5.com.br |
|
||||
| Seeder | http://seeder.rodiziosdaqui.rede5.com.br |
|
||||
|
||||
### CI/CD
|
||||
⚠️ **Sem pipeline configurado** - Deploy apenas via webhook manual
|
||||
|
||||
### Webhooks (Coolify)
|
||||
| Serviço | UUID | Secret |
|
||||
|---------|------|--------|
|
||||
| Backend | `ecso4woo4woo0ks84888k8ck` | `ElwDbKAUgKRvKPJPCqig1v3IGc31cZvo` |
|
||||
| Frontend | `l4g4cc884gc04kg8s480gs48` | `Rlz5bQyKJABIDWSZyEn30H1jvFMDF98k` |
|
||||
| Backoffice | `s4kskw08400wcw8g40ossggo` | `jDMmawqSg1ObcrlSt85HZKvrnzUPwBpt` |
|
||||
| Seeder | `ko0kkw4kw8g80scksg8sk0wc` | `7sCTpRSYtxsrAwFGBW5XCyiF4SR22mcn` |
|
||||
|
||||
### Repositório
|
||||
- GitHub: https://github.com/rede5/rodiziosdaqui
|
||||
- Branch: `dev`
|
||||
|
||||
### Banco de Dados
|
||||
- PostgreSQL interno (Coolify): `rodiziosdaqui-dev`
|
||||
- PostgreSQL externo (Absam): `db-60604.dc-us-1.absamcloud.com:11985`
|
||||
|
||||
### Ações Necessárias
|
||||
1. Criar GitHub Actions workflow para deploy automático
|
||||
2. Configurar webhooks no GitHub para disparar Coolify
|
||||
|
||||
---
|
||||
|
||||
## Q1Food DEV
|
||||
|
||||
### URLs
|
||||
| Serviço | URL | Status |
|
||||
|---------|-----|:------:|
|
||||
| Frontend | http://dev.q1food.com | ❌ unhealthy |
|
||||
| Backend | http://api-dev.q1food.com | ❌ unhealthy |
|
||||
|
||||
### CI/CD
|
||||
❌ **Sem pipeline configurado**
|
||||
|
||||
### Webhooks (Coolify)
|
||||
| Serviço | UUID | Secret |
|
||||
|---------|------|--------|
|
||||
| Backend | `eosgwscc4g044c884k0ws4gc` | `d66bac276faa04631124559d77199d0e` |
|
||||
| Frontend | `g8w440g0w0oowo8skss440wk` | `c512dc54933829d1cde381e2c9bf394a` |
|
||||
|
||||
### Repositórios
|
||||
- Backend: https://github.com/rede5/food-backend
|
||||
- Frontend: https://github.com/rede5/food-frontend
|
||||
- Branch: `dev`
|
||||
|
||||
### Ações Necessárias
|
||||
1. Verificar erro no container (exited:unhealthy)
|
||||
2. Criar GitHub Actions workflow
|
||||
3. Configurar webhooks no GitHub
|
||||
|
||||
---
|
||||
|
||||
## Obramarket DEV
|
||||
|
||||
### Status
|
||||
⚠️ **CRÍTICO** - 4 instâncias duplicadas, todas unhealthy
|
||||
|
||||
### URLs
|
||||
| Serviço | URL | Status |
|
||||
|---------|-----|--------|
|
||||
| Backend (1) | sslip.io | ❌ exited:unhealthy |
|
||||
| Backend (2) | sslip.io | ❌ exited:unhealthy |
|
||||
| Backend (3) | sslip.io | ❌ exited:unhealthy |
|
||||
| Backend (4) | sslip.io | ❌ exited:unhealthy |
|
||||
|
||||
### CI/CD
|
||||
❌ **Sem pipeline configurado**
|
||||
|
||||
### Webhooks
|
||||
❌ **Não configurado**
|
||||
|
||||
### Ações Necessárias
|
||||
1. Remover instâncias duplicadas (manter apenas 1)
|
||||
2. Configurar domínio próprio
|
||||
3. Configurar webhook para deploy automático
|
||||
4. Verificar erro no container
|
||||
|
||||
### Repositório
|
||||
- GitHub: https://github.com/rede5/obramarket
|
||||
- Branch: `main`
|
||||
|
||||
---
|
||||
|
||||
## Bancos de Dados (Coolify)
|
||||
|
||||
| Database | UUID | Status | Tipo |
|
||||
|----------|------|:------:|------|
|
||||
| gohorsejobs-dev | `bgws48os8wgwk08o48wg8k80` | ✅ healthy | PostgreSQL 16 |
|
||||
| rodiziosdaqui-dev | `e8ogwk008c8s8sok8wc00ow0` | ✅ healthy | PostgreSQL 16 |
|
||||
| vaultwarden | `sg0co4s44cs48o4kc4cgg844` | ✅ healthy | PostgreSQL 16 |
|
||||
|
||||
---
|
||||
|
||||
## Webhooks URL
|
||||
|
||||
Configurar no GitHub (Settings → Webhooks):
|
||||
|
||||
```
|
||||
https://redbull.rede5.com.br/api/v1/webhooks/deploy?uuid={UUID}
|
||||
```
|
||||
|
||||
Content-Type: `application/json`
|
||||
Secret: webhook secret da aplicação
|
||||
Events: `Push events`
|
||||
|
||||
---
|
||||
|
||||
## Links Úteis
|
||||
|
||||
- Coolify Dashboard: https://redbull.rede5.com.br
|
||||
- Coolify API: https://redbull.rede5.com.br/api/v1
|
||||
- GitHub Token: `~/.ssh/github-token`
|
||||
- Coolify Token: `~/.ssh/coolify-redbull-token`
|
||||
- Forgejo: https://pipe.gohorsejobs.com
|
||||
|
|
@ -1,208 +1,93 @@
|
|||
# Inventário de Serviços Redbull
|
||||
|
||||
> Última atualização: 2026-02-28 — Limpeza de duplicatas + fixes de repo + deploy q1food
|
||||
|
||||
---
|
||||
> Última atualização: 2026-02-18
|
||||
|
||||
## Visão Geral
|
||||
|
||||
Servidor Redbull (`185.194.141.70`) gerenciado pelo Coolify v4. Proxy reverso: Traefik.
|
||||
Este documento apresenta o inventário completo de serviços hospedados no servidor Redbull (185.194.141.70), utilizando a plataforma Coolify como camada de gerenciamento de aplicações baseadas em contêineres.
|
||||
|
||||
**SSH:** Conexão funciona via IP diretamente (`ssh redbull` → aponta para `185.194.141.70:22`).
|
||||
> ⚠️ `redbull.rede5.com.br` está atrás do Cloudflare — porta 22 bloqueada. SSH usa IP direto.
|
||||
## Tabela de Aplicações
|
||||
|
||||
---
|
||||
### GoHorse Jobs (DEV)
|
||||
|
||||
## Aplicações — Status Completo
|
||||
|
||||
### Q1 Agenda (DEV / HML)
|
||||
|
||||
| Aplicação | UUID | Domínio | Branch | CI/CD | Status |
|
||||
|-----------|------|---------|--------|-------|:------:|
|
||||
| **backend-dev** | `fk00s0cg8kgc0w4csswskgkw` | https://api-dev.q1agenda.com.br | dev | ❌ Sem webhook | ❌ Exited (aguardando envs) |
|
||||
| **backend-hml** | `lkoc4coo48k0sow4c00gwo8k` | https://api-hml.q1agenda.com.br | hml | ❌ Sem webhook | ❌ Exited (aguardando envs) |
|
||||
| **frontend-dev** | `jgook0gkss4cco0484co0s4o` | https://dev.q1agenda.com.br | main | ❌ Sem webhook | ✅ Running |
|
||||
| **frontend-hml** | `lg4k0gk4gsog8ckcs8sw4cwc` | https://hml.q1agenda.com.br | main | ❌ Sem webhook | ✅ Running |
|
||||
|
||||
**Repo backend:** `git@github.com:rede5/q1agenda-backend.git` (branch `dev`/`hml`)
|
||||
**Repo frontend:** `git@github.com:rede5/q1-agenda-frontend.git`
|
||||
**Fix 2026-02-28:** Repo URL corrigido (`q1-agenda-backend` → `q1agenda-backend`), duplicata sslip deletada, envs Appwrite base adicionados.
|
||||
**Pendente:** `APPWRITE_PROJECT_ID`, `APPWRITE_API_KEY`, `SECURITY_API_KEY`, `JWT_SECRET` — preencher no Coolify Dashboard antes de deployar.
|
||||
|
||||
---
|
||||
|
||||
### GoHorse Jobs (LOCAL / DEV)
|
||||
|
||||
| Aplicação | UUID | Domínio | Branch | CI/CD | Status |
|
||||
|-----------|------|---------|--------|-------|:------:|
|
||||
| **gohorsejobs-backend-local** | `iw4sow8s0kkg4cccsk08gsoo` | https://test2.q1agenda.com.br | dev | ✅ GitHub webhook | ✅ Running |
|
||||
| **gohorsejobs-frontend-local** | `ao8g40scws0w4cgo8coc8o40` | https://local.gohorsejobs.com | dev | ✅ GitHub webhook | ✅ Running |
|
||||
| **gohorsejobs-backoffice-local** | `hg48wkw4wggwsswcwc8sooo4` | https://b-local.gohorsejobs.com | dev | ✅ GitHub webhook | ✅ Running |
|
||||
| **gohorsejobs-seeder-local** | `q4w48gos8cgssso00o8w8gck` | https://s-local.gohorsejobs.com | dev | ✅ GitHub webhook | ✅ Healthy |
|
||||
**Repo:** `git@github.com:rede5/gohorsejobs.git`
|
||||
**Fix 2026-02-28:** `gohorsejobs-frontend-dev` (sslip.io, sem domínio, sem envs) deletada — duplicata da `frontend-local`.
|
||||
**Nota:** `gohorsejobs-backend-local` aponta para `test2.q1agenda.com.br` — revisar domínio.
|
||||
|
||||
---
|
||||
| Aplicação | UUID | Porta | Domínio | Status |
|
||||
|-----------|------|:-----:|---------|:------:|
|
||||
| **gohorsejobs-backend-dev** | `iw4sow8s0kkg4cccsk08gsoo` | 8521 | coolify-dev.gohorsejobs.com | ✅ Running |
|
||||
| **gohorsejobs-frontend-dev** | `ao8g40scws0w4cgo8coc8o40` | 3000 | dev.gohorsejobs.com | ✅ Running |
|
||||
| **gohorsejobs-backoffice-dev** | `hg48wkw4wggwsswcwc8sooo4` | 3001 | backoffice-dev.gohorsejobs.com | ✅ Running |
|
||||
| **gohorsejobs-seeder-dev** | `q4w48gos8cgssso00o8w8gck` | 8080 | seeder-dev.gohorsejobs.com | ✅ Running |
|
||||
|
||||
### Rodizios Daqui (DEV)
|
||||
|
||||
| Aplicação | UUID | Domínio | Branch | CI/CD | Status |
|
||||
|-----------|------|---------|--------|-------|:------:|
|
||||
| **rodiziosdaqui-backend-dev** | `ecso4woo4woo0ks84888k8ck` | http://api.rodiziosdaqui.rede5.com.br | dev | ✅ GitHub webhook | ✅ Running |
|
||||
| **rodiziosdaqui-frontend-dev** | `l4g4cc884gc04kg8s480gs48` | http://rodiziosdaqui.rede5.com.br | dev | ✅ GitHub webhook | ✅ Running |
|
||||
| **rodiziosdaqui-backoffice-dev** | `s4kskw08400wcw8g40ossggo` | http://backoffice.rodiziosdaqui.rede5.com.br | dev | ✅ GitHub webhook | ✅ Running |
|
||||
| **rodiziosdaqui-seeder-dev** | `ko0kkw4kw8g80scksg8sk0wc` | http://seeder.rodiziosdaqui.rede5.com.br | dev | ✅ GitHub webhook | ✅ Healthy |
|
||||
| Aplicação | UUID | Porta | Domínio | Status |
|
||||
|-----------|------|:-----:|---------|:------:|
|
||||
| **rodiziosdaqui-backend-dev** | `ecso4woo4woo0ks84888k8ck` | 8080 | api.rodiziosdaqui.rede5.com.br | ✅ Running |
|
||||
| **rodiziosdaqui-frontend-dev** | `l4g4cc884gc04kg8s480gs48` | 3000 | rodiziosdaqui.rede5.com.br | ✅ Running |
|
||||
| **rodiziosdaqui-backoffice-dev** | `s4kskw08400wcw8g40ossggo` | 8082 | backoffice.rodiziosdaqui.rede5.com.br | ✅ Running |
|
||||
| **rodiziosdaqui-seeder-dev** | `ko0kkw4kw8g80scksg8sk0wc` | 8081 | seeder.rodiziosdaqui.rede5.com.br | ✅ Healthy |
|
||||
|
||||
**Repo:** `git@github.com:rede5/rodiziosdaqui.git`
|
||||
**Projeto mais completo e estável** — todos rodando com CI/CD configurado.
|
||||
### Q1Food (DEV)
|
||||
|
||||
---
|
||||
| Aplicação | UUID | Porta | Domínio | Status |
|
||||
|-----------|------|:-----:|---------|:------:|
|
||||
| **q1food-backend-dev** | `eosgwscc4g044c884k0ws4gc` | 8000 | api-dev.q1food.com | ❌ Unhealthy |
|
||||
| **q1food-frontend-dev** | `g8w440g0w0oowo8skss440wk` | 3000 | dev.q1food.com | ❌ Unhealthy |
|
||||
|
||||
### Q1 Food (DEV)
|
||||
### Obramarket (DEV)
|
||||
|
||||
| Aplicação | UUID | Domínio | Branch | CI/CD | Status |
|
||||
|-----------|------|---------|--------|-------|:------:|
|
||||
| **q1food-backend-dev** | `eosgwscc4g044c884k0ws4gc` | http://api-dev.q1food.com | dev | ✅ GitHub webhook | ❌ Exited |
|
||||
| **q1food-frontend-dev** | `g8w440g0w0oowo8skss440wk` | http://dev.q1food.com | dev | ✅ GitHub webhook | ✅ Running |
|
||||
| Aplicação | UUID | Porta | Domínio | Status |
|
||||
|-----------|------|:-----:|---------|:------:|
|
||||
| **obramarket-backend-dev** | múltiplos | 8080 | sslip.io | ❌ Unhealthy |
|
||||
|
||||
**Repos:** `rede5/food-backend.git` / `rede5/food-frontend.git`
|
||||
**Issues:** Backend parado desde 18/02. CI/CD configurado mas deploy falhou.
|
||||
## Tabela de Bancos de Dados
|
||||
|
||||
---
|
||||
| Serviço | UUID | Versão | Apps Vinculados | Porta |
|
||||
|---------|------|:------:|-----------------|:-----:|
|
||||
| **gohorsejobs-dev** | `bgws48os8wgwk08o48wg8k80` | PostgreSQL 16 | gohorsejobs-* | 5432 |
|
||||
| **rodiziosdaqui-dev** | `e8ogwk008c8s8sok8wc00ow0` | PostgreSQL 16 | rodiziosdaqui-* | 5432 |
|
||||
|
||||
### Sextando (DEV)
|
||||
## Webhooks GitHub
|
||||
|
||||
| Aplicação | UUID | Domínio | Branch | CI/CD | Status |
|
||||
|-----------|------|---------|--------|-------|:------:|
|
||||
| **sextando-backend** | `h8c4sg0sg80c4o8kkcw4ogcg` | https://api-dev.sextando.com.br | dev | ❌ Sem webhook | ❌ Exited |
|
||||
| **sextando-backoffice** | `nsc0gw0og40g0c88soc0o0wc` | https://backoffice-dev.sextando.com.br | dev | ❌ Sem webhook | ❌ Exited |
|
||||
| **sextando-frontend** | `vggkcs880o8go0ws84wcggco` | https://dev.sextando.com.br | dev | ❌ Sem webhook | ✅ Running |
|
||||
### GoHorse Jobs
|
||||
| App | Webhook Secret |
|
||||
|-----|----------------|
|
||||
| Backend | `oRTKAwXgHrIzIcXdVqa7BXPkzXVQAhwS` |
|
||||
| Frontend | `H3CfQuM9Jnpv9Tl37WKupEMlaaIWFlU5` |
|
||||
| Backoffice | `wvREqj94RRX60113cYb2nMCZf0pmg662` |
|
||||
| Seeder | `sa08PAj2RwyjW5VNmqKX0Ac9s7zIMyH2` |
|
||||
|
||||
**Repo:** `git@github.com:rede5/sextando.git`
|
||||
**Build:** Frontend usa `nixpacks`, backend/backoffice usam `dockerfile`
|
||||
**Issues:** Nenhum dos 3 tem webhook CI/CD. Backend e backoffice parados.
|
||||
### Rodizios Daqui
|
||||
| App | Webhook Secret |
|
||||
|-----|----------------|
|
||||
| Backend | `ElwDbKAUgKRvKPJPCqig1v3IGc31cZvo` |
|
||||
| Frontend | `Rlz5bQyKJABIDWSZyEn30H1jvFMDF98k` |
|
||||
| Backoffice | `jDMmawqSg1ObcrlSt85HZKvrnzUPwBpt` |
|
||||
| Seeder | `7sCTpRSYtxsrAwFGBW5XCyiF4SR22mcn` |
|
||||
|
||||
---
|
||||
### Q1Food
|
||||
| App | Webhook Secret |
|
||||
|-----|----------------|
|
||||
| Backend | `d66bac276faa04631124559d77199d0e` |
|
||||
| Frontend | `c512dc54933829d1cde381e2c9bf394a` |
|
||||
|
||||
### ObraMarket (DEV)
|
||||
## Containers Docker Ativos
|
||||
|
||||
| Aplicação | UUID | Domínio | Branch | CI/CD | Status |
|
||||
|-----------|------|---------|--------|-------|:------:|
|
||||
| **obramarket-backend-dev** | `ws08owk8ocog0gswg8ogo8c4` | sslip.io (sem domínio próprio) | main | ❌ Sem webhook | ❌ Exited |
|
||||
|
||||
**Repo:** `git@github.com:rede5/obramarket.git`
|
||||
**Fix 2026-02-28:** 3 duplicatas deletadas (forgejo, IP interno, URL inválida). Envs base adicionados (SERVER_PORT, DB_PORT, etc.).
|
||||
**Pendente:** `DB_HOST`, `DB_USER`, `DB_PASSWORD`, `DB_NAME`, `JWT_SECRET`, `PEPPER_SECRET`, `ADMIN_EMAIL`, `ADMIN_PASSWORD`, `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` — preencher no Coolify + configurar domínio próprio.
|
||||
|
||||
---
|
||||
|
||||
## Resumo de Status
|
||||
|
||||
| Projeto | Rodando | Parado | CI/CD | Apps Total |
|
||||
|---------|:-------:|:------:|-------|:----------:|
|
||||
| Q1Agenda | 2 | 2 | ❌ Nenhum | 4 |
|
||||
| GoHorse Jobs | 4 | 0 | ✅ Todos | 4 |
|
||||
| Rodizios Daqui | 4 | 0 | ✅ Todos | 4 |
|
||||
| Q1Food | 1 | 1 🔄 | ✅ Ambos | 2 |
|
||||
| Sextando | 3 | 0 | ❌ Nenhum | 3 |
|
||||
| ObraMarket | 0 | 1 | ❌ Nenhum | 1 |
|
||||
| Q1Total | 1 | 0 | ✅ | 1 |
|
||||
| Q1Site | 1 | 0 | ✅ | 1 |
|
||||
| SaveInMed | 2 | 0 | ✅ | 2 |
|
||||
| **Total** | **18** | **4** | | **22** |
|
||||
|
||||
> 🔄 q1food-backend em deploy após refactor Supabase → PostgreSQL (2026-02-28)
|
||||
|
||||
---
|
||||
|
||||
## Bancos de Dados (Databases)
|
||||
|
||||
| Serviço | UUID | DB | Apps Vinculados | Status |
|
||||
|---------|------|----|-----------------|:------:|
|
||||
| **gohorsejobs-dev** | `bgws48os8wgwk08o48wg8k80` | PostgreSQL 16 | gohorsejobs-* | ✅ Healthy (10d) |
|
||||
| **rodiziosdaqui-dev** | `e8ogwk008c8s8sok8wc00ow0` | PostgreSQL 16 | rodiziosdaqui-* | ✅ Healthy (10d) |
|
||||
| **q1food-dev** | `vskkccs8880cg0ggckccsgww` | PostgreSQL | q1food-* | ✅ Healthy (8d) |
|
||||
| **vaultwarden-db** | `sg0co4s44cs48o4kc4cgg844` | PostgreSQL | Vaultwarden | ✅ Healthy (8d) |
|
||||
| **bookstack-db** | `mariadb-ogs4okgoosk48cswoo0s4k84` | MariaDB | BookStack | ✅ Up (3d) |
|
||||
|
||||
---
|
||||
|
||||
## Serviços (Coolify Services)
|
||||
|
||||
| Serviço | Domínio | Status |
|
||||
|---------|---------|:------:|
|
||||
| **BookStack** (`ogs4okgoosk48cswoo0s4k84`) | https://docs.rede5.com.br | ✅ Running (3d) |
|
||||
| **Vaultwarden** (`h8wg0gogw44swosgk8wgc8cs`) | https://vault.rede5.com.br | ✅ Healthy |
|
||||
| **Forgejo** (`zskgc8sck4w8g8w0o4w44o40`) | pipe.gohorsejobs.com | ⚠️ API=exited, Docker=Up 9d |
|
||||
| **Supabase** (`hk0ogck8w0co0skc0c8g0ss0`) | - | ❌ Exited |
|
||||
|
||||
---
|
||||
|
||||
## Infraestrutura Coolify (containers internos)
|
||||
|
||||
| Container | Status |
|
||||
|-----------|:------:|
|
||||
| coolify | ✅ Up 9d (healthy) |
|
||||
| coolify-proxy (Traefik) | ✅ Up 9d (healthy) |
|
||||
| coolify-db | ✅ Up 10d (healthy) |
|
||||
| coolify-redis | ✅ Up 10d (healthy) |
|
||||
| coolify-realtime | ✅ Up 10d (healthy) |
|
||||
| coolify-sentinel | ✅ Up 20h (healthy) |
|
||||
|
||||
---
|
||||
|
||||
## Conectividade SSH
|
||||
|
||||
| Método | Status | Observação |
|
||||
|--------|:------:|------------|
|
||||
| `ssh redbull` (via IP `185.194.141.70:22`) | ✅ OK | Funciona |
|
||||
| `ssh root@redbull.rede5.com.br` (port 22) | ❌ Timeout | Cloudflare bloqueia porta 22 |
|
||||
| Coolify API (`https://redbull.rede5.com.br`) | ✅ OK | Via Traefik HTTPS |
|
||||
| Coolify API (`http://185.194.141.70:8000`) | ✅ OK | Acesso direto |
|
||||
|
||||
**SSH Config:** `~/.ssh/config` usa `HostName 185.194.141.70` (IP direto).
|
||||
|
||||
---
|
||||
|
||||
## Webhooks CI/CD
|
||||
|
||||
### GoHorse Jobs (`rede5/gohorsejobs` → branch `dev`)
|
||||
|
||||
| App | Webhook URL |
|
||||
|-----|------------|
|
||||
| Backend | `https://redbull.rede5.com.br/api/v1/webhook/github?uuid=iw4sow8s0kkg4cccsk08gsoo` |
|
||||
| Frontend | `https://redbull.rede5.com.br/api/v1/webhook/github?uuid=ao8g40scws0w4cgo8coc8o40` |
|
||||
| Backoffice | `https://redbull.rede5.com.br/api/v1/webhook/github?uuid=hg48wkw4wggwsswcwc8sooo4` |
|
||||
| Seeder | `https://redbull.rede5.com.br/api/v1/webhook/github?uuid=q4w48gos8cgssso00o8w8gck` |
|
||||
|
||||
### Rodizios Daqui (`rede5/rodiziosdaqui` → branch `dev`)
|
||||
|
||||
| App | Webhook URL |
|
||||
|-----|------------|
|
||||
| Backend | `https://redbull.rede5.com.br/api/v1/webhook/github?uuid=ecso4woo4woo0ks84888k8ck` |
|
||||
| Backoffice | `https://redbull.rede5.com.br/api/v1/webhook/github?uuid=s4kskw08400wcw8g40ossggo` |
|
||||
| Frontend | `https://redbull.rede5.com.br/api/v1/webhook/github?uuid=l4g4cc884gc04kg8s480gs48` |
|
||||
| Seeder | `https://redbull.rede5.com.br/api/v1/webhook/github?uuid=ko0kkw4kw8g80scksg8sk0wc` |
|
||||
|
||||
### Q1Food (`rede5/food-*` → branch `dev`)
|
||||
|
||||
| App | Webhook URL |
|
||||
|-----|------------|
|
||||
| Backend | `https://redbull.rede5.com.br/api/v1/webhook/github?uuid=eosgwscc4g044c884k0ws4gc` |
|
||||
| Frontend | `https://redbull.rede5.com.br/api/v1/webhook/github?uuid=g8w440g0w0oowo8skss440wk` |
|
||||
|
||||
> **Secrets dos webhooks:** ver `services_inventory.md` seção anterior ou Coolify Dashboard.
|
||||
|
||||
---
|
||||
| Container | Imagem | Porta | Notas |
|
||||
|-----------|--------|:-----:|-------|
|
||||
| coolify | ghcr.io/coollabsio/coolify:4.0.0-beta.463 | 8000 | Painel Coolify |
|
||||
| coolify-db | postgres:15-alpine | 5432 | Banco Coolify |
|
||||
| coolify-redis | redis:7-alpine | 6379 | Cache Coolify |
|
||||
| coolify-realtime | soketi | 6001 | WebSocket |
|
||||
| coolify-sentinel | coolify-sentinel | 8888 | Monitoramento |
|
||||
| coolify-proxy | traefik:v3.6 | 80/443 | Proxy reverso |
|
||||
|
||||
## Portas do Sistema
|
||||
|
||||
| Porta | Serviço |
|
||||
|:-----:|---------|
|
||||
| 22 | SSH (acesso via IP direto) |
|
||||
| 80 | Traefik HTTP |
|
||||
| 443 | Traefik HTTPS |
|
||||
| 22 | SSH |
|
||||
| 80 | Traefik (HTTP) |
|
||||
| 443 | Traefik (HTTPS) |
|
||||
| 8000 | Coolify Dashboard |
|
||||
| 22222 | Forgejo SSH |
|
||||
| 3000 | Frontends (Next.js) |
|
||||
|
|
@ -211,96 +96,72 @@ Servidor Redbull (`185.194.141.70`) gerenciado pelo Coolify v4. Proxy reverso: T
|
|||
| 8081 | Seeders |
|
||||
| 8521 | GoHorse Backend |
|
||||
|
||||
---
|
||||
|
||||
## Fixes Aplicados
|
||||
|
||||
### 2026-02-28
|
||||
|
||||
| App | Problema | Fix | Status |
|
||||
|-----|----------|-----|:------:|
|
||||
| **q1food-backend** | Migração Supabase → PostgreSQL incompleta (app crashava no startup) | 19 arquivos reescritos via GitHub API (branch `dev`): config, database, 7 models, 6 services, migrations/init.sql + Dockerfile uploads dir + fix postgres:// → ✅ Running | ✅ OK |
|
||||
| **q1agenda-backend** (dev+hml) | Repo URL errado (`q1-agenda-backend` → `q1agenda-backend`), duplicata sslip.io, sem envs | PATCH Coolify repo URL, branch dev/hml, DELETE duplicata, envs Appwrite base adicionados | ⚠️ Aguarda credenciais |
|
||||
| **obramarket-backend** | 4 duplicatas com repos inconsistentes (forgejo, IP, inválido, github) | DELETE 3 duplicatas, envs base adicionados | ⚠️ Aguarda credenciais DB |
|
||||
| **gohorsejobs-frontend-dev** | Duplicata sem domínio/envs (sslip.io) da frontend-local | DELETE do Coolify | ✅ Limpo |
|
||||
|
||||
### 2026-02-26
|
||||
|
||||
| App | Problema | Fix | Status |
|
||||
|-----|----------|-----|:------:|
|
||||
| **q1food-backend** | Submodulo `.gitmodules` auto-referenciando o próprio repo via HTTPS | Deletado `.gitmodules` via GitHub API (commit `432e07d`) | ✅ Build OK |
|
||||
| **sextando-backend** | `schema.sql` não copiado para container final (multi-stage) | Adicionado `COPY --from=builder /app/internal/database/schema.sql` no Dockerfile (commit `61d6b98`) | ✅ UP |
|
||||
| **sextando-backend** | `base_directory=/` causava contexto errado (Go files em `/backend/`) | PATCH Coolify: `base_directory=/backend`, `dockerfile=/Dockerfile` | ✅ Fixado |
|
||||
| **sextando-backoffice** | `base_directory=/` contexto errado (`prisma/` não encontrado) | PATCH Coolify: `base_directory=/backoffice`, `dockerfile=/Containerfile` | ✅ Fixado |
|
||||
| **sextando-backoffice** | Containerfile usava `npm ci` sem `package-lock.json` (projeto usa pnpm) | Trocado para `npm install` (commit `84ca0d7`) | ✅ Build OK |
|
||||
| **sextando-backoffice** | `dist/main` não encontrado — `tsconfig.json` sem `rootDir` → saída em `dist/src/main`. Prisma sem `DATABASE_URL` | CMD → `node dist/src/main` + `openssl` no final stage + `DATABASE_URL` configurada | ✅ UP |
|
||||
|
||||
## Issues Pendentes (Ação Manual Necessária)
|
||||
|
||||
| # | Problema | Severidade | Ação |
|
||||
|---|----------|:----------:|------|
|
||||
| 1 | **q1agenda-backend** (dev+hml): faltam credenciais Appwrite | 🔴 Alta | Coolify → App → Envs: `APPWRITE_PROJECT_ID`, `APPWRITE_API_KEY`, `SECURITY_API_KEY`, `JWT_SECRET` → Deploy |
|
||||
| 2 | **obramarket-backend**: faltam credenciais DB + S3 + JWT | 🔴 Alta | Coolify → App → Envs: `DB_HOST/USER/PASSWORD/NAME`, `JWT_SECRET`, `PEPPER_SECRET`, `AWS_ACCESS_KEY_ID/SECRET` → Deploy |
|
||||
| 3 | **obramarket-backend**: sem domínio próprio (sslip.io) | 🟡 Média | Coolify UI → App → Domains → adicionar `api-dev.obramarket.com.br` |
|
||||
| 4 | **Sextando: nenhum app tem webhook CI/CD** | 🟡 Média | Configurar webhook GitHub para todos (ver URLs abaixo) |
|
||||
| 5 | **SSH hostname bloqueado** — porta 22 inacessível via `redbull.rede5.com.br` | 🟢 Baixa | Cloudflare bloqueia porta 22 — SSH config usa IP `185.194.141.70` |
|
||||
| 6 | **gohorsejobs-backend-local** usa domínio `test2.q1agenda.com.br` | 🟢 Baixa | Revisar domínio para `api-local.gohorsejobs.com` |
|
||||
|
||||
### q1agenda-backend — Envs pendentes
|
||||
```bash
|
||||
APPWRITE_PROJECT_ID=<id_do_projeto_appwrite>
|
||||
APPWRITE_API_KEY=<api_key_server>
|
||||
SECURITY_API_KEY=<chave_interna>
|
||||
JWT_SECRET=<segredo_jwt>
|
||||
```
|
||||
|
||||
### obramarket-backend — Envs pendentes
|
||||
```bash
|
||||
DB_HOST=<host_postgres>
|
||||
DB_USER=<usuario>
|
||||
DB_PASSWORD=<senha>
|
||||
DB_NAME=obramarket_dev
|
||||
JWT_SECRET=<segredo>
|
||||
PEPPER_SECRET=<pepper>
|
||||
ADMIN_EMAIL=admin@obramarket.com.br
|
||||
ADMIN_PASSWORD=<senha_inicial>
|
||||
AWS_ACCESS_KEY_ID=<key>
|
||||
AWS_SECRET_ACCESS_KEY=<secret>
|
||||
```
|
||||
|
||||
### Sextando — Webhooks CI/CD a configurar no GitHub
|
||||
```
|
||||
# Repositório: github.com/rede5/sextando → Settings → Webhooks
|
||||
Backend URL: https://redbull.rede5.com.br/api/v1/webhook/github?uuid=h8c4sg0sg80c4o8kkcw4ogcg
|
||||
Backoffice URL: https://redbull.rede5.com.br/api/v1/webhook/github?uuid=nsc0gw0og40g0c88soc0o0wc
|
||||
Frontend URL: https://redbull.rede5.com.br/api/v1/webhook/github?uuid=vggkcs880o8go0ws84wcggco
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Comandos Rápidos
|
||||
|
||||
### SSH Access
|
||||
```bash
|
||||
# SSH (usar IP direto)
|
||||
ssh redbull
|
||||
|
||||
# Ver todos os containers
|
||||
ssh redbull "docker ps --format 'table {{.Names}}\t{{.Status}}'"
|
||||
|
||||
# Ver logs de um app
|
||||
ssh redbull "docker logs <container_name> --tail 50"
|
||||
|
||||
# Coolify API
|
||||
TOKEN=$(cat ~/.ssh/coolify-redbull-token)
|
||||
URL="https://redbull.rede5.com.br/api/v1"
|
||||
|
||||
# Listar apps com status
|
||||
curl -s -H "Authorization: Bearer $TOKEN" "$URL/applications" | \
|
||||
node -e "const c=[]; process.stdin.on('data',d=>c.push(d)); process.stdin.on('end',()=>{ JSON.parse(c.join('')).forEach(a=>console.log(a.status+' | '+a.name+' | '+a.fqdn)); })"
|
||||
|
||||
# Deploy por UUID
|
||||
curl -s -H "Authorization: Bearer $TOKEN" "$URL/deploy?uuid=<UUID>"
|
||||
|
||||
# Reiniciar app
|
||||
curl -s -H "Authorization: Bearer $TOKEN" "$URL/applications/<UUID>/restart"
|
||||
```
|
||||
|
||||
### Check All Containers
|
||||
```bash
|
||||
ssh redbull "docker ps -a"
|
||||
```
|
||||
|
||||
### Health Check via API
|
||||
```bash
|
||||
TOKEN="2|tjaxz6z6osQUz6whMvNMw23kcBqgToQAvMjSLos347164da9"
|
||||
curl -s -H "Authorization: Bearer $TOKEN" "https://redbull.rede5.com.br/api/v1/applications"
|
||||
```
|
||||
|
||||
### Deploy Application
|
||||
```bash
|
||||
# Via UUID
|
||||
TOKEN="2|tjaxz6z6osQUz6whMvNMw23kcBqgToQAvMjSLos347164da9"
|
||||
curl -s -X GET -H "Authorization: Bearer $TOKEN" "https://redbull.rede5.com.br/api/v1/deploy?uuid={UUID}"
|
||||
```
|
||||
|
||||
### View Logs
|
||||
```bash
|
||||
ssh redbull "docker logs {container_name}"
|
||||
```
|
||||
|
||||
## Script de Health Check Automático
|
||||
|
||||
Execute no terminal local:
|
||||
```bash
|
||||
#!/bin/bash
|
||||
echo "=== Redbull Health Check ==="
|
||||
echo ""
|
||||
|
||||
# Check containers
|
||||
echo "📦 Containers:"
|
||||
ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no redbull "docker ps --format '{{.Names}}:{{.Status}}'" 2>/dev/null | while read line; do
|
||||
if echo "$line" | grep -q "healthy\|Up"; then
|
||||
echo " ✅ $line"
|
||||
else
|
||||
echo " ❌ $line"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "🌐 Aplicações Coolify:"
|
||||
TOKEN="2|tjaxz6z6osQUz6whMvNMw23kcBqgToQAvMjSLos347164da9"
|
||||
curl -s -H "Authorization: Bearer $TOKEN" "https://redbull.rede5.com.br/api/v1/applications" 2>/dev/null | python -c "
|
||||
import json,sys
|
||||
try:
|
||||
d = json.load(sys.stdin)
|
||||
for a in d:
|
||||
status = a.get('status','unknown')
|
||||
icon = '✅' if 'running' in status else '❌'
|
||||
print(f' {icon} {a[\"name\"]}: {status}')
|
||||
except: print(' Erro ao buscar dados')
|
||||
"
|
||||
```
|
||||
|
||||
## Issues Conhecidos
|
||||
|
||||
1. ~~gohorsejobs-seeder-dev~~ - ✅ CORRIGIDO
|
||||
2. ~~gohorsejobs-frontend-dev~~ - ✅ CORRIGIDO (erro de tipagem TypeScript)
|
||||
3. SSL: Domínios ainda sem HTTPS configurado
|
||||
4. S3: Rodiziosdaqui backend sem S3 configurado (uploads desabilitados)
|
||||
|
|
|
|||
Loading…
Reference in a new issue