devolucao/
├── src/
│ ├── domain/ # Camada de Domínio
│ │ ├── entities/
│ │ │ └── devolucao.py # Entidade Devolucao com validações
│ │ └── repositories/
│ │ └── devolucao_repository.py # Interface do repositório (Port)
│ │
│ ├── application/ # Camada de Aplicação
│ │ ├── use_cases/
│ │ │ └── devolucao_use_cases.py # 7 casos de uso implementados
│ │ └── schemas/
│ │ └── devolucao_schema.py # Schemas Pydantic
│ │
│ ├── infrastructure/ # Camada de Infraestrutura
│ │ ├── database/
│ │ │ ├── config.py # Configuração SQLAlchemy
│ │ │ └── models.py # Modelo ORM DevolucaoModel
│ │ └── repositories/
│ │ └── devolucao_repository_impl.py # Implementação concreta
│ │
│ └── presentation/ # Camada de Apresentação
│ └── api/
│ └── routes/
│ └── devolucao_routes.py # Endpoints FastAPI
└── __init__.py # Torna devolucao um módulo Python
- Dataclass com todos os atributos necessários
- Validações de negócio no
__post_init__:reclamante_id: deve ser um número positivoitem_id: deve ser um número positivoobservacao: não pode ser vazia
data_devolucaocomdefault_factory=datetime.now(registra data/hora atual automaticamente)- Método de domínio:
atualizar_observacao()- Atualiza a observação com validação
- Independente de frameworks
- Abstração (Port) para acesso a dados
- Métodos definidos:
create()- Criar devoluçãoget_by_id()- Buscar por IDget_all()- Listar todos (com paginação)update()- Atualizardelete()- Deletarget_by_data()- Buscar por datacount()- Contar total de registros
7 casos de uso implementados:
CreateDevolucaoUseCase- Criar nova devoluçãoGetDevolucaoByIdUseCase- Buscar devolução por IDGetAllDevolucoesUseCase- Listar todas as devoluções (com validação de paginação)UpdateDevolucaoUseCase- Atualizar devolução existenteDeleteDevolucaoUseCase- Deletar devoluçãoGetDevolucoesByDataUseCase- Buscar devoluções por dataCountDevolucoesUseCase- Contar total de devoluções
DevolucaoBase- Schema base com campos comunsDevolucaoCreate- Para criação (herda de DevolucaoBase)DevolucaoUpdate- Para atualização completa PUT (herda de DevolucaoBase)DevolucaoPatch- Para atualização parcial PATCH (campos opcionais)DevolucaoResponse- Para resposta da API (incluiid,created_at,updated_at)DevolucaoListResponse- Para listagem paginada
- Setup do SQLAlchemy com async
- Engine assíncrono para banco SQLite separado (
devolucao.db) - Session maker específico com
async_sessionmaker - Função
get_session()para dependency injection - Função
init_db()para criar tabelas
DevolucaoModel- Modelo SQLAlchemy- Mapeamento completo da tabela
devolucoes - Importa
Basedo próprio módulodevolucao(banco isolado) - Campos:
id- INTEGER PRIMARY KEY AUTOINCREMENTdata_devolucao- DATETIME NOT NULLobservacao- TEXT NOT NULLreclamante_id- INTEGER NOT NULLitem_id- INTEGER NOT NULLcreated_at- DATETIME comserver_default=func.now()updated_at- DATETIME comonupdate=func.now()
- Implementação concreta de
DevolucaoRepository - Conversões entre Entity e Model:
_model_to_entity()- ORM → Domain_entity_to_model()- Domain → ORM
- Implementação de todos os métodos da interface
get_by_data()usafunc.date()para comparar apenas a parte da data (sem hora)- Uso de SQLAlchemy async com
select,func.count()
Endpoints REST implementados:
| Método | Endpoint | Descrição |
|---|---|---|
| POST | /api/v1/devolucoes/ |
Criar nova devolução |
| GET | /api/v1/devolucoes/ |
Listar todas (paginado) |
| GET | /api/v1/devolucoes/data/{data} |
Buscar por data |
| GET | /api/v1/devolucoes/{id} |
Buscar devolução por ID |
| PUT | /api/v1/devolucoes/{id} |
Atualizar devolução (completa) |
| PATCH | /api/v1/devolucoes/{id} |
Atualização parcial |
| DELETE | /api/v1/devolucoes/{id} |
Deletar devolução |
Características:
- Dependency Injection do repositório via
Depends(get_session) - Tratamento de erros com
HTTPException - Validação automática via Pydantic
- Documentação automática (OpenAPI/Swagger)
- PATCH reutiliza
UpdateDevolucaoUseCasecom merge dos campos na camada de apresentação
- Importação do módulo
devolucao - Lifespan atualizado para inicializar os quatro bancos:
init_db_item()- Banco de itemsinit_db_responsavel()- Banco de responsaveisinit_db_local()- Banco de locaisinit_db_devolucao()- Banco de devoluções
- Inclusão das rotas de devolução
- Prefixo:
/api/v1/devolucoes
def __post_init__(self):
if self.reclamante_id <= 0:
raise ValueError("O ID do reclamante deve ser um número positivo.")
if self.item_id <= 0:
raise ValueError("O ID do item deve ser um número positivo.")
if not self.observacao or len(self.observacao.strip()) == 0:
raise ValueError("A observação é obrigatória.")class DevolucaoBase(BaseModel):
reclamante_id: int = Field(..., gt=0)
item_id: int = Field(..., gt=0)
observacao: str = Field(..., min_length=1, max_length=255)
data_devolucao: datetime = Field(default_factory=datetime.now)# CreateDevolucaoUseCase / UpdateDevolucaoUseCase
if devolucao.data_devolucao > datetime.now():
raise ValueError("Data da devolução não pode ser no futuro")
# GetDevolucaoByIdUseCase
if devolucao_id <= 0:
raise ValueError("ID da devolução deve ser maior que zero")
# GetAllDevolucoesUseCase
if skip < 0:
raise ValueError("Skip não pode ser negativo")
if limit <= 0 or limit > 1000:
raise ValueError("Limit deve estar entre 1 e 1000")
# GetDevolucoesByDataUseCase
if not data:
raise ValueError("Data não pode ser nula")poetry run uvicorn main:app --reload --port 5003- Swagger UI: http://localhost:5003/docs
- ReDoc: http://localhost:5003/redoc
curl -X POST "http://localhost:5003/api/v1/devolucoes/" \
-H "Content-Type: application/json" \
-d '{
"reclamante_id": 1,
"item_id": 1,
"observacao": "Item devolvido ao proprietário após verificação de identidade"
}'Resposta:
{
"id": 1,
"reclamante_id": 1,
"item_id": 1,
"observacao": "Item devolvido ao proprietário após verificação de identidade",
"data_devolucao": "2026-03-07T14:30:00",
"created_at": "2026-03-07T14:30:00",
"updated_at": null
}curl -X GET "http://localhost:5003/api/v1/devolucoes/?skip=0&limit=10"Resposta:
{
"devolucoes": [
{
"id": 1,
"reclamante_id": 1,
"item_id": 1,
"observacao": "Item devolvido ao proprietário após verificação de identidade",
"data_devolucao": "2026-03-07T14:30:00",
"created_at": "2026-03-07T14:30:00",
"updated_at": null
}
],
"total": 1,
"skip": 0,
"limit": 10
}curl -X GET "http://localhost:5003/api/v1/devolucoes/1"curl -X GET "http://localhost:5003/api/v1/devolucoes/data/2026-03-07T00:00:00"curl -X PUT "http://localhost:5003/api/v1/devolucoes/1" \
-H "Content-Type: application/json" \
-d '{
"reclamante_id": 1,
"item_id": 1,
"observacao": "Observação atualizada com mais detalhes da devolução",
"data_devolucao": "2026-03-07T15:00:00"
}'curl -X PATCH "http://localhost:5003/api/v1/devolucoes/1" \
-H "Content-Type: application/json" \
-d '{
"observacao": "Apenas a observação foi atualizada"
}'curl -X DELETE "http://localhost:5003/api/v1/devolucoes/1"- Item:
achados_perdidos.db - Responsavel:
responsavel.db - Local:
local.db - Devolucao:
devolucao.db
Devolucaoé a entidade de maior dependência do sistema: relaciona-se comItem(viaitem_id) e comReclamante(viareclamante_id)- As Foreign Keys estão temporariamente como campos INTEGER simples, a serem adicionadas quando a entidade
Reclamantefor implementada
data_devolucaousadefault_factory=datetime.now— ao criar uma devolução sem informar a data, é registrado o momento atual automaticamente
get_by_data()compara apenas a parte da data (sem hora) usandofunc.date(), permitindo buscar todas as devoluções de um determinado dia
- A data da devolução não pode ser futura — validada no
CreateDevolucaoUseCaseeUpdateDevolucaoUseCase
Quando as entidades forem relacionadas:
# Em devolucao/src/infrastructure/database/models.py
reclamante_id = Column(Integer, ForeignKey('reclamantes.id'), nullable=False)
item_id = Column(Integer, ForeignKey('items.id'), nullable=False)# Em CreateDevolucaoUseCase
async def execute(self, devolucao: Devolucao, item_repository, reclamante_repository):
item = await item_repository.get_by_id(devolucao.item_id)
if not item:
raise ValueError("Item não encontrado")
if item.status != 'disponivel':
raise ValueError("Item não está disponível para devolução")
reclamante = await reclamante_repository.get_by_id(devolucao.reclamante_id)
if not reclamante:
raise ValueError("Reclamante não encontrado")
# Marca o item como devolvido
item.marcar_como_devolvido()
await item_repository.update(item.id, item)
return await self.repository.create(devolucao)class DevolucaoResponseCompleta(BaseModel):
id: int
item: ItemResponse
reclamante: ReclamanteResponse
observacao: str
data_devolucao: datetime
created_at: datetime
updated_at: Optional[datetime]- Separação em camadas: Domain, Application, Infrastructure, Presentation
- Regra de dependência: Camadas internas não conhecem externas
- Inversão de dependências: Use cases dependem de interfaces, não implementações
- Single Responsibility: Cada classe tem uma única responsabilidade
- Open/Closed: Aberto para extensão, fechado para modificação
- Liskov Substitution: Implementações substituíveis pela interface
- Interface Segregation: Interface específica e enxuta
- Dependency Inversion: Dependência de abstrações, não concretizações
- Repository Pattern: Abstração de acesso a dados
- Dependency Injection: Injeção de dependências via FastAPI
- DTO (Data Transfer Object): Schemas Pydantic
- Use Case Pattern: Encapsulamento de lógica de aplicação
- PUT vs PATCH: Uso semântico correto
- PUT: Atualização completa (todos os campos obrigatórios)
- PATCH: Atualização parcial (campos opcionais, merge na camada de apresentação)
- Resource-Oriented: URLs representam recursos (
/api/v1/devolucoes/) - HTTP Status Codes: Uso apropriado (200, 201, 204, 400, 404)
devolucao/__init__.py
devolucao/src/__init__.py
devolucao/src/domain/__init__.py
devolucao/src/domain/entities/__init__.py
devolucao/src/domain/entities/devolucao.py
devolucao/src/domain/repositories/__init__.py
devolucao/src/domain/repositories/devolucao_repository.py
devolucao/src/application/__init__.py
devolucao/src/application/schemas/__init__.py
devolucao/src/application/schemas/devolucao_schema.py
devolucao/src/application/use_cases/__init__.py
devolucao/src/application/use_cases/devolucao_use_cases.py
devolucao/src/infrastructure/__init__.py
devolucao/src/infrastructure/database/__init__.py
devolucao/src/infrastructure/database/config.py
devolucao/src/infrastructure/database/models.py
devolucao/src/infrastructure/repositories/__init__.py
devolucao/src/infrastructure/repositories/devolucao_repository_impl.py
devolucao/src/presentation/__init__.py
devolucao/src/presentation/api/__init__.py
devolucao/src/presentation/api/routes/__init__.py
devolucao/src/presentation/api/routes/devolucao_routes.py
docs/ENTIDADE-DEVOLUCAO.md
main.py # Inclusão de rotas e lifespan para init_db_devolucao()
- FastAPI Documentation
- SQLAlchemy Documentation
- Clean Architecture (Robert C. Martin)
- Pydantic Documentation
Grupo Ditko.br Projeto Frameworks Full Stack - Prof. Giovani Bontempo - Faculdade Impacta
Data de Implementação: 7 de Março de 2026