Business Rules
Neemias follows 12 business rules that govern system behavior across all layers (frontend, backend, and synchronization). These rules are immutable and any implementation decision must respect them.
1. Role-Based Access Control (RBAC) — FR-001, FR-002
Four roles — ADMIN, CHAMADOR, RELATORIOS, CADASTRO — with explicit permissions defined in a single source (packages/permissions/index.ts). ADMIN has full access (17 permissions); the other roles are restricted to the permissions of their function.
2. Soft-Delete — FR-007
No primary entity is physically deleted from the database. Students, classes, núcleos, and users are marked with status: "DELETED", preserving the full history. Student deletion requires a mandatory justification of 10 to 500 characters.
3. Event Sourcing — FR-004
Every state mutation generates an immutable event. Attendance records become entries in the attendance_events table; student changes become entries in the unified events table via createCommandHandler → applyEvent. The current state of each entity is a projection derived from the event chain (backend) or the local SQLite store (frontend). The frontend implements EventWriter, which writes the event and enqueues synchronization in a single atomic transaction.
4. Offline-First — SR-001
IndexedDB (via Dexie) is the local source of truth. The user works normally without an internet connection — all read and write operations are resolved locally. Synchronization with the backend is automatic and uses exponential backoff when connectivity is restored.
5. Session TTL (24 hours) — FR-005
The user session expires after 24 hours of inactivity. Upon expiration, a modal forces re-authentication before any protected operation. The JWT access token has a 15-minute TTL and is renewed via refresh token (7 days) with automatic rotation.
6. Expired Session Blocks Attendance — FR-005
The attendance page (AttendancePage) checks session validity before allowing any attendance marking. With an expired session, the attendance flow is halted until the user re-authenticates.
7. Encryption at Rest
Sensitive data stored locally — such as changePayload and deletion justifications — is encrypted with AES-GCM using a key derived from the user's password hash (SHA-256 + PBKDF2). This protects data even if the device is compromised.
8. Conflict Resolution on Sync
When two conflicting events arrive at the backend, the ADMIN_PRECEDENCE rule decides the winner: the event from the higher-weight role prevails. In case of a tie, LAST_TIMESTAMP_WINS. The losing event is marked with isConflictLoser: true and a conflictSupersededBy pointer references the winner.
9. Mandatory Idempotency
Every mutation (POST/PATCH) requires the Idempotency-Key header. The backend maintains an idempotency ledger (key, user_id) with payload hash. Repeated requests with the same key and same payload return the original response; same key with a different payload returns HTTP 409 Conflict.
10. Phone Numbers: Minimum 1, Maximum 3
Each student must have at least 1 and at most 3 phone numbers registered. Validation is applied both on the frontend (TypeScript/Zod) and backend (worker Zod schemas).
11. Unique Email per User — FR-001
Each user's email is unique in the system. The UNIQUE constraint on the users table ensures uniqueness in the database; the frontend validates duplicates before submission.
12. Audit Trail
Every relevant operation — login, creation, editing, deletion, permission changes — generates an immutable record in the audit_logs table with correlation_id, actor_user_id, actor_role, endpoint, outcome, and details in JSON. This trail meets LGPD traceability requirements.
Sources: PRD §8 · workers/CONTEXT.md · app/CONTEXT.md