Camada de Módulo (Business Logic)
A camada de Módulo (packages/modules/*) é o coração da nossa arquitetura. É nela que a lógica de negócio de saúde reside, sendo responsável por definir como as regras médicas e fluxos de trabalho são traduzidos em código. Cada módulo é projetado para ser um Contexto Delimitado (Bounded Context), operando com autonomia e minimizando o acoplamento lateral.
O Que Define um Módulo?
Diferente de uma simples pasta de componentes, um módulo é uma unidade funcional completa que encapsula:
- Regras de Negócio: Validações clínicas, cálculos de doses, critérios de elegibilidade para exames.
- Estado Global Próprio: Gerenciado via Redux Toolkit (Slices e Selectors).
- Processos Assíncronos: Fluxos complexos coordenados por Redux-Saga.
- Orquestração de Status: Máquinas de estado (XState) para fluxos rígidos.
- Interfaces de Usuário (UI): Componentes inteligentes que conhecem o contexto do negócio.
Estratégia de Isolamento (Strict Isolation)
Para garantir que o sistema escale sem se tornar uma "bola de lama" (Big Ball of Mud), aplicamos regras rigorosas de isolamento na camada de módulo:
- Proibido Importar Entre Módulos: O módulo de
Consultationnunca deve importar nada deChat. - Independência de Estilo: Módulos não devem depender de temas específicos de um App. Eles usam o Design System (
packages/shared/ui) para manter a consistência visual. - Contratos como Fronteira: Toda a comunicação com o Backend ou com outros módulos (via eventos) deve respeitar as interfaces definidas em
packages/contracts.
Estrutura Interna Padronizada
Para manter a consistência cognitiva entre os times, cada módulo segue uma anatomia de pastas previsível:
packages/modules/[nome-do-modulo]/
├── api/ # Serviços de comunicação com o Backend (Axios/Fetch)
├── store/ # Lógica de estado (Redux Toolkit)
│ ├── slice.ts # Reducer e Actions
│ ├── selectors.ts # Seletores de estado (Reselect)
│ ├── sagas.ts # Efeitos colaterais e fluxos assíncronos
│ └── types.ts # Tipos específicos do estado do módulo
├── machines/ # Máquinas de estado (XState) para fluxos complexos
├── ui/ # Componentes React
│ ├── components/ # Componentes internos e granulares
│ ├── fragments/ # Composições maiores (ex: Header da Consulta)
│ └── Page.tsx # Ponto de entrada principal (View)
├── hooks/ # Hooks específicos da lógica do módulo
├── utils/ # Helpers que só fazem sentido para este módulo
└── index.ts # Public API (Exporta apenas o necessário)Responsabilidades por Sub-camada
1. API (Services)
Nesta camada, definimos funções puras que realizam chamadas ao backend. Elas não devem lidar com o estado do Redux, apenas transformar dados de entrada e saída conforme necessário.
2. Store (State Management)
O estado do módulo é injetado dinamicamente. Ele deve ser o mais normalizado possível. O uso de Selectors é obrigatório para que os componentes da UI não conheçam o formato exato da Store, facilitando refatorações internas sem quebrar o visual.
3. Sagas (Side Effects)
Os Sagas são fundamentais em sistemas médicos para garantir a ordem de operações. Por exemplo: antes de "Finalizar Atendimento", o Saga garante que o "Upload do Prontuário" foi concluído com sucesso.
4. UI (User Interface)
Os componentes na camada de módulo são "Smart Components" (ou Componentes de Negócio). Eles têm permissão para:
- Despachar ações do Redux.
- Consumir seletores do Redux.
- Utilizar máquinas de estado do XState.
- Integrar com o Design System.
Encapsulamento via Public API (index.ts)
Para garantir que o isolamento seja respeitado, o arquivo index.ts na raiz do módulo atua como um "Gatekeeper", exportando apenas o que é necessário para as Apps.
// packages/modules/consultation/index.ts
// 1. Exporta a View Principal (Page) para ser usada nas rotas da App
export { ConsultationPage } from './ui/Page';
// 2. Exporta Reducers e Sagas para Injeção Dinâmica
export { consultationReducer } from './store/slice';
export { consultationSaga } from './store/sagas';
// 3. Exporta Selectors se o App precisar de algum dado específico do módulo
export { selectActiveConsultation } from './store/selectors';
// 4. Exporta as Actions para que a App possa disparar eventos de navegação/fluxo
export { consultationActions } from './store/slice';Fluxo de Dados e Interação
O fluxo de dados dentro de um módulo é estritamente unidirecional:
- O usuário interage com um componente na pasta
ui/. - O componente despacha uma Action do Redux.
- Um Saga intercepta a Action e executa lógica assíncrona (ex: chamada de API).
- O Saga atualiza o Reducer com o resultado.
- O Selector detecta a mudança e atualiza a UI.
Se o módulo precisar notificar o resto do sistema sobre algo (ex: "Consulta Finalizada"), o Saga publica um Domain Event no barramento central em vez de tentar chamar uma função de outro módulo.
Como Decidir se Algo é um Módulo?
Uma funcionalidade deve ser um módulo se ela representar uma unidade de negócio que possui:
- Um vocabulário próprio (Linguagem Ubíqua).
- Um conjunto de regras de negócio específicas.
- Ciclo de vida próprio independente de outros módulos.
Exemplo: Medical Record (Prontuário) é um módulo pois tem suas próprias regras de auditoria, histórico e sigilo, que são diferentes de Vaccination (Vacinação), embora ambos possam estar relacionados a uma mesma consulta médica.