Regras de Negócio
O Neemias segue 12 regras de negócio que regem o comportamento do sistema em todas as camadas (frontend, backend e sincronização). Estas regras são imutáveis e qualquer decisão de implementação deve respeitá-las.
1. Controle de Acesso Baseado em Papéis (RBAC) — FR-001, FR-002
Quatro papéis — ADMIN, CHAMADOR, RELATORIOS, CADASTRO — com permissões explícitas definidas em fonte única (packages/permissions/index.ts). O ADMIN possui acesso total (17 permissões); os demais papéis são restritos às permissões de sua função.
2. Soft-Delete — FR-007
Nenhuma entidade principal é excluída fisicamente do banco de dados. Alunos, turmas, núcleos e usuários são marcados com status: "DELETED", preservando o histórico completo. A exclusão de alunos exige justificativa obrigatória de 10 a 500 caracteres.
3. Event Sourcing — FR-004
Toda mutação de estado gera um evento imutável. Presenças viram registros na tabela attendance_events; alterações de alunos viram registros na tabela unificada events via createCommandHandler → applyEvent. O estado atual de cada entidade é uma projeção derivada da cadeia de eventos (backend) ou do SQLite local (frontend). O frontend implementa o EventWriter, que grava o evento e enfileira a sincronização em uma única transação atômica.
4. Offline-First — SR-001
O IndexedDB (via Dexie) é a fonte da verdade local. O usuário trabalha normalmente sem conexão com a internet — todas as operações de leitura e escrita são resolvidas localmente. A sincronização com o backend é automática e usa backoff exponencial quando a conectividade é restaurada.
5. TTL de Sessao (24 horas) — FR-005
A sessão do usuário expira após 24 horas de inatividade. Ao expirar, um modal força a reautenticação antes de qualquer operação protegida. O access token JWT possui TTL de 15 minutos e é renovado via refresh token (7 dias) com rotação automática.
6. Sessao Expirada Bloqueia Chamada — FR-005
A página de chamada (AttendancePage) verifica a validade da sessão antes de permitir qualquer marcação de presença. Com a sessão expirada, o fluxo de chamada é interrompido até que o usuário se reautentique.
7. Criptografia em Repouso
Dados sensíveis armazenados localmente — como changePayload e justificativas de exclusão — são criptografados com AES-GCM utilizando uma chave derivada do hash da senha do usuário (SHA-256 + PBKDF2). Isso protege os dados mesmo que o dispositivo seja comprometido.
8. Resolução de Conflitos na Sincronização
Quando dois eventos conflitantes chegam ao backend, a regra ADMIN_PRECEDENCE decide o vencedor: o evento do papel com maior peso prevalece. Em caso de empate, LAST_TIMESTAMP_WINS. O evento perdedor é marcado com isConflictLoser: true e um ponteiro conflictSupersededBy aponta para o vencedor.
9. Idempotência Obrigatória
Toda mutação (POST/PATCH) exige o header Idempotency-Key. O backend mantém um ledger de idempotência (key, user_id) com hash do payload. Requisições repetidas com a mesma chave e mesmo payload retornam a resposta original; chave igual com payload diferente retorna HTTP 409 Conflict.
10. Telefones: Mínimo 1, Máximo 3
Cada aluno deve ter no mínimo 1 e no máximo 3 números de telefone cadastrados. A validação é aplicada tanto no frontend (TypeScript/Zod) quanto no backend (schemas Zod do worker).
11. E-mail Unico por Usuario — FR-001
O e-mail de cada usuário é único no sistema. A constraint UNIQUE na tabela users garante a unicidade no banco; o frontend valida duplicidade antes do envio.
12. Trilha de Auditoria
Toda operação relevante — login, criação, edição, exclusão, alteração de permissões — gera um registro imutável na tabela audit_logs com correlation_id, actor_user_id, actor_role, endpoint, outcome e detalhes em JSON. Esta trilha atende aos requisitos de rastreabilidade da LGPD.
Fontes: PRD §8 · workers/CONTEXT.md · app/CONTEXT.md