# Donc — Módulos e Bounded Contexts > Referência: [visao-geral.md](visao-geral.md) | [adr-001-modular-monolith.md](adr-001-modular-monolith.md) Cada módulo é uma unidade autônoma com responsabilidade clara. Nenhum módulo acessa diretamente as tabelas de outro. A comunicação é sempre por interface pública ou evento. --- ## Módulo: OrdemServico (OS) **Responsabilidades:** - Criação, edição e cancelamento de ordens de serviço - Ciclo de vida da OS (status: Aguardando → Encaminhada → Em execução → Finalizada) - Checklist de execução (TipoJobItem, TipoJobSessao) - Produtos associados à OS (PedidoItem, ProdutoComercial) - Leitura de etiquetas QR em campo (SessaoValidacaoQr) - Fila de criação automática de OS (FilaCriacaoPedido — GeraMontagem, reagendamento, múltipla escolha) **Entidades:** - `Pedido` (OS/Job) — entidade raiz - `PedidoItem` — produtos da OS - `PedidoStatus` — histórico de status - `JobIten` — itens do checklist - `JobItensMultiEscolha` — respostas de múltipla escolha - `SessaoValidacaoQr` — leituras de etiqueta - `TipoJob` — template de serviço (compartilhado com módulo Profissional) - `TipoJobItem`, `TipoJobSessao` — estrutura do checklist - `ProdutoComercial` — catálogo de produtos - `FilaCriacaoPedido` — fila de criação automática **Contratos públicos expostos:** ```csharp public interface IServicoOrdemServico { Task CriarAsync(CriarOSCommand comando, CancellationToken ct = default); Task BuscarPorIdAsync(int ordemServicoId, CancellationToken ct = default); Task FinalizarAsync(FinalizarOSCommand comando, CancellationToken ct = default); Task CancelarAsync(int ordemServicoId, string motivo, CancellationToken ct = default); } ``` **O que NÃO pertence a este módulo:** - Distribuição para profissional (→ Roteirizacao) - Cálculo de comissão (→ Financeiro) - Envio de webhook (→ Notificacao) - Disponibilidade do profissional (→ Profissional) - Resolução de tenant (→ Tenancy) --- ## Módulo: Profissional **Responsabilidades:** - Cadastro e gestão de profissionais (Motoqueiro) e empresas parceiras (Parceiro) - Disponibilidade e capacidade de atendimento - Cobertura geográfica (FaixaCEP por profissional/estabelecimento) - Credenciamento e treinamento - Associação com tipos de serviço aceitos **Entidades:** - `Motoqueiro` (Profissional) — entidade raiz - `Parceiro` — empresa prestadora - `ParceiroTipoJob` — tipos de serviço aceitos pelo parceiro - `FaixaCEP` — área de cobertura - `Zona`, `ZonaContrato` — zonamento geográfico - `PlanoGsr` — plano de capacidade **Contratos públicos expostos:** ```csharp public interface IServicoProfissional { Task BuscarPorCodigoManualAsync(string codigoManual, int contratoSaasId, CancellationToken ct = default); Task> BuscarDisponiveisAsync(BuscarDisponiveisQuery consulta, CancellationToken ct = default); Task CriarComParceiroAsync(CriarProfissionalComParceiroCommand comando, CancellationToken ct = default); } ``` **O que NÃO pertence a este módulo:** - OS atribuída ao profissional (→ OrdemServico) - Roteiro do dia (→ Roteirizacao) - Comissão (→ Financeiro) --- ## Módulo: Agendamento **Responsabilidades:** - Disponibilidade de janelas de atendimento - Reserva e confirmação de horário - Autoagendamento pelo cliente (portal/app) - Reagendamento de OS **Entidades:** - `DisponibilidadeAgenda` — janelas disponíveis - `ReservaAgenda` — slots reservados - `ConfiguracaoAgenda` — regras por tipo de serviço/estabelecimento **Contratos públicos expostos:** ```csharp public interface IServicoAgendamento { Task> BuscarJanelasAsync(BuscarJanelasQuery consulta, CancellationToken ct = default); Task ReservarAsync(ReservarAgendaCommand comando, CancellationToken ct = default); Task ReagendarAsync(ReagendarOSCommand comando, CancellationToken ct = default); } ``` **O que NÃO pertence a este módulo:** - Criação da OS após confirmação do agendamento (→ OrdemServico) - Disponibilidade do profissional (→ Profissional) --- ## Módulo: Roteirizacao **Responsabilidades:** - Distribuição manual e inteligente de OS para profissionais - Cálculo de rota otimizada (DoncRouter) - Criação e gestão de Saidas (Rotas/Bags) - Distribuição assistida por IA (Google Gemini) **Entidades:** - `Saida` (Rota/Bag) — entidade raiz - `RotaContrato` — configuração de rota por contrato - `RotaContratoEstabelecimento` — vínculo rota-estabelecimento **Contratos públicos expostos:** ```csharp public interface IServicoRoteirizacao { Task DistribuirAsync(DistribuirOSCommand comando, CancellationToken ct = default); Task> SugerirDistribuicaoAsync(SugerirDistribuicaoQuery consulta, CancellationToken ct = default); Task AtribuirProfissionalAsync(AtribuirProfissionalCommand comando, CancellationToken ct = default); } ``` **O que NÃO pertence a este módulo:** - Status interno da OS (→ OrdemServico) - Disponibilidade do profissional (→ Profissional) - Notificação ao profissional após atribuição (→ Notificacao) --- ## Módulo: Financeiro **Responsabilidades:** - Fechamento financeiro diário (job 03:00) - Cálculo de comissão do profissional/parceiro (3 algoritmos: percentual, fixo, sobre total) - Relatórios financeiros - Cobranças e faturamento **Entidades:** - `FechamentoDiario` — registro do fechamento - `ComissaoProfissional` — comissão calculada por OS - Campos em `Parceiro`: `ComissaoParceiro`, `ValorComissaoTerceirizado`, `CalcularComissaoSobreValorTotal` - Campos em `Pedido`: `ValorCobrarPeloServico`, `ValorPagarProfissional`, `Valor` **Contratos públicos expostos:** ```csharp public interface IServicoFinanceiro { Task ExecutarFechamentoDiarioAsync(DateOnly data, int contratoSaasId, CancellationToken ct = default); Task CalcularComissaoAsync(CalcularComissaoQuery consulta, CancellationToken ct = default); } ``` **O que NÃO pertence a este módulo:** - Status da OS (→ OrdemServico) - Pagamento externo / gateway (→ Integracoes) --- ## Módulo: Integracoes **Responsabilidades:** - Recebimento de OS de ERPs externos (FilaIntegracaoPedido) - Envio de webhooks e notificações externas (PostSchedule, Gatilho) - Integração bidirecional com sistemas de terceiros (HubSoft, IXC, MK, Berlanda, LojasMM, Cybelar, SSW) - De-para de IDs externos (IntegracaoJob) - API externa pública (endpoints para clientes integrarem) **Entidades:** - `FilaIntegracaoPedido` — JSON bruto aguardando processamento - `IntegracaoJob` — de-para ERP ↔ Donc - `Gatilho` — configuração de webhook - `PostSchedule` — fila de envio de webhook - `ApiLog` — log de chamadas externas **Contratos públicos expostos:** ```csharp public interface IServicoIntegracao { Task EnfileirarOSExternaAsync(EnfileirarOSExternaCommand comando, CancellationToken ct = default); Task EnviarWebhookAsync(EnviarWebhookCommand comando, CancellationToken ct = default); } ``` **O que NÃO pertence a este módulo:** - Lógica de criação da OS (→ OrdemServico) - Lógica de criação de profissional (→ Profissional) - Resolução de tenant (→ Tenancy) --- ## Módulo: Notificacao **Responsabilidades:** - Envio de webhooks para ERPs (processamento de PostSchedule) - Notificações push para o app - Notificações por e-mail (senhas, alertas) - Avaliação pós-serviço (SMS/WhatsApp) **Entidades:** - `PostSchedule` — fila de envio - `Gatilho` — configuração - Configurações de e-mail por tenant **Contratos públicos expostos:** ```csharp public interface IServicoNotificacao { Task NotificarAsync(NotificarCommand comando, CancellationToken ct = default); Task ProcessarFilaWebhookAsync(CancellationToken ct = default); } ``` **O que NÃO pertence a este módulo:** - Lógica de negócio que dispara a notificação (cada módulo publica um evento; Notificacao reage) --- ## Módulo: Tenancy **Responsabilidades:** - Resolução do tenant a partir de api_key, JWT ou host - Isolamento de dados por `ContratoSaasId` - Gestão de configurações por tenant (TipoJob, FormaPagamento, etc.) - Usuários e permissões (Membership) **Entidades:** - `ContratoSaa` (Tenant) — entidade raiz - `Estabelecimento` — filial/loja do tenant - `FormaPagamento` — por tenant - Membership tables (Users, Roles) — por AppName do tenant **Contrato central:** ```csharp public interface IContextoTenant { int ContratoSaasId { get; } int EstabelecimentoId { get; } string AppName { get; } } ``` **Regra:** `IContextoTenant` é injetado em todos os handlers que precisam de isolamento. Nenhum handler recebe `contratoSaasId` como parâmetro direto — ele sempre vem do contexto. **O que NÃO pertence a este módulo:** - Qualquer lógica de negócio dos outros domínios --- ## Regras de Comunicação entre Módulos ``` ┌──────────────┐ IServicoOrdemServico ┌──────────────────┐ │ Integracoes │ ───────────────────────► │ OrdemServico │ └──────────────┘ └──────────────────┘ │ IServicoRoteirizacao │ evento: OSCriada ┌──────────────────────────────┘ ▼ ┌─────────────────┐ │ Roteirizacao │──── IServicoProfissional ──► Profissional └─────────────────┘ │ │ evento: OSDistribuida ▼ ┌─────────────────┐ │ Notificacao │ └─────────────────┘ ``` **Regras:** 1. Módulo A chama módulo B apenas pela interface pública (`IServicoX`) 2. Módulo A nunca faz `SELECT` diretamente em tabela do módulo B 3. Eventos de domínio (`INotification` do MediatR) são o mecanismo preferido para reações assíncronas 4. `IContextoTenant` é injetado por request — nunca propagado manualmente entre módulos