Criar um domínio no back¶
Molde: app/domains/users/.
Abra os arquivos dele lado a lado com os seus durante todo o caminho. No fim, a
diferença entre os dois deve ser só o assunto.
Regras que mandam: Backend · Banco e migrations · Testes.
Passo 0 — os campos existem?¶
Antes de qualquer código. O que a tabela guarda é decisão de produto:
| Você tem | Caminho |
|---|---|
| Subtarefa com os campos | siga; ela é a fonte |
| Subtarefa sem os campos | volte para quem publicou — a subtarefa não passou na Definition of Ready |
| Um campo que você acha que falta | é premissa: registre antes de criar a coluna |
Copie do molde a forma, nunca os campos. Coluna inventada vira migration, e migration vira dado.
A ordem¶
models.py— a tabela. Classe no singular (Insight), tabela no plural (insights).- Registre o model em
app/models.py, uma linha em ordem alfabética. 🔒 O teste de arquitetura reprova o domínio que ficar de fora — e sem o registro o autogenerate do Alembic não enxerga a tabela. - Migration temporária, para testar no seu banco — ver Mudar o banco numa tarefa. Ela não vai para o PR.
schemas.py— um schema por direção (<Entidade>Create,<Entidade>Response), cada campo comField(description=..., examples=[...]), e o@classmethod de_model()no schema de saída.repository.py— classe que recebe a sessão no construtor. Consulta, agrega, grava comflush(). Não achou? DevolveNone. Nuncacommit(), nunca erro de domínio. 🔒service.py— classe que recebe o repository no construtor. A regra de negócio mora aqui, e o erro é deapp/shared/exceptions.py. Semfastapi, semsqlalchemy. 🔒dependencies.py— a cadeiaSessionDep→ repository → service, exportandoServiceDep. Copie a forma do molde.router.py— recebe, valida pelo schema, chama o service, traduz o erro de domínio emHTTPException. Toda rota comsummary,description,operation_ide as respostas de erro emresponses=🔒. Sem importarmodels🔒.- Registre o router na tupla do
for _router in (...)deapp/main.py, e a tag do domínio, com descrição, emOPENAPI_TAGSno mesmo arquivo 🔒. - Testes em
tests/domains/<nome>/:test_service.pycom repository falso,test_router.pycom service falso (Testes).
utils.py (cálculo puro) e constants.py (número com significado) nascem só quando
houver o que pôr dentro.
Precisa de dado de outro domínio?¶
Use o service do dono, recebido em dependencies.py — como o users faz com o
LinkService. E declare a composição em COMPOE_COM_SERVICE_DE, em
tests/test_arquitetura.py, com o motivo. Sem a declaração, o CI falha 🔒.
Fatie¶
Domínio inteiro num diff só é irrevisável. Corte por fatia vertical: model + o primeiro caso de uso de ponta a ponta numa subtarefa; os demais endpoints depois, um por vez. Não corte por camada ("uma task para os schemas, outra para o service"): uma task que não entrega comportamento não dá para testar.
Antes de fechar¶
ruff check . && ruff format --check .
mypy app
pytest tests/domains/<nome> -q
pytest tests/test_arquitetura.py tests/test_openapi.py -q
pytest
E a checagem que nenhum comando faz: abra o seu domínio e o users lado a lado. A
diferença deve ser só o assunto.