Skip to content

Guia de Desenvolvimento: Criando um Novo Módulo

Para manter a consistência e o isolamento da arquitetura em nosso ecossistema de saúde, a criação de um novo domínio (ex: prescriptions, exams, telemetry) deve seguir um padrão rigoroso. Este guia detalha o processo de "scaffolding" e as regras de implementação passo a passo.

Passo 1: Preparação e Scaffolding

Cada novo módulo deve ser criado dentro de packages/modules/[nome-do-modulo].

  1. Criação do Diretório: No terminal (raiz do projeto):

    bash
    mkdir -p packages/modules/my-new-module/{api,store,machines,ui,hooks,utils}
    touch packages/modules/my-new-module/index.ts
    touch packages/modules/my-new-module/README.md
  2. Estrutura Interna Esperada:

    text
    packages/modules/[nome-do-modulo]/
    ├── api/                # Chamadas HTTP/Axios exclusivas do módulo
    ├── store/              # Lógica Redux (Slices, Selectors, Sagas)
    │   ├── slice.ts
    │   ├── selectors.ts
    │   ├── sagas.ts
    │   └── types.ts
    ├── machines/           # Máquinas de estado (XState)
    ├── ui/                 # Componentes React
    │   ├── components/     # Componentes internos (não exportados)
    │   ├── Page.tsx        # Entry point da página (se aplicável)
    │   └── index.ts        # Exportações públicas da UI
    ├── index.ts            # Public API do Pacote (Gatekeeper)
    └── README.md           # Documentação técnica do módulo

Passo 2: Definindo o Contrato (Contracts)

Antes de codificar a lógica, defina os tipos de dados em packages/contracts. Isso garante o "Single Source of Truth" para tipagem.

  1. Crie o arquivo packages/contracts/src/my-new-domain.ts.
  2. Adicione as interfaces de negócio:
    typescript
    export interface MyData {
      id: string;
      status: 'PENDING' | 'COMPLETED';
      createdAt: string;
    }
  3. Exporte no packages/contracts/src/index.ts.

Passo 3: Implementando a Camada de Dados (Store)

O módulo deve gerenciar seu próprio estado de forma isolada.

  1. Slice (store/slice.ts):

    typescript
    import { createSlice, PayloadAction } from '@reduxjs/toolkit';
    import { MyData } from 'contracts/my-new-domain';
    
    interface DomainState {
      items: MyData[];
      loading: boolean;
    }
    
    const initialState: DomainState = { items: [], loading: false };
    
    const domainSlice = createSlice({
      name: 'myNewDomain',
      initialState,
      reducers: {
        fetchDataRequest: (state) => { state.loading = true; },
        fetchDataSuccess: (state, action: PayloadAction<MyData[]>) => {
          state.items = action.payload;
          state.loading = false;
        }
      }
    });
    
    export const { actions: domainActions, reducer: domainReducer } = domainSlice;
  2. Sagas (store/sagas.ts): Implemente a lógica de efeitos colaterais (chamadas de API).

Passo 4: Public API e Encapsulamento

O arquivo index.ts na raiz do módulo é a única porta de entrada permitida.

  1. Edite packages/modules/my-new-module/index.ts:{
    typescript
    // 1. Exporta Componentes de UI
    export { MyDomainPage } from './ui/Page';
    
    // 2. Exporta Lógica de Estado para Injeção Dinâmica
    export { domainReducer } from './store/slice';
    export { domainSaga } from './store/sagas';
    
    // 3. Exporta Actions e Selectors necessários para a App
    export { domainActions } from './store/slice';
    export { selectMyData } from './store/selectors';

Passo 5: Registro e Consumo na Aplicação (App)

As aplicações orquestram os domínios. Siga estes passos para injetar o domínio:

  1. Importação:

    tsx
    import { useInjectReducer, useInjectSaga } from 'core/store-injector';
    import { moduleReducer, moduleSaga, MyModulePage } from 'modules/my-new-module';
  2. Injeção no Componente de Rota:

    tsx
    const MyRoute = () => {
      // Passo Crítico: Injetar os recursos antes de renderizar a UI
      useInjectReducer({ key: 'myNewModule', reducer: moduleReducer });
      useInjectSaga({ key: 'myNewModule', saga: moduleSaga });
    
      return <MyModulePage />;
    };

Regras de Ouro (Checklist)

  • [ ] Meu módulo importa algo de outro módulo? (Deve ser NÃO).
  • [ ] Meus tipos estão em packages/contracts? (Deve ser SIM).
  • [ ] O index.ts exporta apenas o estritamente necessário? (Deve ser SIM).
  • [ ] Usei o Design System de packages/shared/ui? (Deve ser SIM).