Conectar ao banco
A connection string do DIVZ tem o formato postgresql://<role>:<senha>@db.divz.com.br:5432/<projeto>?sslmode=require. TLS é obrigatório e a porta é a 5432 padrão do PostgreSQL, então qualquer driver funciona sem adaptação.
Formato da connection string
postgresql://<role>:<senha>@<host>:5432/<projeto>?sslmode=require
│ │ │ │
│ │ │ └── nome do banco = slug do projeto
│ │ └────────────── db.divz.com.br ou db-br.divz.com.br
│ └─────────────────────── gerada pelo DIVZ, visível no console
└──────────────────────────────── <projeto>_owner, ou o role de appHosts por região
| Região | Host | Onde fica | Quando usar |
|---|---|---|---|
| fsn1-de | db.divz.com.br | Falkenstein, Alemanha | padrão; melhor custo e a região onde tudo nasce |
| br-sp | db-br.divz.com.br | São Paulo, Brasil | quando a latência a partir do Brasil importa mais que o resto |
A região é escolhida na criação do projeto e pode ser trocada depois pelo console. O host da string acompanha a região — mover um projeto muda o host, então leia a string de novo depois de mover.
TLS é obrigatório
A porta pública recusa conexão sem TLS (client_tls_sslmode = require). Não é opcional e não há como desligar: sem isso a senha viajaria em claro numa porta exposta à internet. Mantenha ?sslmode=require na string.
O certificado é autoassinado. Com sslmode=require o cliente cifra a conexão sem validar a cadeia, que é o comportamento esperado aqui. Usar verify-full vai falhar.
Você conecta num pooler, não direto no Postgres
Toda conexão passa por um PgBouncer em modo transação. Isso é o que permite milhares de clientes contra um banco que escala a zero, e tem consequências práticas que valem mais que a economia de conexões:
| Recurso | Funciona? | Por quê |
|---|---|---|
| Queries e transações normais | sim | o caso comum; nada muda |
| Prepared statements nomeados | com ressalva | cada transação pode cair em outra conexão de servidor; use o modo simple query ou prepared statements do lado do cliente |
| LISTEN / NOTIFY | não | depende de sessão fixa, que o modo transação não garante |
| Tabelas temporárias entre transações | não | somem quando a conexão de servidor é devolvida ao pool |
| Advisory locks de sessão | não | mesma razão; use locks de transação |
| SET de parâmetro por sessão | não confiável | vale só até o fim da transação |
Frameworks modernos lidam bem com isso. No Prisma, acrescente ?pgbouncer=true à string. No node-postgres, evite client.query com name: definido. No SQLAlchemy, use NullPool — o pooling já está do lado do servidor.
O limite atual é de 2.000 conexões de cliente por instância, com pool de 25 conexões de servidor por banco. Na prática você esgota o plano antes de esgotar o pooler.
Feche o banco para o resto da internet
Por padrão a allowlist de um projeto novo está vazia, e vazia significa liberado a qualquer origem — a senha é a única barreira. Assim que souber de onde sua aplicação conecta, preencha a lista em Projeto → Segurança, ou pela API:
curl -X PUT https://api.divz.com.br/api/v1/projects/<id>/ip-allow \
-H "Authorization: Bearer divz_..." \
-H "Content-Type: application/json" \
-d '{"ips": ["203.0.113.10", "10.0.0.0/8"]}'A lista substitui a anterior — não acrescenta. Leia a lista atual antes de escrever, e inclua nela os endereços que devem continuar entrando, ou você se tranca do lado de fora.
Use o role de aplicação, não o dono
Todo projeto nasce com o role <projeto>_owner, que é dono do banco e pode tudo — inclusive derrubar tabelas e contornar row level security. Ele serve para migração e manutenção, não para viver no .env de um serviço em produção.
Crie o role de aplicação (console ou POST /api/v1/projects/:id/roles/app). Ele recebe uma connection string própria, respeita RLS e não tem privilégio de dono. Se ele vazar, o estrago é limitado ao que você concedeu.
Rotação de senha
A senha de qualquer role pode ser rotacionada pelo console ou pela API. A do role de app tem rotação suave: a string antiga continua válida até o host materializar a nova (acompanhe pelo campo ready em GET /api/v1/projects/:id/roles). A do dono não — ela quebra as conexões antigas assim que aplica.
Próximo: Branches copy-on-write