Skip to content

Visão Geral do App

O frontend do Neemias é uma PWA (Progressive Web App) construída com foco em offline-first e resiliência de rede. A aplicação funciona plenamente mesmo sem conexão com o backend, sincronizando automaticamente ao reconectar.

Stack Tecnológica

CamadaTecnologia
FrameworkReact 19 + TypeScript
BuildVite 6
EstilizaçãoTailwind CSS v4 + shadcn/ui + MUI 7
Estado / PersistênciaDexie.js (IndexedDB) via useLiveQuery
RoteamentoReact Router v7 com PermissionGuard por rota
Autenticaçãowindow.crypto.subtle (SHA-256 client-side), sessão em IndexedDB com TTL de 24h
PWAvite-plugin-pwa, tema #01696f
i18nPortuguês brasileiro fixo — objeto pt_BR em app/src/app/utils/i18n.ts

Gerenciamento de Estado

Sem Redux ou Zustand. O estado é derivado diretamente do IndexedDB via Dexie.js com o hook useLiveQuery. Cada componente que precisa de dados reativos assina consultas ao banco local, que é a fonte da verdade.

Caminho de Escrita (Write Path)

Toda mutação no sistema segue o padrão Event Sourcing:

  1. EventWriter — singleton que gerencia gravação de eventos (writeAttendance(), writeStudent())
  2. Cada evento é gravado na tabela local + enfileirado na syncQueue em uma única transação Dexie (atômica)
  3. A interface reage ao evento — o estado atual é uma projeção dos eventos persistidos
typescript
// Factory para CRUD genérico com role guard e soft-delete
createCrudService<T>(config) → { list, create, update, remove, ... }

Entidades Principais

Student (app/src/db/types.ts)

  • studentId, displayName, photoRef, status (ACTIVE|DELETED)
  • guardianName, guardianNameAlt?, birthDate?, phones: PhoneEntry[], address: Address
  • classId? → FK para Class
  • nucleusParticipates, nucleusRegion?, nucleusName?
  • allergies?, specialNeeds?, familyMembershipStatus

Class (Turma)

  • classId, name, ageMin?, ageMax?, status (ACTIVE|DELETED)
  • Seed: Berçário, Maternal Infantil, Jardim de Infância, Infantil, Juniores 1/2, Pré-Adolescentes

ClassSlot / ClassSession (Aula)

  • ClassSlot: dia da semana + horário (dayOfWeek, startTime, label) — recorrente semanal ou avulsa
  • ClassSession: ocorrência concreta (sessionDate), vinculada a um ClassSlot

AttendanceEvent

  • eventId, studentId, classSessionId, actionType (MARK_PRESENT|MARK_ABSENT)
  • actorId, actorRole, timestamp, syncState, isConflictLoser, conflictSupersededBy?

LocalUser

  • userId, username, displayName, passwordHash?, role, status
  • Roles: ADMIN, CHAMADOR, RELATORIOS, CADASTRO

Regras de Negócio

  1. RBAC — 4 papéis com permissões explícitas. CHAMADOR só marca presença; CADASTRO gerencia alunos/aulas; RELATORIOS só vê relatórios; ADMIN acesso total.
  2. Soft delete — alunos viram status: "DELETED" com justificativa obrigatória (10-500 chars). Histórico de presença preservado.
  3. Event sourcing — toda mutação passa pelo EventWriter com transação Dexie atômica.
  4. Offline-first — IndexedDB é fonte da verdade local. Sync automático com backoff exponencial.
  5. Sessão expira em 24h — modal força reautenticação. AttendancePage bloqueia marcação com sessão expirada.
  6. Criptografia em repouso — dados sensíveis (changePayload, justification) criptografados com AES via hash da senha.
  7. Conflitos de sincronia — perdedor marcado com isConflictLoser: true + ponteiro conflictSupersededBy.

Arquivos-Chave

ArquivoFunção
app/src/db/db.tsSchema Dexie + migrações (v1→v6)
app/src/db/types.tsDefinições de tipos de todas as entidades
app/src/modules/eventWriter.tsEventWriter — writeAttendance(), writeStudent()
app/src/modules/shared/createCrudService.tsFactory de CRUD com role guard
app/src/modules/sync/registry.tsRegistro de providers de sincronia com fallback
app/src/modules/attendance/Serviço + UI de chamada
app/src/modules/students/Serviço CRUD de alunos
app/src/modules/classes/Serviço CRUD de turmas
app/src/modules/sync/Sincronia com backend + resolução de conflitos
app/src/app/context/AuthContext.tsxEstado de autenticação, roles, sessão
app/src/app/context/OfflineContext.tsxDreno automático da fila de sync
app/src/app/utils/i18n.tsTraduções pt-BR (~324 linhas)
app/vite.config.tsConfiguração Vite + Vitest

Fonte: app/CONTEXT.md

Distributed under MIT License.