Skip to content

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:

  1. Regras de Negócio: Validações clínicas, cálculos de doses, critérios de elegibilidade para exames.
  2. Estado Global Próprio: Gerenciado via Redux Toolkit (Slices e Selectors).
  3. Processos Assíncronos: Fluxos complexos coordenados por Redux-Saga.
  4. Orquestração de Status: Máquinas de estado (XState) para fluxos rígidos.
  5. 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 Consultation nunca deve importar nada de Chat.
  • 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:

text
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.

typescript
// 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:

  1. O usuário interage com um componente na pasta ui/.
  2. O componente despacha uma Action do Redux.
  3. Um Saga intercepta a Action e executa lógica assíncrona (ex: chamada de API).
  4. O Saga atualiza o Reducer com o resultado.
  5. 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.