Pular para conteúdo

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 zone para eventos reais;
  • usar date apenas 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_case no 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.