Skip to main content

Database Schema

The complete schema is in core/models.py.

Core Entities

ModelPurpose
PersonCard holder profile and identity data (is_archived flag controls active/archived status)
DevicePhysical scanner identity and area assignment
RecordCard scan event, with optional class or event context
DeviceLogDevice heartbeat and connectivity telemetry
DepartmentOrganizational grouping
ProgramAcademic program linked to a department with code and title
AreaPhysical deployment location
ClassClass attendance domain model
EventEvent attendance domain model
SemesterAcademic period model
UserLoginEventAudit log of successful user logins (IP, user agent, source)
UserActivityEvent log of user page visits with debounce (full history)
IDCardIssued physical card instance for a Person; lifecycle state (draft, active, lost, damaged, expired)
IDCardPrintLogAppend-only audit log of every card print event (who printed, when, why)
DatasetAsynchronous dataset export job and reusable template for ML and data visualization with strict PII anonymization

Dataset export & ML hygiene: Dataset stores export configurations (config), status (pending, processing, ready, failed, expired), file artifacts, and manifest summaries. Generated archives are automatically cleaned up from storage after a 7-day TTL while preserving the dataset definition for one-click re-generation. Zero-trust sanitization ensures personal PII (names, personal contacts, government IDs, images) is never exported.

ID card lifecycle: Person.active_card (FK, nullable) points at the currently active IDCard. Each print issues a new IDCard (status active) and expires the previous one (expired), so historical card numbers still resolve scans to the same person. IDCardPrintLog records the reason (first_issue, lost_replacement, damaged_replacement, reprint_error, info_update, test_print) and the printed_by user for auditing and per-person print-count reporting. The legacy Person.card_number / id_image / id_image_back fields are retained for backward compatibility but deprecated in favour of IDCard.

Record attribution: Record stores the raw scanned card_number (not a FK), so the admin list, Record.__str__, and the MCP attendance reports resolve the person via core.card_resolution.resolve_person_by_card_number — which consults IDCard history (including expired cards) before falling back to the current Person.card_number. This keeps historical scans attributing to the right person after a card is reissued with a new RFID.

Model-Level Permissions

Custom model permissions are declared in core/models.py for visibility control and action authorization:

ModelPermission CodenamePurpose
Classview_all_classesPermit viewing all Class records in admin without instructor/co-instructor restriction
Eventview_all_eventsPermit viewing all Event records in admin without facilitator restriction
Personimport_personsPermit importing person records from external files
Personscan_personsPermit access to the Scan Persons dashboard (only grants page/view access)
Personperson_id_registrationPermit registering new IDs
Personmigrate_card_numbersPermit migrating legacy card numbers
AIAgentaccess_ai_agentPermit access to the Onyx AI chat widget in the admin portal

Relationship Snapshot

  • Department links to Person, Class, Event, Program, and access mappings
  • Program belongs to a Department
  • Device belongs to Area and emits DeviceLog entries
  • Record links card scans to Device, the User who performed the scan, and optional Class or Event
  • Semester scopes Class and Event timing windows
  • UserLoginEvent and UserActivity link to the Django auth User model for audit trail