Skip to content

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 createCommandHandlerapplyEvent. 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

Distributed under MIT License.