Skip to content

Domain Model

This document describes the core entities of Neemias, their attributes, and relationships, as implemented in the backend (Cloudflare Workers + D1) and consumed by the frontend (React SPA).

Glossary (Portuguese → English)

Portuguese termEntity / ConceptUsage in code
Presença / ChamadaAttendance — mark a student as present or absentAttendanceEvent.actionType: MARK_PRESENT, MARK_ABSENT
Aluno / EstudanteStudent — child registered in the systemStudent entity, students table
TurmaClass — age group (e.g., Nursery, Juniors)Class entity, classes table
AulaClassSlot (recurring) + ClassSession (concrete occurrence)ClassSlot (day+time), ClassSession (specific date)
Núcleo / CélulaNucleus — small group by regionNucleus entity, nuclei table
RegiãoNucleusRegion — 7 fixed colorsAzul Celeste, Azul, Amarela, Branca, Vermelha, Laranja, Verde
ResponsávelGuardian — parent/guardian of the studentguardianName, guardianNameAlt
FrequênciaReport — weekly/monthly attendance, per studentReportsPage — Weekly Attendance, per Class, per Student
MembresiaFamily membership statusMEMBRO, NAO_MEMBRO, DESCONHECIDO

Entities

Student (Aluno)

Table: students (D1 SQLite) / Dexie table: students (IndexedDB)

AttributeTypeDescription
student_idTEXT PKUnique identifier
display_nameTEXTStudent's display name
photo_refTEXTPhoto reference
statusTEXTACTIVE or DELETED
deleted_justificationTEXTRequired justification (10-500 chars) when deleting
guardian_nameTEXTPrimary guardian's name
guardian_name_altTEXTAlternate guardian's name
birth_dateTEXTDate of birth
phonesJSON arrayPhone list (min 1, max 3)
family_membership_statusTEXTFamily membership status
address_streetTEXTStreet
address_numberTEXTNumber
address_complementTEXTComplement
address_neighborhoodTEXTNeighborhood
address_cityTEXTCity
address_stateTEXTState
address_zipTEXTZIP code
class_idTEXT FKReference to classes
nucleus_participatesINTEGER0 or 1
nucleus_regionTEXTNucleus region
nucleus_nameTEXTNucleus name
allergiesTEXTAllergies
special_needsTEXTSpecial needs

Rules: Soft-delete with mandatory justification (10-500 chars). Attendance history preserved after deletion. Index: (status, updated_at DESC).

Class (Turma)

Table: classes (D1 SQLite) / Dexie table: classes (IndexedDB)

AttributeTypeDescription
class_idTEXT PKUnique identifier
nameTEXT UNIQUEClass name
age_minINTEGERMinimum age
age_maxINTEGERMaximum age
statusTEXTACTIVE or DELETED

Default seed: Berçário (Nursery), Maternal Infantil (Toddlers), Jardim de Infância (Kindergarten), Infantil (Preschool), Juniores 1 (Juniors 1), Juniores 2 (Juniors 2), Pré-Adolescentes (Pre-Teens).

Rules: Soft-delete via status = 'DELETED'. Only ADMIN may create/edit.

ClassSlot (Recurring class)

Dexie table: classSlots (IndexedDB, frontend only)

AttributeTypeDescription
slot_idTEXT PKUnique identifier
day_of_weekINTEGER0=Sun, 1=Mon, ..., 6=Sat
start_timeTEXTStart time (HH:MM)
labelTEXTDescriptive label
session_dateTEXT?One-off class date (YYYY-MM-DD), undefined for weekly recurring

ClassSession (Concrete class occurrence)

Dexie table: classSessions (IndexedDB, frontend only)

AttributeTypeDescription
session_idTEXT PKUnique identifier
slot_idTEXT FKReference to ClassSlot
session_dateTEXTSession date (YYYY-MM-DD)

AttendanceEvent (Attendance Event)

Table: attendance_events (D1 SQLite) / Dexie table: attendanceEvents (IndexedDB)

AttributeTypeDescription
event_idTEXT PKUnique identifier
student_idTEXT FKReference to students
class_session_idTEXT FKReference to ClassSession (frontend)
action_typeTEXTMARK_PRESENT or MARK_ABSENT
happened_atTEXTEvent timestamp
actor_user_idTEXT FKUser who performed the action
actor_roleTEXTActor's role at the time
server_timestampTEXTServer timestamp
is_conflict_loserINTEGER0 or 1 — loser in conflict resolution
conflict_superseded_byTEXT?Pointer to winning event (frontend)

Rules: Event-sourced — every attendance mark is an immutable event. Projection derives current state. Index: (student_id, server_timestamp DESC).

Nucleus (Núcleo)

Table: nuclei (D1 SQLite)

AttributeTypeDescription
nucleus_idTEXT PKUnique identifier
regionTEXTOne of 7 fixed regions
nameTEXTNucleus name
statusTEXTACTIVE or DELETED

Fixed regions: Azul Celeste (Sky Blue), Azul (Blue), Amarela (Yellow), Branca (White), Vermelha (Red), Laranja (Orange), Verde (Green).

Rules: Soft-delete via status = 'DELETED'. Only ADMIN may create/edit.

User (Usuário)

Table: users (D1 SQLite) / Dexie table: users (IndexedDB)

AttributeTypeDescription
user_idTEXT PKUnique identifier
emailTEXT UNIQUEUser's email
display_nameTEXTDisplay name
roleTEXTADMIN, CHAMADOR, RELATORIOS, or CADASTRO
statusTEXTACTIVE or DELETED
password_hashTEXTPBKDF2 hash in pbkdf2:<hexSalt>:<hexHash> format

Role (Papel / Profile)

Defined in packages/permissions/index.ts — single source of truth.

RoleCodeMain permissions
AdminADMINFull access: CRUD students/classes/nuclei, attendance, reports, seed
ChamadorCHAMADORMark attendance, search students
RelatóriosRELATORIOSView attendance reports
CadastroCADASTROCreate and edit students and classes

Relationships

User ──┐
       │ actor_user_id

AttendanceEvent ◄──── Student ──────── Class
       │                  │
       │                  │ class_id
       │                  ▼
       │                Class

       │                  ┌── Nucleus (nucleus_participates)
       │                  │
       └──────────────────┘
  • Student → Class: N:1 via class_id FK.
  • Student → Nucleus: Optional participation (nucleus_participates 0/1).
  • AttendanceEvent → Student: N:1 via student_id FK.
  • AttendanceEvent → User: N:1 via actor_user_id — every event records who generated it.
  • ClassSlot → ClassSession: 1:N — a recurring slot generates multiple concrete sessions.
  • ClassSession → AttendanceEvent: 1:N — each session has multiple attendance events.

Event Sourcing and Soft-Delete

  • Event Sourcing: Every primary entity mutation (students, attendance) generates an immutable event. The current state is a projection derived from these events. Auxiliary tables: student_events, user_events.
  • Soft-delete: No primary entity is physically removed. The status field transitions to DELETED. Justification is mandatory for student deletions.

Sources: workers/CONTEXT.md, app/CONTEXT.md

Distributed under MIT License.