A fundação técnica: Git, open source, REST, GraphQL e MySQL
O que sustenta os projetos por baixo da interface, e as regras que adotei para cada camada depois de errar em todas elas.

Todo projeto neste portfólio tem uma interface que dá para ver e uma fundação que não dá. Este texto é sobre a fundação: versionamento, contribuição aberta, APIs e persistência.
Nada aqui é original. É o conjunto de práticas que eu passei a seguir depois de quebrar cada uma delas pelo menos uma vez.
Git: o histórico é documentação
Comecei usando Git como backup remoto. Commit único no fim do dia, mensagem update, push. Funciona até você precisar descobrir quando um comportamento mudou.
O que passei a fazer:
git switch -c feat/limiar-por-estacao
# trabalho em incrementos pequenos
git add -p
git commit -m "feat: limiar de cheia calibrado por estacao"
git push -u origin feat/limiar-por-estacaoTrês regras que valem mais que qualquer ferramenta:
- Uma branch por intenção. O nome da branch declara o que aquele conjunto de mudanças resolve.
- Commit que compila. Um commit que quebra o build é um ponto do histórico onde você não pode voltar, e um histórico onde não dá para voltar não serve para nada.
mainsempre publicável. Com deploy automático na Vercel, isso deixa de ser disciplina e vira consequência: o que entra emmainvai para produção.
O git add -p foi a mudança de hábito com melhor retorno. Ele obriga a olhar cada trecho antes de versionar, e é onde eu pego a maior parte dos console.log esquecidos.
Antes de abrir o merge
Um checklist curto, sempre o mesmo:
- Build passa
- Tipos passam sem
anynovo - Nenhum segredo no diff
- Mensagem descreve o porquê, não o o quê
Open source: publicar muda como você escreve
Meu primeiro repositório público foi o jSpoofer, um utilitário em JavaScript para automatizar o envio de assets no Roblox Studio, licenciado sob GPL-3.0.
O código era pior do que eu imaginava. Escrever sabendo que alguém vai ler é um filtro diferente de escrever para si mesmo. Nomes de variável melhoram, funções encolhem, e o README passa a existir.
Hoje mantenho também dois templates abertos, web-template e exe-template, que são a base de todo projeto novo em Next.js e TypeScript. Manter isso público tem um efeito prático: o padrão não pode ser negociado projeto a projeto, porque ele mora num lugar só.
Escolher a licença faz parte do trabalho. GPL-3.0 obriga trabalhos derivados a permanecerem abertos; MIT não obriga nada. Nenhuma das duas é a certa por padrão. A pergunta é o que você quer que aconteça com o seu código depois.
REST: o contrato importa mais que o verbo
A maior parte das integrações que eu faço é REST. No Mundaú Sentinela, os dados de estação e a previsão de cheia vêm de endpoints públicos consultados de hora em hora.
O que aprendi consumindo API dos outros, aplicado quando eu projeto a minha:
- Status code honesto.
200com{"error": ...}no corpo obriga todo cliente a reimplementar tratamento de erro. - Paginação desde o primeiro dia. Adicionar depois é mudança quebrando contrato.
- Formato de data em ISO 8601 com fuso.
2026-08-11T14:30:00Znão tem ambiguidade;11/08/2026 14:30tem duas. - Nunca confiar em quem responde. Timeout, retry com espera crescente e um caminho de degradação para quando a fonte estiver fora.
Esse último ponto é o que separa integração de demonstração. Uma plataforma de alerta de cheia que fica em branco porque a API da fonte caiu falhou justamente quando importava.
GraphQL: resolve overfetching, cria outros problemas
GraphQL entra quando o cliente precisa de recortes diferentes dos mesmos dados. Em vez de multiplicar endpoints, o cliente declara o que quer:
query PainelEstacao($id: ID!) {
estacao(id: $id) {
nome
nivelAtual
limiares { atencao alerta inundacao }
leituras(ultimas: 72) { instante centimetros }
}
}Uma requisição, exatamente os campos usados. O ganho é real em tela composta, onde a alternativa é encadear três chamadas REST.
O que não contam junto:
- Cache fica mais difícil. REST cacheia por URL de graça. Em GraphQL, tudo é
POSTpara o mesmo endpoint. - Consulta aninhada demais derruba o servidor. Sem limite de profundidade e de complexidade, o cliente escreve a própria negação de serviço.
- Um resolver ingênuo gera N+1. Buscar uma lista e depois consultar o banco uma vez por item é o erro clássico, e ele só aparece sob carga.
Minha regra prática: REST para leitura pública e cacheável, GraphQL quando a tela agrega muitas entidades relacionadas. Usar os dois não é indecisão; é escolher a ferramenta por tipo de acesso.
MySQL: o esquema é a parte que você não refaz
Firebase resolve bem parte dos meus projetos. Quando o dado é relacional de verdade (usuário, categoria, lançamento, recorrência, como no Paycel), o modelo relacional é mais honesto.
O que eu trato como não negociável:
CREATE TABLE lancamento (
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
usuario_id BIGINT UNSIGNED NOT NULL,
categoria_id BIGINT UNSIGNED NOT NULL,
valor_centavos INT NOT NULL,
ocorrido_em DATE NOT NULL,
criado_em TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT fk_lancamento_usuario
FOREIGN KEY (usuario_id) REFERENCES usuario(id) ON DELETE CASCADE,
INDEX idx_lancamento_usuario_data (usuario_id, ocorrido_em)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;Cinco decisões embutidas aí:
- Dinheiro em inteiro de centavos.
FLOATpara valor monetário acumula erro de arredondamento. Não é opinião. - Chave estrangeira declarada. Integridade referencial no banco, não na camada de aplicação, que é onde ela vaza.
- Índice composto na consulta real. A pergunta é sempre “lançamentos deste usuário neste período”, e o índice espelha exatamente isso.
utf8mb4.utf8do MySQL não cobre todo o Unicode. Acento e emoji quebram.- Migração versionada. Alteração de esquema é código, entra em Git e é revisada como código.
O índice composto é o que mais rende. Uma consulta que varre a tabela inteira parece instantânea com quinhentas linhas e trava com quinhentas mil, e o momento em que você descobre isso é sempre em produção.
O fio comum
As quatro camadas seguem a mesma ideia: deixar o sistema explícito sobre o que ele garante.
Git torna explícito o que mudou e por quê. Licença open source torna explícito o que pode ser feito com o código. Contrato de API torna explícito o que o cliente pode esperar. Esquema de banco torna explícito o que é dado válido.
Sistema que não declara as próprias garantias funciona por coincidência. Funciona, até parar.
Continue lendo
- 6 min
SAML: reconstruindo o futebol competitivo do Roblox do zero
Como e por que estou reescrevendo o padrão MPS com uma camada de rede binária própria, física customizada e um sistema de balanceamento centralizado. - 3 min
Mundaú Sentinela: dado hidrológico público não é aviso de cheia
Os dados da bacia do Mundaú já existiam e eram abertos. O que faltava era alguém traduzir número de cota em decisão de quem mora na margem. - 3 min
Guardião da Praia: moderação é a parte difícil da ciência cidadã
Coletar registro de poluição costeira é trivial. Fazer com que esse registro sirva a pesquisador e a órgão ambiental é um problema de confiança, não de formulário.