Jobs
Este documento descreve todas as operações disponíveis para o agregado Job e seus sub-recursos, seguindo os padrões de Domain-Driven Design (DDD) e Command Query Responsibility Segregation (CQRS).
Índice
- Jobs (Trabalhos)
- Commands: CreateJob, DeleteJob, UpdateJob
- Queries: GetJobById, SearchJobs
- JobTasks (Tarefas de Trabalho)
- Commands: CreateJobTask, DeleteJobTask, UpdateJobTask
- Queries: GetJobTaskById, SearchJobTasks
- JobCities (Cidades do Trabalho)
- JobTaskCities (Cidades da Tarefa)
- JobTaskSkills (Habilidades da Tarefa)
- JobTaskEstimates (Estimativas da Tarefa)
- JobPackages (Pacotes de Trabalho)
- JobPackageTasks (Tarefas do Pacote)
- Value Objects
- Conceitos de DDD e CQRS
Jobs (Trabalhos)
Visão Geral
O agregado Job representa categorias principais de serviços disponíveis no sistema (ex: Eletricista, Encanador, Pintor). Um Job contém múltiplas JobTasks (tarefas específicas) e pode estar disponível em várias cidades.
Commands (Comandos)
1. Criação de Trabalho (CreateJob)
Contrato: CreateJobCommand
Campos Necessários:
Name(string, obrigatório) - Nome do trabalhoDetails(string, obrigatório) - Descrição detalhada do trabalhoIsActive(bool, obrigatório) - Indica se o trabalho está ativoAuthor(string, opcional) - Autor da operação
Validações:
Name: Não pode ser vazio; Tamanho máximo: 99 caracteresDetails: Não pode ser vazio; Tamanho máximo: 500 caracteresIsActive: Não pode ser vazio
Retorno: CreateJobResponse
- Id (Guid) - Identificador do trabalho criado
Handler: CreateJobHandler
Eventos de Domínio:
JobCreatedEvent- Disparado quando um trabalho é criado (se implementado)
Regras de Negócio:
- Um trabalho representa uma categoria principal de serviço
- Trabalhos inativos não aparecem em buscas públicas
- Após criar o trabalho, é necessário:
- Adicionar JobTasks (tarefas específicas)
- Associar cidades onde o trabalho está disponível (JobCities)
Exemplo de Uso:
{
"name": "Serviços Elétricos",
"details": "Instalação, manutenção e reparo de sistemas elétricos residenciais e comerciais",
"isActive": true,
"author": "admin@sistema.com"
}
2. Exclusão de Trabalho (DeleteJob)
Contrato: DeleteJobCommand
Campos Necessários:
Id(Guid, obrigatório) - Identificador do trabalho
Validações:
Id: Não pode ser vazio
Retorno: Void
Handler: DeleteJobHandler
Regras de Negócio:
- O trabalho deve existir no sistema
- Verifica dependências antes de excluir:
- JobTasks associadas
- JobCities associadas
- Requests vinculadas ao trabalho
3. Atualização de Trabalho (UpdateJob)
Contrato: UpdateJobCommand
Campos Necessários:
Id(Guid, obrigatório) - Identificador do trabalho (JsonIgnore)Name(string, obrigatório) - Nome do trabalhoDetails(string, obrigatório) - Descrição detalhada do trabalhoIsActive(bool, obrigatório) - Indica se o trabalho está ativoObservation(string, opcional) - Observações adicionaisAuthor(string, opcional) - Autor da operação
Validações:
Id: Não pode ser vazio; Trabalho deve existirName: Não pode ser vazio; Tamanho máximo: 99 caracteresDetails: Não pode ser vazio; Tamanho máximo: 500 caracteresIsActive: Não pode ser vazio
Retorno: Void
Handler: UpdateJobHandler
Regras de Negócio:
- O trabalho deve existir no sistema
- Atualizar
IsActiveparafalseoculta o trabalho de buscas públicas - Trabalhos com solicitações em andamento devem permanecer ativos
Exemplo de Uso:
{
"name": "Serviços Elétricos Residenciais",
"details": "Instalação, manutenção e reparo de sistemas elétricos residenciais",
"isActive": true,
"observation": "Nome atualizado para maior clareza",
"author": "admin@sistema.com"
}
Queries (Consultas)
1. Buscar Trabalho por ID (GetJobById)
Contrato: GetJobByIdQuery
Campos Necessários:
Id(Guid, obrigatório) - Identificador do trabalho
Retorno: GetJobByIdResponse
- Dados completos do trabalho incluindo tarefas, cidades e pacotes
Handler: GetJobByIdHandler
Mapper: GetJobByIdMapper
Descrição:
- Retorna todos os dados do trabalho especificado
- Inclui informações de tarefas, cidades e pacotes associados
Exemplo de Resposta:
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"name": "Serviços Elétricos",
"details": "Instalação, manutenção e reparo de sistemas elétricos residenciais e comerciais",
"isActive": true,
"createdAt": "2025-01-08T10:00:00Z",
"updatedAt": null,
"authorCreated": "admin@sistema.com"
}
2. Pesquisar Trabalhos (SearchJobs)
Descrição:
- Retorna uma lista de trabalhos conforme os filtros aplicados
- Permite busca por cidade, status, nome e outras propriedades
Exemplo de Uso:
{
"cityId": "987fcdeb-51a2-43f9-9876-543210fedcba",
"isActive": true,
"name": "elétrico"
}
Exemplo de Resposta:
{
"jobs": [
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"name": "Serviços Elétricos",
"details": "Instalação, manutenção e reparo de sistemas elétricos",
"isActive": true,
"createdAt": "2025-01-08T10:00:00Z"
},
{
"id": "456e7890-e12b-34d5-b678-901234567890",
"name": "Instalações Elétricas Industriais",
"details": "Serviços elétricos especializados para indústrias",
"isActive": true,
"createdAt": "2025-01-07T14:30:00Z"
}
]
}
Contrato: SearchJobsQuery
Campos Opcionais:
- CityId (Guid?, opcional) - Filtrar por cidade onde o trabalho está disponível
- IsActive (bool?, opcional) - Filtrar por status ativo/inativo
- Name (string, opcional) - Filtrar por nome (busca parcial)
- UserId (Guid?, opcional) - Filtrar trabalhos relacionados a um usuário
- Created (DateTime?, opcional) - Filtrar por data de criação
Retorno: SearchJobsResponse
- Lista de trabalhos que atendem aos critérios
Handler: SearchJobsHandler
Mapper: SearchJobsMapper
JobTasks (Tarefas de Trabalho)
Visão Geral
JobTask representa tarefas específicas dentro de um trabalho (ex: "Instalação de Tomada", "Troca de Disjuntor" dentro de "Serviços Elétricos"). JobTasks são precificáveis e podem ter atributos dinâmicos.
Commands (Comandos)
1. Criação de Tarefa (CreateJobTask)
Contrato: CreateJobTaskCommand
Campos Necessários:
JobId(Guid, obrigatório, JsonIgnore) - ID do trabalho paiName(string, obrigatório) - Nome da tarefaAttributes(List, obrigatório) - Atributos dinâmicos da tarefa Multipliers(List, obrigatório) - Multiplicadores de preço BasePrice(decimal?, obrigatório) - Preço base da tarefaPercentage(int, obrigatório) - Porcentagem de margem/taxaMaximumRecurrence(int?, opcional) - Número máximo de recorrências permitidasIsActive(bool, obrigatório) - Indica se a tarefa está ativaIsPriceable(bool, obrigatório) - Indica se a tarefa tem precificaçãoObservation(string, opcional) - Observações adicionaisAuthor(string, opcional) - Autor da operação
Validações:
JobId: Não pode ser vazioName: Não pode ser vazio; Tamanho máximo: 99 caracteresAttributes: Validado porTaskAttributesValidatorMultipliers: Validado porMultipliersValidatorBasePrice: Não pode ser vazioPercentage: Não pode ser vazio
Retorno: CreateJobTaskResponse
- Id (Guid) - Identificador da tarefa criada
Handler: CreateJobTaskHandler
Eventos de Domínio:
JobTaskCreatedEvent- Disparado quando uma tarefa é criada (se implementado)
Regras de Negócio:
- Atributos permitem configuração dinâmica (ex: "Número de tomadas", "Metragem")
- Multiplicadores afetam o cálculo de preço final
IsPriceable = falseindica que a tarefa não pode ser cotada individualmenteMaximumRecurrencelimita quantas vezes a tarefa pode ser solicitada no mesmo pedido
Exemplo de Uso:
{
"jobId": "123e4567-e89b-12d3-a456-426614174000",
"name": "Instalação de Tomadas",
"attributes": [
{
"identifier": "quantity",
"label": "Quantidade de tomadas",
"category": "Configuração",
"type": "Integer",
"value": 1,
"maximumQuantity": 20,
"isAdditional": false
}
],
"multipliers": [
{
"type": "Unit",
"key": 1,
"value": 1.0,
"attribute": "quantity"
},
{
"type": "Price",
"key": 5,
"value": 1.5
}
],
"basePrice": 50.00,
"percentage": 20,
"maximumRecurrence": 10,
"isActive": true,
"isPriceable": true,
"observation": "Instalação padrão 110V/220V",
"author": "admin@sistema.com"
}
2. Exclusão de Tarefa (DeleteJobTask)
Contrato: DeleteJobTaskCommand
Campos Necessários:
Id(Guid, obrigatório) - Identificador da tarefa
Validações:
Id: Não pode ser vazio
Retorno: Void
Handler: DeleteJobTaskHandler
3. Atualização de Tarefa (UpdateJobTask)
Contrato: UpdateJobTaskCommand
Campos Necessários:
JobId(Guid, obrigatório, JsonIgnore) - ID do trabalho paiJobTaskId(Guid, obrigatório, JsonIgnore) - ID da tarefaName(string, obrigatório) - Nome da tarefaAttributes(List, obrigatório) - Atributos dinâmicos Multipliers(List, obrigatório) - Multiplicadores de preço BasePrice(decimal?, obrigatório) - Preço basePercentage(int, obrigatório) - Porcentagem de margem/taxaMaximumRecurrence(int?, opcional) - Número máximo de recorrênciasIsActive(bool, obrigatório) - Indica se a tarefa está ativaIsPriceable(bool, obrigatório) - Indica se tem precificaçãoObservation(string, opcional) - Observações adicionaisAuthor(string, opcional) - Autor da operação
Validações:
JobId: Não pode ser vazio; Trabalho deve existirJobTaskId: Não pode ser vazio; Tarefa deve existirName: Não pode ser vazio; Tamanho máximo: 99 caracteresAttributes: Validado porTaskAttributesValidatorMultipliers: Validado porMultipliersValidatorBasePrice: Não pode ser vazioPercentage: Não pode ser vazio
Retorno: Void
Handler: UpdateJobTaskHandler
Regras de Negócio:
- A tarefa deve existir e pertencer ao trabalho especificado
- Atualizar preços não afeta solicitações já em andamento
- Cuidado ao alterar atributos e multiplicadores em tarefas ativas
Exemplo de Uso:
{
"name": "Instalação de Tomadas (Atualizado)",
"attributes": [...],
"multipliers": [...],
"basePrice": 55.00,
"percentage": 25,
"maximumRecurrence": 15,
"isActive": true,
"isPriceable": true,
"observation": "Preço atualizado para 2024",
"author": "admin@sistema.com"
}
Queries (Consultas)
1. Buscar Tarefa por ID (GetJobTaskById)
Contrato: GetJobTaskByIdQuery
Campos Necessários:
Id(Guid, obrigatório) - Identificador da tarefa
Retorno: GetJobTaskByIdResponse
Handler: GetJobTaskByIdHandler
Mapper: GetJobTaskByIdMapper
2. Listar Tarefas de um Trabalho (GetJobTasks)
Contrato: GetJobTasksQuery
Campos Necessários:
JobId(Guid, obrigatório) - ID do trabalho
Retorno: GetJobTasksResponse
- Lista de todas as tarefas do trabalho
Handler: GetJobTasksHandler
Mapper: GetJobTasksMapper
JobCities (Cidades do Trabalho)
Visão Geral
JobCity define em quais cidades um trabalho está disponível. É a associação entre Job e City.
Commands (Comandos)
1. Adicionar Cidade ao Trabalho (CreateJobCity)
Contrato: CreateJobCityCommand
Campos Necessários:
JobId(Guid, obrigatório) - ID do trabalhoCityId(Guid, obrigatório) - ID da cidade
Validações:
JobId: Não pode ser vazioCityId: Não pode ser vazio
Retorno: CreateJobCityResponse
- Id (Guid) - Identificador da associação criada
Handler: CreateJobCityHandler
Regras de Negócio:
- A cidade deve estar ativa
- Um trabalho pode estar disponível em múltiplas cidades
- Previne duplicação da mesma associação
Exemplo de Uso:
{
"jobId": "123e4567-e89b-12d3-a456-426614174000",
"cityId": "987fcdeb-51a2-43f9-9876-543210fedcba"
}
2. Remover Cidade do Trabalho (DeleteJobCity)
Contrato: DeleteJobCityCommand
Campos Necessários:
Id(Guid, obrigatório) - ID da associação
Validações:
Id: Não pode ser vazio
Retorno: Void
Handler: DeleteJobCityHandler
JobTaskCities (Cidades da Tarefa)
Visão Geral
JobTaskCity permite granularidade maior: uma tarefa específica pode estar disponível apenas em certas cidades, mesmo que o trabalho esteja disponível em mais cidades.
Commands (Comandos)
1. Adicionar Cidade à Tarefa (CreateJobTaskCity)
Contrato: CreateJobTaskCityCommand
Campos Necessários:
JobId(Guid, obrigatório, JsonIgnore) - ID do trabalhoJobTaskId(Guid, obrigatório, JsonIgnore) - ID da tarefaCityId(Guid, obrigatório) - ID da cidade
Validações:
JobId: Não pode ser vazioJobTaskId: Não pode ser vazioCityId: Não pode ser vazio
Retorno: CreateJobTaskCityResponse
- Id (Guid) - Identificador da associação criada
Handler: CreateJobTaskCityHandler
Regras de Negócio:
- Permite restringir disponibilidade regional de tarefas específicas
- A cidade deve estar associada ao Job pai (JobCity)
- Útil quando uma tarefa requer recursos ou certificações regionais específicas
2. Remover Cidade da Tarefa (DeleteJobTaskCity)
Contrato: DeleteJobTaskCityCommand
Campos Necessários:
Id(Guid, obrigatório) - ID da associação
Validações:
Id: Não pode ser vazio
Retorno: Void
Handler: DeleteJobTaskCityHandler
JobTaskSkills (Habilidades da Tarefa)
Visão Geral
JobTaskSkill associa habilidades (Skills) necessárias para executar uma tarefa, com um score de importância/proficiência.
Commands (Comandos)
1. Adicionar Habilidade à Tarefa (CreateJobTaskSkill)
Contrato: CreateJobTaskSkillCommand
Campos Necessários:
JobTaskId(Guid, obrigatório, JsonIgnore) - ID da tarefaJobId(Guid, obrigatório, JsonIgnore) - ID do trabalhoSkillId(Guid, obrigatório) - ID da habilidadeScore(int, obrigatório) - Pontuação de importância/proficiência (0-100)Observation(string, opcional) - Observações adicionaisAuthor(string, opcional) - Autor da operação
Validações:
JobId: Não pode ser vazioJobTaskId: Não pode ser vazioSkillId: Não pode ser vazioScore: Deve estar entre 0 e 100 (Score.MinScoreValue e Score.MaxScoreValue)Observation: Tamanho máximo: 12 caracteres quando fornecido
Retorno: CreateJobTaskSkillResponse
- Id (Guid) - Identificador da associação criada
Handler: CreateJobTaskSkillHandler
Regras de Negócio:
- Score indica o nível de importância da habilidade para a tarefa
- Scores mais altos = habilidade mais crítica
- Usado para matching de profissionais com tarefas
- Profissionais com skills matching têm prioridade em propostas
Exemplo de Uso:
{
"jobId": "123e4567-e89b-12d3-a456-426614174000",
"jobTaskId": "456e7890-e12b-34d5-b678-901234567890",
"skillId": "789fabcd-e34f-56a7-c890-123456789012",
"score": 85,
"observation": "Essencial",
"author": "admin@sistema.com"
}
2. Atualizar Habilidade da Tarefa (UpdateJobTaskSkill)
Contrato: UpdateJobTaskSkillCommand
Campos Necessários:
JobTaskId(Guid, obrigatório, JsonIgnore) - ID da tarefaJobId(Guid, obrigatório, JsonIgnore) - ID do trabalhoJobTaskSkillId(Guid, obrigatório, JsonIgnore) - ID da associaçãoValue(int, obrigatório) - Novo valor do scoreObservation(string, opcional) - ObservaçõesAuthor(string, opcional) - Autor da operação
Validações:
- Mesmas validações do CreateJobTaskSkill para o campo Value
Retorno: Void
Handler: UpdateJobTaskSkillHandler
3. Remover Habilidade da Tarefa (DeleteJobTaskSkill)
Contrato: DeleteJobTaskSkillCommand
Campos Necessários:
Id(Guid, obrigatório) - ID da associação
Validações:
Id: Não pode ser vazio
Retorno: Void
Handler: DeleteJobTaskSkillHandler
Queries (Consultas)
1. Buscar Habilidade por ID (GetJobTaskSkillById)
Contrato: GetJobTaskSkillByIdQuery
Campos Necessários:
Id(Guid, obrigatório) - ID da associação
Retorno: GetJobTaskSkillByIdResponse
Handler: GetJobTaskSkillByIdHandler
Mapper: GetJobTaskSkillByIdMapper
2. Listar Habilidades de uma Tarefa (GetJobTaskSkills)
Contrato: GetJobTaskSkillsQuery
Campos Necessários:
JobTaskId(Guid, obrigatório) - ID da tarefa
Retorno: GetJobTaskSkillsResponse
- Lista de habilidades com seus scores
Handler: GetJobTaskSkillsHandler
Mapper: GetJobTaskSkillsMapper
JobTaskEstimates (Estimativas da Tarefa)
Visão Geral
JobTaskEstimate define estimativas de tempo e esforço para completar uma tarefa, considerando diferentes níveis de experiência do profissional.
Commands (Comandos)
1. Criar Estimativa de Tarefa (CreateJobTaskEstimate)
Contrato: CreateJobTaskEstimateCommand
Campos Necessários:
JobTaskId(Guid, obrigatório, JsonIgnore) - ID da tarefaJobId(Guid, obrigatório, JsonIgnore) - ID do trabalhoEstimates(List, obrigatório) - Lista de estimativas Observation(string, opcional) - Observações adicionaisAuthor(string, opcional) - Autor da operação
Validações:
JobTaskId: Não pode ser vazioJobId: Não pode ser vazioEstimates: Validado porEstimatesValidator
Retorno: CreateJobTaskEstimateResponse
- Id (Guid) - Identificador da estimativa criada
Handler: CreateJobTaskEstimateHandler
Regras de Negócio:
- Cada estimativa considera nível de experiência do profissional
- Ajuda a calcular tempo de execução e agendar serviços
- Usado para validar propostas de profissionais
Exemplo de Uso:
{
"jobTaskId": "456e7890-e12b-34d5-b678-901234567890",
"jobId": "123e4567-e89b-12d3-a456-426614174000",
"estimates": [
{
"type": "Unit",
"value": 2,
"hours": 4,
"experiences": [
{
"level": "Junior",
"multiplier": 1.5
},
{
"level": "Senior",
"multiplier": 1.0
}
]
}
],
"observation": "Considerando instalação padrão",
"author": "admin@sistema.com"
}
2. Excluir Estimativa de Tarefa (DeleteJobTaskEstimate)
Contrato: DeleteJobTaskEstimateCommand
Campos Necessários:
Id(Guid, obrigatório) - ID da estimativa
Validações:
Id: Não pode ser vazio
Retorno: Void
Handler: DeleteJobTaskEstimateHandler
Queries (Consultas)
1. Buscar Estimativa por JobTaskId (GetJobTaskEstimateByJobTaskId)
Contrato: GetJobTaskEstimateByJobTaskIdQuery
Campos Necessários:
JobTaskId(Guid, obrigatório) - ID da tarefa
Retorno: GetJobTaskEstimateByJobTaskIdResponse
- Estimativas configuradas para a tarefa
Handler: GetJobTaskEstimateByJobTaskIdHandler
Mapper: GetJobTaskEstimateByJobTaskIdMapper
JobPackages (Pacotes de Trabalho)
Visão Geral
JobPackage representa pacotes/planos de serviço recorrente (ex: "Manutenção Mensal", "Plano Semestral"). Pacotes agrupam múltiplas tarefas com agendamento recorrente.
Commands (Comandos)
1. Criar Pacote de Trabalho (CreateJobPackage)
Contrato: CreateJobPackageCommand
Campos Necessários:
JobId(Guid, obrigatório, JsonIgnore) - ID do trabalhoName(string, obrigatório) - Nome do pacoteCategory(string, obrigatório) - Categoria do pacoteDetails(string, opcional) - Descrição detalhadaStartDate(DateTime, obrigatório) - Data de início da vigênciaEndDate(DateTime, obrigatório) - Data de término da vigênciaStartTime(TimeSpan, obrigatório) - Horário de início permitidoEndTime(TimeSpan, obrigatório) - Horário de término permitidoDayOfWeeks(List, obrigatório) - Dias da semana disponíveis Additional(List, opcional) - Atributos adicionais IsActive(bool, obrigatório) - Indica se o pacote está ativoAuthor(string, opcional) - Autor da operação
Validações:
JobId: Não pode ser vazioName: Não pode ser vazio; Tamanho máximo: 99 caracteresCategory: Não pode ser vazio; Tamanho máximo: 99 caracteresDetails: Tamanho máximo: 500 caracteres quando fornecidoStartDate: Deve ser anterior a EndDateStartTime: Deve ser anterior a EndTimeDayOfWeeks: Pelo menos um dia da semana deve ser selecionadoAdditional: Validado porTaskAttributeValidatorquando fornecidoIsActive: Não pode ser nulo
Retorno: CreateJobPackageResponse
- Id (Guid) - Identificador do pacote criado
Handler: CreateJobPackageHandler
Regras de Negócio:
- Pacotes permitem serviços recorrentes (ex: diarista, faxineira mensal)
- DayOfWeeks define quais dias da semana o serviço pode ser agendado
- Horários definem janela de disponibilidade
- Período de vigência controla quando o pacote está disponível
Exemplo de Uso:
{
"jobId": "123e4567-e89b-12d3-a456-426614174000",
"name": "Pacote Manutenção Mensal",
"category": "Recorrente",
"details": "Manutenção preventiva mensal incluindo inspeção e pequenos reparos",
"startDate": "2025-01-01T00:00:00",
"endDate": "2025-12-31T23:59:59",
"startTime": "08:00:00",
"endTime": "18:00:00",
"dayOfWeeks": ["Monday", "Wednesday", "Friday"],
"additional": [],
"isActive": true,
"author": "admin@sistema.com"
}
2. Excluir Pacote de Trabalho (DeleteJobPackage)
Contrato: DeleteJobPackageCommand
Campos Necessários:
Id(Guid, obrigatório) - ID do pacote
Validações:
Id: Não pode ser vazio
Retorno: Void
Handler: DeleteJobPackageHandler
Queries (Consultas)
1. Buscar Pacote por ID (GetJobPackageById)
Contrato: GetJobPackageByIdQuery
Campos Necessários:
Id(Guid, obrigatório) - ID do pacote
Retorno: GetJobPackageByIdResponse
Handler: GetJobPackageByIdHandler
Mapper: GetJobPackageByIdMapper
2. Pesquisar Pacotes (SearchJobPackages)
Contrato: SearchJobPackagesQuery
Campos Necessários:
JobId(Guid, obrigatório, BindNever) - ID do trabalho
Campos Opcionais:
- Name (string, opcional) - Filtrar por nome
- Category (string, opcional) - Filtrar por categoria
- DayOfWeeks (DayOfWeek?, opcional) - Filtrar por dia da semana
- Created (DateTime?, opcional) - Filtrar por data de criação
- IsActive (bool?, opcional) - Filtrar por status
- JobTaskId (Guid?, opcional) - Filtrar pacotes que contêm uma tarefa específica
Retorno: SearchJobPackagesResponse
Handler: SearchJobPackagesHandler
Mapper: SearchJobPackagesMapper
JobPackageTasks (Tarefas do Pacote)
Visão Geral
JobPackageTask associa tarefas a um pacote. Um pacote pode incluir múltiplas tarefas que serão executadas no serviço recorrente.
Commands (Comandos)
1. Adicionar Tarefa ao Pacote (CreateJobPackageTask)
Contrato: CreateJobPackageTaskCommand
Campos Necessários:
JobId(Guid, obrigatório, JsonIgnore) - ID do trabalhoJobPackageId(Guid, obrigatório, JsonIgnore) - ID do pacoteJobTaskId(Guid, obrigatório) - ID da tarefa
Validações:
JobId: Não pode ser vazioJobPackageId: Não pode ser vazioJobTaskId: Não pode ser vazio
Retorno: CreateJobPackageTaskResponse
- Id (Guid) - Identificador da associação criada
Handler: CreateJobPackageTaskHandler
Regras de Negócio:
- A tarefa deve pertencer ao mesmo Job do pacote
- Previne duplicação da mesma tarefa no pacote
2. Remover Tarefa do Pacote (DeleteJobPackageTask)
Contrato: DeleteJobPackageTaskCommand
Campos Necessários:
Id(Guid, obrigatório) - ID da associação
Validações:
Id: Não pode ser vazio
Retorno: Void
Handler: DeleteJobPackageTaskHandler
Queries (Consultas)
1. Listar Tarefas de um Pacote (GetJobPackageTasksByJobPackageId)
Contrato: GetJobPackageTasksByJobPackageIdQuery
Campos Necessários:
JobPackageId(Guid, obrigatório) - ID do pacote
Retorno: GetJobPackageTasksByJobPackageIdResponse
- Lista de tarefas incluídas no pacote
Handler: GetJobPackageTasksByJobPackageIdHandler
Mapper: GetJobPackageTasksByJobPackageIdMapper
Value Objects
TaskAttribute
Representa atributos dinâmicos/configuráveis de uma tarefa.
Propriedades:
- Identifier (string) - Identificador único do atributo (max: 100 caracteres)
- Label (string) - Rótulo exibido ao usuário (max: 500 caracteres)
- Category (string) - Categoria do atributo (max: 100 caracteres)
- Type (TaskAttributeType) - Tipo de dado (Integer ou Boolean)
- Value (decimal?) - Valor padrão
- MaximumQuantity (int?) - Quantidade máxima permitida
- IsAdditional (bool?) - Indica se é um atributo adicional/opcional
Enum TaskAttributeType:
- Integer - Valor numérico inteiro
- Boolean - Valor booleano (sim/não)
Validações:
- Identifier não pode ser vazio
- Label não pode ser vazio
- Category não pode ser vazio
- Value não pode ser negativo
- MaximumQuantity não pode ser negativo
Exemplo:
{
"identifier": "num_rooms",
"label": "Número de cômodos",
"category": "Dimensões",
"type": "Integer",
"value": 1,
"maximumQuantity": 10,
"isAdditional": false
}
Multiplier
Representa multiplicadores aplicados ao cálculo de preço.
Propriedades:
- Type (MultiplierType) - Tipo do multiplicador (Unit ou Price)
- Key (decimal) - Chave de referência
- Value (decimal) - Valor do multiplicador
- Attribute (string?) - Atributo associado (apenas para Type = Unit)
Enum MultiplierType:
- Unit - Multiplicador baseado em unidade/quantidade
- Price - Multiplicador baseado em faixa de preço
Validações:
- Value não pode ser negativo
- Attribute só pode ser especificado quando Type = Unit
Exemplo:
{
"type": "Unit",
"key": 5,
"value": 1.2,
"attribute": "num_rooms"
}
Lógica:
- Se quantidade de cômodos (num_rooms) = 5, aplica multiplicador de 1.2x no preço
Estimate
Representa estimativas de tempo para conclusão de tarefas.
Propriedades:
- Type (EstimateType) - Tipo de estimativa (Unit ou Price)
- Value (int) - Valor de referência
- Hours (int) - Horas estimadas
- Experiences (List
Enum EstimateType:
- Unit - Estimativa baseada em unidade/quantidade
- Price - Estimativa baseada em faixa de preço
Validações:
- Experiences não pode ser vazio
- Deve ter pelo menos um nível de experiência
Exemplo:
{
"type": "Unit",
"value": 3,
"hours": 6,
"experiences": [
{
"level": "Junior",
"multiplier": 1.5
},
{
"level": "Senior",
"multiplier": 1.0
}
]
}
Lógica: - Para 3 unidades, estima-se 6 horas - Profissional Junior leva 6 * 1.5 = 9 horas - Profissional Senior leva 6 * 1.0 = 6 horas
Conceitos de DDD e CQRS
Domain-Driven Design (DDD)
Aggregate Root:
- Job é o agregado raiz principal
- Controla acesso e consistência de:
- JobTasks
- JobCities
- JobPackages
Entities:
- JobTask - Entidade filha de Job
- JobCity - Entidade de associação
- JobTaskCity - Entidade de associação granular
- JobTaskSkill - Entidade de associação
- JobTaskEstimate - Entidade de configuração
- JobPackage - Entidade de pacote
- JobPackageTask - Entidade de associação
Value Objects:
- TaskAttribute - Configuração dinâmica
- Multiplier - Cálculo de preço
- Estimate - Estimativa de tempo
- Author - Autor da operação
- Observation - Observações
- Score - Pontuação de habilidade
Invariantes: - Job deve ter ao menos uma JobTask para ser utilizável - JobTask com IsPriceable = true deve ter BasePrice - JobPackage: StartDate < EndDate, StartTime < EndTime - JobTaskSkill: Score entre 0 e 100 - Multiplicadores: Value >= 0
CQRS (Command Query Responsibility Segregation)
Commands (Modificam Estado): - Create: Job, JobTask, JobCity, JobTaskCity, JobTaskSkill, JobTaskEstimate, JobPackage, JobPackageTask - Update: JobTaskSkill - Delete: Job, JobTask, JobCity, JobTaskCity, JobTaskSkill, JobTaskEstimate, JobPackage, JobPackageTask
Queries (Apenas Leitura): - GetById: Job, JobTask, JobTaskSkill, JobTaskEstimate, JobPackage - Search/List: Jobs, JobTasks, JobTaskSkills, JobPackages, JobPackageTasks
Separação de Responsabilidades: - Commands usam modelo de escrita otimizado - Queries usam DTOs/Responses otimizados para leitura - Mappers convertem entre domínio e DTOs
Observações Importantes
- Hierarquia:
- Job > JobTask > JobTaskSkill, JobTaskCity, JobTaskEstimate
-
Job > JobPackage > JobPackageTask
-
Precificação Dinâmica:
- TaskAttributes definem parâmetros configuráveis
- Multipliers ajustam preço baseado em quantidade ou faixa de valor
-
BasePrice + (Multipliers * Attributes) = Preço Final
-
Disponibilidade Regional:
- JobCity: Disponibilidade do trabalho inteiro
-
JobTaskCity: Granularidade por tarefa específica
-
Matching de Profissionais:
- JobTaskSkills com score alto indicam requisitos críticos
-
Profissionais com skills correspondentes têm prioridade
-
Estimativas:
- Ajustadas por nível de experiência do profissional
-
Usadas para agendar e validar propostas
-
Pacotes Recorrentes:
- Ideais para serviços contínuos (limpeza, manutenção)
- DayOfWeeks controla disponibilidade semanal
-
Período de vigência limita quando pode ser contratado
-
Auditoria:
- Campos Author registram quem criou/modificou
- Timestamps automáticos (CreatedAt, UpdatedAt)