Guia do Desenvolvedor - CAKeysama/ReTool GitHub Wiki

Guia do Desenvolvedor

Como estender o ReTool seguindo o padrão já existente. A visão geral das camadas está em Arquitetura.

Convenções

  • Idioma: nomes do domínio, mensagens e comentários em português (Dispositivo, solicitarAlteracaoCargo, ErroPermissao).
  • Estilo: estilos inline com as variáveis CSS de src/index.css (var(--color-primary), var(--spacing-md), var(--radius)) e as classes .btn, .btn-primary, .btn-icon, .input-field, .input-label, .card. Não há framework de CSS.
  • Componentes de apoio:
    • Feedback.tsx: Aviso, EstadoCarregando, EstadoErro;
    • Badges.tsx: Pill, RoleBadge, SituacaoBadge;
    • Tabs.tsx: Tabs e EmptyState;
    • AccessibleModal.tsx: modal acessível;
    • BulkActionModal.tsx: ações em massa.
  • Commits: no estilo Conventional Commits, em português (feat(escopo): ..., fix(...), refactor(...), style(...), docs(...)).
  • Branches: main (estável), dev e branches de funcionalidade (feat/...).

Onde colocar cada coisa

Quero… Onde Observações
Nova tela src/pages/ e uma rota em src/App.tsx Dentro de ProtectedLayout; restrinja com RoleRoute se preciso. Adicione o link em src/components/Layout.tsx (barra lateral e navegação inferior)
Novo componente src/components/ (components/admin/ se for só da Administração) Reaproveite Feedback, Badges e Tabs
Lógica de tela com estado src/presentation/hooks/use*Controller.ts Ex.: useDispositivosController, useHistoricoAuditoriaController
Nova entidade ou regra pura src/domain/entities/ Sem dependência do Firebase; é onde os testes são mais baratos
Acesso ao Firestore src/data/repositories/Firestore*Repository.ts, com o contrato em src/domain/repositories/
Serviço externo (Storage, Functions) src/data/services/
Fluxo com várias etapas (gravar + notificar + auditar) src/application/usecases/ Receba os repositórios pelo construtor (ver os casos de uso de acesso)
Expor a operação para as telas AuthContext (contas e acesso) ou ReToolContext (dados industriais) Cheque a permissão na função do contexto
Operação que exige Admin SDK retool/functions/src/index.ts Veja abaixo

Nova operação de dados

  1. Método no repositório.
  2. Função no contexto, que:
    • confere a permissão (ex.: if (!canEditar) { announce('Acesso negado...'); return; });
    • chama o repositório;
    • chama registrarAuditoria(...) após o sucesso.
  3. Regra correspondente em firestore.rules. Sem ela, a operação é negada no servidor.
  4. Testes: domínio e repositório com firebaseMock; regras em src/tests/rules/firestore.rules.test.ts.

Permissões

Para uma nova permissão de cargo:

  1. adicione o campo em RoleConfig e preencha ROLES_CONFIG e CONVIDADO_CONFIG (sempre false), em src/domain/entities/user.ts;
  2. exponha o campo no AuthContext (can...) e em usePermissions();
  3. aplique a mesma regra em firestore.rules (e em storage.rules, se envolver arquivos);
  4. atualize a matriz em src/tests/domain/entities/user.test.ts e a tabela em Usuários, Cargos e Permissões.

Um novo cargo exige ainda:

  • ajustar UserRole e perfisOperacionais() nas regras (Firestore e Storage);
  • ajustar PERFIS_OPERACIONAIS na Cloud Function;
  • ajustar TRANSICOES_REUTILIZACAO.

Auditoria

Para um novo tipo de evento:

  1. Em src/domain/entities/auditLog.ts:
    • adicione o token em AuditLogAcao;
    • adicione o rótulo em ROTULO_ACAO;
    • coloque o token em uma categoria de ACOES_POR_CATEGORIA. O teste auditLog.test.ts falha se uma ação ficar sem categoria ou em duas.
  2. Registre com registrarAuditoria(...) (ReToolContext), registrarAuditoriaSemFalhar(...) (casos de uso) ou auditRepo.registrarLog(...).
  3. Preencha acao, acaoDescricao, tipoEntidade, entidadeId e, se útil, conteudo/dadosAnteriores. Use resultado: 'negado' ou 'falha' quando for o caso.
  4. Nunca coloque senha, token ou hash nos dados. A sanitização remove esses campos, mas não conte com ela.
  5. Para um novo recurso, atualize AuditLogTipoEntidade e ROTULO_TIPO_ENTIDADE.

Para um novo filtro no Histórico de Ações:

  1. adicione o campo em FiltrosAuditoria e em filtrosDeIgualdade(), e o nome do campo em CAMPOS_FILTRO_AUDITORIA (a ordem define a ordem nos índices), em FirestoreAuditLogRepository.ts;
  2. prefira igualdade (==). Evite novos in, que multiplicam as sub-consultas;
  3. rode npm test: o FirestoreAuditLogRepository.indices.test.ts mostra a lista de índices esperada. Atualize firestore.indexes.json até o teste passar;
  4. adicione o controle em HistoricoAcoesPanel.tsx e a combinação em historicoAuditoria.consultas.test.ts;
  5. publique os índices (ver Build e Deploy).

Notificações

  1. Adicione o tipo em NotificacaoTipo (src/domain/entities/notificacao.ts).
  2. Crie a notificação no caso de uso ou no contexto com id: idNotificacao(tipo, entidadeId, destinatarioUid). Envolva em try/catch: falhar ao notificar não deve derrubar a operação. Para avisar a Administração, use notificarAdministradores(...).
  3. Adicione o ramo do tipo no allow create de match /notifications/{notifId}, em firestore.rules, validando remetente e destinatário.
  4. Em src/components/NotificationsMenu.tsx, defina o selo de status (statusDaNotificacao), a ação ao clicar (abrir) e, se exigir decisão, a regra de "aguardando ação" (exigeAcao).
  5. Cubra o novo tipo em firestore.rules.test.ts.

Consultas ao Firestore e índices

  • Consultas só com igualdade, ou só com ordenação e intervalo em um campo, usam índices automáticos.
  • Igualdade combinada com orderBy ou intervalo em outro campo exige índice composto. Declare-o em firestore.indexes.json e publique.
  • O emulador não acusa índice ausente; só a nuvem acusa. Cubra combinações novas com um teste como o de índices do histórico.
  • Evite combinar vários in: o Firestore multiplica as expansões e tem limite de filtros por consulta.
  • Assinaturas em tempo real (onSnapshot) devem ser abertas só para contas operacionais. Veja como o ReToolContext usa isOperacional.

Cloud Functions

  1. Crie a função em retool/functions/src/index.ts com onCall. A região vem de setGlobalOptions.
  2. Refaça a autorização no servidor lendo users/{request.auth.uid}. O Admin SDK ignora as regras.
  3. Registre a auditoria com o Admin SDK, seguindo os mesmos campos (categoria, resultado, dataHoraServidor).
  4. No cliente, crie o método em src/data/services/ (httpsCallable(functions, 'nome')) e exponha pelo contexto.
  5. Teste nos emuladores em src/tests/funcoes/ (npm run test:funcoes).
  6. O deploy exige o plano Blaze.

Testes e build

Antes de abrir um PR:

npm test
npm run test:rules
npm run test:funcoes
npx tsc --noEmit -p .
npm run build

Os dois comandos de emulador pedem Java; os detalhes estão em Testes.

Scripts auxiliares

Script Para quê Como usar
scripts/emuladores.mjs Sobe os emuladores (npm run emuladores) e roda os testes que dependem deles Pelos scripts npm
scripts/semearEmulador.mjs Cria contas de demonstração nos emuladores node scripts/semearEmulador.mjs, com os emuladores no ar
scripts/criarFormularioBugReTool.js Cria o formulário de reporte de bugs no Google Forms Cole no Google Apps Script e execute criarFormularioBugReTool; os links saem no console
scripts/criarIssuesGitHub.js Cria labels e as issues do backlog inicial, com milestones, no GitHub node scripts/criarIssuesGitHub.js, com o gh autenticado (gh auth login)

O botão "Encontrou algum bug?" da Home abre o formulário já publicado.