Banco de Dados Relacionais¶
Este documento define o padrão essencial da Arkorizon para bancos de dados relacionais, com foco em PostgreSQL.
O objetivo é manter consistência, segurança e rastreabilidade sem burocracia desnecessária.
Princípios¶
- PostgreSQL é o padrão para dados relacionais.
- Segurança vem antes de conveniência.
- Cada aplicação deve usar o menor privilégio possível.
- Ambientes diferentes não compartilham database.
- Produtos diferentes não compartilham database.
- Toda mudança estrutural deve ser versionada por migration.
- Nomes devem ser claros, previsíveis e em
snake_case.
Separação por ambiente¶
Produção, homologação, desenvolvimento e testes devem usar databases separados.
product_a_prod
product_a_staging
product_a_dev
product_a_test
product_b_prod
product_b_staging
product_b_dev
product_b_test
Regras:
- produção nunca compartilha database com homologação;
- homologação nunca escreve no database de produção;
- desenvolvimento usa database próprio ou local;
- testes automatizados usam database descartável ou isolado;
- credenciais devem ser diferentes por ambiente;
- dados de produção não devem ir para ambientes menores sem anonimização.
Database, schema e aplicação¶
Regra prática:
Ambiente diferente -> database diferente.
Produto diferente -> database diferente.
Contexto interno do mesmo produto -> schema diferente apenas quando houver motivo real.
Exemplo:
product_a_prod
schema: core
schema: audit
product_b_prod
schema: core
schema: knowledge
Use schema quando:
- os dados pertencem ao mesmo produto;
- estão no mesmo ambiente;
- têm o mesmo ownership;
- precisam apenas de separação lógica.
Use database separado quando:
- muda o ambiente;
- muda o produto;
- muda o owner;
- muda o ciclo de backup/restore;
- muda o conjunto de permissões.
Convivência entre produtos¶
Produtos diferentes não devem acessar tabelas internas uns dos outros.
Ruim:
Produto B -> SELECT direto em product_a_prod.core.user_account
Bom:
Produto B -> API do Produto A
Produto A -> evento -> Produto B atualiza uma cópia local de leitura
Produto B -> valida claims recebidas em token emitido pelo Produto A
Se um produto precisar manter uma cópia local de leitura, deixe claro que é uma cópia, não a fonte oficial.
Exemplo:
create table external_user_snapshot (
user_id uuid not null,
display_name text not null,
status text not null,
updated_at timestamptz not null,
constraint pk_external_user_snapshot primary key (user_id)
);
Usuários e permissões¶
Use usuários técnicos separados por aplicação e ambiente.
Padrão:
| Usuário | Uso | Permissões |
|---|---|---|
*_app |
Runtime da aplicação. | SELECT, INSERT, UPDATE, DELETE apenas no schema necessário. |
*_migration |
Execução de migrations. | Permissões DDL controladas no schema da aplicação. |
Regras:
- usuário da aplicação não deve ser admin;
- usuário da aplicação não deve criar database;
- usuário da aplicação não deve criar schema;
- usuário da aplicação não deve criar extensão;
- usuário administrativo não deve ser usado pela aplicação;
- credenciais devem vir de secret manager ou variável segura;
- grants devem ser explícitos e revisáveis.
Exemplo:
revoke all on schema public from public;
create schema if not exists core;
grant usage on schema core to product_app;
grant select, insert, update, delete on all tables in schema core to product_app;
grant usage, select on all sequences in schema core to product_app;
grant usage, create on schema core to product_migration;
Schemas¶
Schemas devem usar snake_case.
Bom:
core
audit
identity
knowledge
Ruim:
public
schema1
ProductCore
backend
Evite usar public para tabelas da aplicação.
Tabelas¶
Tabelas devem usar snake_case, no singular e sem prefixo obrigatório.
Bom:
user_account
project
conversation
knowledge_source
Ruim:
tb_user
tbl_project
users
UserAccount
Colunas¶
Colunas devem usar snake_case e nomes claros.
Bom:
id
email
password_hash
status
created_at
updated_at
deleted_at
created_by
updated_by
Ruim:
usr_id
pwd
createdAt
DT_CREATE
flag1
Regras:
- não usar abreviações obscuras;
- não usar nomes genéricos sem contexto;
- booleanos devem expressar estado:
active,verified,locked; - timestamps devem indicar o evento:
created_at,expires_at,revoked_at.
Chaves primárias¶
Toda tabela deve ter chave primária explícita.
Nome padrão:
id
Tipos recomendados:
| Cenário | Tipo |
|---|---|
| IDs expostos em API ou sistemas distribuídos | uuid |
| Tabelas internas simples | bigint generated always as identity |
Exemplo:
id uuid not null
Chaves estrangeiras¶
Use foreign keys para integridade referencial dentro do mesmo produto e database.
Padrão:
<referenced_table>_id
Exemplo:
project_id uuid not null
Evite foreign key entre produtos diferentes.
Constraints¶
Constraints devem ter nomes explícitos.
| Tipo | Padrão | Exemplo |
|---|---|---|
| Primary key | pk_<table> |
pk_project |
| Foreign key | fk_<table>_<column> |
fk_conversation_project_id |
| Unique | uk_<table>_<column> |
uk_user_account_email |
| Check | ck_<table>_<rule> |
ck_project_status |
Exemplo:
constraint ck_project_status check (status in ('active', 'archived'))
Índices¶
Índices devem existir para consultas reais.
Padrão:
idx_<table>_<column_or_purpose>
Exemplos:
idx_project_owner_id_created_at
idx_conversation_project_id_updated_at
Regras:
- não criar índice sem necessidade conhecida;
- usar índice composto quando a consulta filtra por múltiplas colunas;
- considerar índice parcial para dados filtrados por estado;
- revisar índices não usados com métricas.
Timestamps¶
Use timestamptz para eventos reais.
Padrão mínimo:
created_at timestamptz not null
updated_at timestamptz not null
Opcional quando existir exclusão lógica:
deleted_at timestamptz null
Regras:
- armazenar em UTC;
- evitar
timestamp without time zonepara eventos reais; - usar
dateapenas para datas sem horário.
Dados sensíveis¶
Regras:
- nunca armazenar senha em texto puro;
- armazenar apenas hash forte de senha;
- não armazenar tokens sensíveis sem necessidade;
- quando armazenar token, prefira hash do token;
- não registrar dados sensíveis em logs;
- restringir acesso por role;
- não copiar produção para ambientes menores sem anonimização.
Bom:
password_hash text not null
integration_token_hash text not null
Ruim:
password text not null
integration_token text not null
Migrations¶
Toda alteração estrutural deve ser feita por migration versionada.
Ferramentas recomendadas:
- Flyway;
- Liquibase.
Padrão Flyway:
V1__create_project_table.sql
V2__create_conversation_table.sql
V3__add_status_to_project.sql
Regras:
- migration aplicada em produção não deve ser alterada;
- criar nova migration para novas mudanças;
- migrations devem ser pequenas e revisáveis;
- scripts destrutivos exigem plano de rollback.
Exemplo mínimo¶
create table project (
id uuid not null,
owner_user_id uuid not null,
name text not null,
status text not null,
created_at timestamptz not null,
updated_at timestamptz not null,
deleted_at timestamptz null,
constraint pk_project primary key (id),
constraint ck_project_status check (status in ('active', 'archived'))
);
create index idx_project_owner_id_created_at
on project (owner_user_id, created_at desc);
O que é proibido¶
- Usuário da aplicação com permissão administrativa.
- Senha em texto puro.
- Token sensível em texto puro.
- Tabelas da aplicação no schema
public. - Tabelas sem primary key.
- Migrations editadas depois de aplicadas.
select *em código de aplicação.- Dados sensíveis em logs ou dumps sem proteção.
- Acesso direto ao schema privado de outro produto.
- Produção e homologação compartilhando o mesmo database.
Checklist de revisão¶
- Database é separado por ambiente.
- Produto tem database próprio.
- Schemas têm nomes claros.
- Usuário da aplicação tem privilégio mínimo.
- Tabelas usam
snake_caseno singular. - Colunas têm nomes claros.
- Primary key está explícita.
- Constraints têm nomes explícitos.
- Índices têm justificativa.
- Timestamps usam
timestamptz. - Dados sensíveis estão protegidos.
- Migrations são versionadas e pequenas.