Cities
# Cities
Este documento descreve todas as operações disponíveis para o agregado Cities e seus recursos, seguindo os padrões de Domain-Driven Design (DDD) e Command Query Responsibility Segregation (CQRS).
Índice
- Cities
- Índice
- Cities (Cidades)
- Conceitos de DDD e CQRS
- Relacionamentos
- Validações de Domínio
- Observações Importantes
Cities (Cidades)
Visão Geral
O agregado City representa as cidades/localidades disponíveis no sistema para prestação de serviços. As cidades podem ser associadas a: - Trabalhos disponíveis (JobCities) - Tarefas específicas de trabalho (JobTaskCities) - Áreas de atuação de profissionais (ProfessionalUserCities) - Endereços de usuários (UserAddresses) - Itens de solicitação (RequestItems)
Commands (Comandos)
1. Criação de Cidade (CreateCity)
Contrato: CreateCityCommand
Campos Necessários:
Name(string, obrigatório) - Nome da cidadeState(string, obrigatório) - Estado/UF da cidadeIsActive(bool, obrigatório) - Indica se a cidade está ativaAuthor(string, opcional) - Autor da operação
Validações:
Name: Não pode ser vazio; Tamanho máximo: 99 caracteresState: Não pode ser vazio; Tamanho máximo: 99 caracteresIsActive: Não pode ser vazio
Retorno: CreateCityResponse
- Id (Guid) - Identificador da cidade criada
Handler: CreateCityHandler
Eventos de Domínio:
CityCreatedEvent- Disparado quando uma cidade é criada (se implementado)
Regras de Negócio:
- Não é permitido criar cidades duplicadas (verificação baseada no nome)
- O nome e estado são automaticamente convertidos para maiúsculas
- O estado deve ser uma UF válida brasileira (validação através de
Address.StateIsValid()) - Estados aceitos: AC, AL, AP, AM, BA, CE, DF, ES, GO, MA, MT, MS, MG, PA, PB, PR, PE, PI, RJ, RN, RS, RO, RR, SC, SP, SE, TO
- Se o estado for inválido, retorna mensagem: "Invalid state. State must be one of the following: [lista de UFs]"
- Cidades inativas não são elegíveis para solicitações de serviço
- A cidade criada fica imediatamente disponível para associação com jobs e profissionais
- Se tentar criar uma cidade que já existe, lança exceção
AlreadyExistsException
Exemplo de Uso:
{
"name": "São Paulo",
"state": "SP",
"isActive": true,
"author": "admin@sistema.com"
}
Exemplo de Resposta:
{
"id": "123e4567-e89b-12d3-a456-426614174000"
}
Nota: Nome e estado serão armazenados como "SÃO PAULO" e "SP" (maiúsculas).
2. Exclusão de Cidade (DeleteCity)
Contrato: DeleteCityCommand
Campos Necessários:
Id(Guid, obrigatório) - Identificador da cidade
Validações:
Id: Não pode ser vazio
Retorno: Void
Handler: DeleteCityHandler
Regras de Negócio:
- A cidade deve existir no sistema
- Verifica se há dependências antes de excluir:
- JobCities (cidades associadas a trabalhos)
- JobTaskCities (cidades associadas a tarefas)
- ProfessionalUserCities (áreas de atuação de profissionais)
- ProfessionalUserAddresses (endereços de profissionais)
- UserAddresses (endereços de usuários)
- RequestItems (itens de solicitação)
- Se houver dependências, a exclusão pode ser impedida
Recomendação: Considere usar inativação (IsActive = false) em vez de exclusão para manter integridade histórica.
3. Atualização de Cidade (UpdateCity)
Contrato: UpdateCityCommand
Campos Necessários:
Id(Guid, obrigatório) - Identificador da cidade (JsonIgnore)Name(string, obrigatório) - Nome da cidadeState(string, obrigatório) - Estado/UF da cidadeIsActive(bool, obrigatório) - Indica se a cidade está ativaObservation(string, opcional) - Observações adicionaisAuthor(string, opcional) - Autor da operação
Validações:
Id: Não pode ser vazio; Cidade deve existirName: Não pode ser vazio; Tamanho máximo: 99 caracteresState: Não pode ser vazio; Tamanho máximo: 99 caracteres; Deve ser UF válidaIsActive: Não pode ser vazio
Retorno: Void
Handler: UpdateCityHandler
Regras de Negócio:
- A cidade deve existir no sistema
- O nome e estado são automaticamente convertidos para maiúsculas
- O estado deve ser uma UF válida brasileira
- Atualizar
IsActiveparafalsedesativa a cidade para novas solicitações - Cidades com pedidos em andamento devem permanecer ativas até conclusão
Exemplo de Uso:
{
"name": "São Paulo",
"state": "SP",
"isActive": false,
"observation": "Cidade temporariamente desativada",
"author": "admin@sistema.com"
}
Queries (Consultas)
1. Buscar Cidade por ID (GetCityById)
Contrato: GetCityByIdQuery
Campos Necessários:
Id(Guid, obrigatório) - Identificador da cidade
Retorno: GetCityByIdResponse
- Id (Guid) - Identificador da cidade
- Name (string) - Nome da cidade
- State (string) - Estado/UF
- IsActive (bool) - Status ativo/inativo
- CreatedAt (DateTime) - Data de criação
- UpdatedAt (DateTime?) - Data da última atualização
- AuthorCreated (string) - Autor da criação
- AuthorUpdated (string) - Autor da última atualização
Handler: GetCityByIdHandler
Mapper: GetCityByIdMapper
Descrição:
- Retorna todos os dados da cidade especificada
- Inclui informações de auditoria (datas e autores)
- Se a cidade não existir, lança exceção NotFound
Regras de Negócio:
- Retorna todos os dados da cidade
- Inclui informações de auditoria
- Se a cidade não existir, lança exceção NotFound
Exemplo de Resposta:
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"name": "SÃO PAULO",
"state": "SP",
"isActive": true,
"createdAt": "2025-01-08T10:30:00Z",
"updatedAt": "2025-01-08T15:45:00Z",
"authorCreated": "admin@sistema.com",
"authorUpdated": null
}
2. Pesquisar Cidades (SearchCities)
Contrato: SearchCitiesQuery
Campos Opcionais:
- State (string, opcional) - Filtrar por estado/UF
- Name (string, opcional) - Filtrar por nome da cidade
- IsActive (bool?, opcional) - Filtrar por status ativo/inativo
- PostalCode (string, opcional) - Filtrar por CEP
- JobId (Guid?, opcional) - Filtrar cidades associadas a um trabalho específico
- JobTaskId (Guid?, opcional) - Filtrar cidades associadas a uma tarefa específica
Retorno: SearchCitiesResponse
- Lista de cidades que atendem aos critérios de filtro
- Cada item contém os dados completos da cidade
Descrição:
- Retorna uma lista de cidades conforme os filtros aplicados
- Permite busca por estado, nome, status e associações com jobs
Handler: SearchCitiesHandler
Mapper: SearchCitiesMapper
Regras de Negócio:
- Quando nenhum filtro é fornecido, retorna todas as cidades ativas
State: Busca exata, case-insensitiveName: Realiza busca parcial, case-insensitive (LIKE)IsActive:true- apenas cidades ativasfalse- apenas cidades inativasnull- todas as cidadesPostalCode: Busca cidades que atendem um CEP específicoJobId: Retorna cidades onde um trabalho específico está disponívelJobTaskId: Retorna cidades onde uma tarefa específica pode ser executada- Filtros podem ser combinados para buscas mais específicas
Exemplo de Uso:
// Buscar todas as cidades ativas de São Paulo
{
"state": "SP",
"isActive": true
}
// Buscar cidades por nome parcial
{
"name": "Santo"
}
// Buscar cidades onde um job está disponível
{
"jobId": "123e4567-e89b-12d3-a456-426614174000"
}
Exemplo de Resposta:
{
"cities": [
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"name": "SÃO PAULO",
"state": "SP",
"isActive": true,
"createdAt": "2025-01-08T10:30:00Z"
},
{
"id": "456e7890-e12b-34d5-b678-901234567890",
"name": "SANTO ANDRÉ",
"state": "SP",
"isActive": true,
"createdAt": "2025-01-07T09:15:00Z"
},
{
"id": "789fabcd-e34f-56a7-c890-123456789012",
"name": "SANTOS",
"state": "SP",
"isActive": true,
"createdAt": "2025-01-06T14:20:00Z"
}
]
}
Conceitos de DDD e CQRS
Domain-Driven Design (DDD)
Aggregate Root:
- City é um agregado raiz independente
- Mantém consistência de suas propriedades
- Possui coleções de entidades relacionadas (JobCities, JobTaskCities, ProfessionalUserCities, ProfessionalUserAddresses, UserAddresses, RequestItems)
- Constantes de domínio:
- MaxNameLength = 99
- MaxStateLength = 2
Value Objects:
- Author - Representa o autor da operação
Domain Methods:
- Validate() - Valida se a cidade está ativa e elegível para solicitações
- Lança RuleViolationDomainException se a cidade não estiver ativa
Invariantes: - Nome não pode exceder 99 caracteres - Estado não pode exceder 2 caracteres e deve ser uma UF válida - Nome e estado são convertidos para maiúsculas - Cidade deve estar ativa para aceitar solicitações
Domain Exceptions:
- RuleViolationDomainException - Quando regras de negócio são violadas
- AlreadyExistsDomainException - Quando tenta criar cidade duplicada
- NotFoundDomainException - Quando cidade não é encontrada
CQRS (Command Query Responsibility Segregation)
Commands (Comandos):
- CreateCityCommand - Cria uma nova cidade
- DeleteCityCommand - Remove uma cidade existente
- Todos os comandos passam por validação (FluentValidation)
- Cada comando tem um handler dedicado que executa a lógica de negócio
- Comandos modificam o estado do sistema
Queries (Consultas):
- GetCityByIdQuery - Busca uma cidade específica
- SearchCitiesQuery - Pesquisa cidades com filtros
- Queries são otimizadas para leitura
- Não modificam o estado do sistema
- Cada query tem um handler e mapper dedicados
- Podem incluir joins com outras entidades para otimização
Validators:
- CreateCityValidator - Valida dados de criação
- DeleteCityValidator - Valida dados de exclusão
- Utilizam FluentValidation para regras declarativas
Relacionamentos
JobCity
Representa a associação entre uma cidade e um trabalho disponível. - Um trabalho pode estar disponível em múltiplas cidades - Define a área de cobertura do serviço
JobTaskCity
Representa a associação entre uma cidade e uma tarefa específica. - Permite granularidade maior: algumas tarefas podem não estar disponíveis em todas as cidades de um job - Controla disponibilidade regional de serviços específicos
ProfessionalUserCity
Representa áreas de atuação de profissionais. - Define em quais cidades o profissional presta serviço - Usado para matching geográfico
ProfessionalUserAddress
Endereços de profissionais vinculados a cidades. - Todo endereço de profissional está associado a uma cidade - Usado para validação geográfica e cálculo de distância para serviços
UserAddress
Endereços de usuários vinculados a cidades. - Todo endereço está associado a uma cidade - Usado para validar elegibilidade de serviços
RequestItem
Itens de solicitação vinculados a cidades. - Cada solicitação é feita para uma cidade específica - A cidade deve estar ativa e associada ao job solicitado
Validações de Domínio
Método Validate()
public void Validate()
{
if (!IsActive)
{
throw new RuleViolationDomainException("City not eligible for requests.");
}
}
Este método é chamado durante o processamento de solicitações para garantir que apenas cidades ativas aceitem novos pedidos.
Observações Importantes
- Normalização de Dados: Nome e estado são convertidos para maiúsculas automaticamente para consistência
- Auditoria: Todas as operações registram autor e data
- Status Ativo: Apenas cidades ativas podem:
- Receber novas solicitações
- Ser associadas a novos jobs
- Aparecer em buscas padrão de usuários
- Integridade Referencial: Verifique dependências antes de excluir
- Unicidade: Sistema previne criação de cidades duplicadas
- Granularidade Regional:
- Use JobCity para disponibilidade geral do trabalho
- Use JobTaskCity quando tarefas específicas têm disponibilidade regional diferente
- CEP: O filtro por PostalCode requer integração com sistema de endereços/CEPs