Technical Documentation
Document 02 of 12

Database Schema & Data Model

Dev Team March 2026 Grio AI Education Platform

Grio AI Platform: Database Schema & Data Model

Version: 1.0 Last Updated: 2026-03-24 Status: Internal Technical Documentation


1. Data Model Overview

The Grio AI platform uses a normalized relational model that mirrors the curriculum hierarchy, enabling multi-curriculum support (Uganda NCDC, Kenya CBC, Zambia ZEC, etc.) while maintaining flexible content scaling. The design separates structural entities (Curriculum → Class → Subject) from content entities (Topic → Lesson → LessonContent) and decorrelates user/session data for analytics.

Key Principles

Entity Relationship Diagram (ASCII)

┌─────────────────┐
│   Curriculum    │
│  (e.g., Uganda  │
│     NCDC)       │
└────────┬────────┘
         │ 1
         │ curriculum_id FK
         │
    ┌────▼────────┐          ┌──────────────┐
    │   School    │────────┤ SchoolEnroll │
    └─────────────┘ 1..N    │ (student→    │
                            │  school)     │
                            └──────────────┘
         │ curriculum_id FK
         │
    ┌────▼────────┐         ┌────────────────────┐
    │   Class     │◄────────┤  ClassSubject      │
    │  (e.g.,     │  1 (M:N)│  (junction table)  │
    │  Senior 1)  │ class_id│                    │
    └─────────────┘         └────────┬───────────┘
                                     │ subject_id FK
                            ┌────────▼──────────┐
                            │    Subject       │
                            │  (e.g., Math,   │
                            │   English)       │
                            └─────────────────┘
                                     │ subject_id FK
                            ┌────────▼──────────────────┐
                            │  AI_Context_Rules         │
                            │  (system prompts, conds)  │
                            └───────────────────────────┘

    ┌─────────────┐
    │    Term     │
    │  (e.g.,     │
    │   Term 1)   │
    └────────┬────┘
             │ term_id FK
             │ 1
    ┌────────▼─────────────┐
    │     Topic            │
    │ (e.g., Number        │
    │  Bases, order_index) │
    └────────┬─────────────┘
             │ topic_id FK
             │ 1
    ┌────────▼──────────────────┐
    │    Lesson                 │
    │  (Subtopic, e.g.,        │
    │   "Converting to Binary") │
    └────────┬──────────────────┘
             │ lesson_id FK
             │ 1
    ┌────────▼──────────────────┐
    │   LessonContent           │
    │  (text, video, quiz, etc) │
    └───────────────────────────┘

    ┌─────────────────────┐
    │     ClassSession    │  (Links class, subject, topic, lesson, teacher)
    │ (session context)   │
    └────────┬────────────┘
             │ session_id FK
             │ 1..N
    ┌────────▼────────────────────┐
    │   StudentProgress           │  (Topic completion, scores)
    │                             │
    └─────────────────────────────┘

             ┌─────────────────────┐
             │  LearningHistory    │  (Interactions, state for continuity)
             └─────────────────────┘

2. Core Curriculum Tables

Curriculum

Defines regional education standards (Uganda NCDC, Kenya CBC, Zambia ZEC).

FieldTypeConstraintsNotes
curriculum_idUUIDPKGenerated UUID
nameVARCHAR(255)NOT NULL, UNIQUE“Uganda NCDC 2022”, “Kenya CBC”
countryVARCHAR(100)NOT NULL“Uganda”, “Kenya”, “Zambia”
descriptionTEXTNULLCurriculum overview, context
versionVARCHAR(50)NULL“2022”, “2023”
created_atTIMESTAMPDEFAULT NOW()Audit trail

Example Data:

curriculum_id: 550e8400-e29b-41d4-a716-446655440000
name: Uganda NCDC 2022
country: Uganda
version: 2022

Class

Represents student cohorts (Senior 1, Primary 5, etc.).

FieldTypeConstraintsNotes
class_idUUIDPKGenerated UUID
curriculum_idUUIDFK (Curriculum.curriculum_id)NOT NULL
nameVARCHAR(255)NOT NULL“Senior 1”, “Primary 5”
grade_levelINTNOT NULL1–13 (Uganda), 1–12 (Kenya)
descriptionTEXTNULLClass context, student age range
created_atTIMESTAMPDEFAULT NOW()Audit trail

Example Data:

class_id: 660e8400-e29b-41d4-a716-446655440001
curriculum_id: 550e8400-e29b-41d4-a716-446655440000
name: Senior 1
grade_level: 10

Subject

Academic subjects taught across classes.

FieldTypeConstraintsNotes
subject_idUUIDPKGenerated UUID
nameVARCHAR(255)NOT NULL, UNIQUE“Mathematics”, “English”, “Physics”
descriptionTEXTNULLSubject scope, prerequisites
created_atTIMESTAMPDEFAULT NOW()Audit trail

Example Data:

subject_id: 770e8400-e29b-41d4-a716-446655440002
name: Mathematics
description: Core subject covering numeracy, algebra, geometry, and data analysis

ClassSubject (M:N Junction Table)

Maps classes to subjects; indicates whether subject is compulsory.

FieldTypeConstraintsNotes
class_subject_idUUIDPKGenerated UUID
class_idUUIDFK (Class.class_id)NOT NULL
subject_idUUIDFK (Subject.subject_id)NOT NULL
is_compulsoryBOOLEANDEFAULT TRUECompulsory or elective
order_indexINTNULLDisplay order in class view
created_atTIMESTAMPDEFAULT NOW()Audit trail

Unique Index: (class_id, subject_id)

Example Data:

class_id: 660e8400-e29b-41d4-a716-446655440001
subject_id: 770e8400-e29b-41d4-a716-446655440002
is_compulsory: true
order_index: 1

Term

Semester or term divisions within an academic year.

FieldTypeConstraintsNotes
term_idUUIDPKGenerated UUID
curriculum_idUUIDFK (Curriculum.curriculum_id)NOT NULL
nameVARCHAR(100)NOT NULL“Term 1”, “Semester 1”
order_indexINTNOT NULL1, 2, 3 (ordering within year)
start_dateDATENULLAcademic calendar
end_dateDATENULLAcademic calendar
created_atTIMESTAMPDEFAULT NOW()Audit trail

Example Data:

term_id: 880e8400-e29b-41d4-a716-446655440003
curriculum_id: 550e8400-e29b-41d4-a716-446655440000
name: Term 1
order_index: 1
start_date: 2026-01-12
end_date: 2026-04-10

Topic

Learning units within a class-subject term (e.g., “Number Bases” in Senior 1 Math).

FieldTypeConstraintsNotes
topic_idUUIDPKGenerated UUID
class_subject_idUUIDFK (ClassSubject.class_subject_id)NOT NULL
term_idUUIDFK (Term.term_id)NOT NULL
titleVARCHAR(255)NOT NULL“Number Bases”, “Quadratic Equations”
descriptionTEXTNOT NULLLearning outcomes, scope
order_indexINTNOT NULLSequence within term
estimated_hoursDECIMAL(5,2)NULLCurriculum time allocation
created_atTIMESTAMPDEFAULT NOW()Audit trail

Example Data:

topic_id: 990e8400-e29b-41d4-a716-446655440004
class_subject_id: [ClassSubject Senior 1 Math]
term_id: 880e8400-e29b-41d4-a716-446655440003
title: Number Bases
order_index: 2
estimated_hours: 8.0

Lesson (Subtopic)

Individual lessons within a topic with learning objectives and content mapping.

FieldTypeConstraintsNotes
lesson_idUUIDPKGenerated UUID
topic_idUUIDFK (Topic.topic_id)NOT NULL
titleVARCHAR(255)NOT NULL“Converting Decimal to Binary”
learning_objectiveTEXTNOT NULLClear, measurable outcomes (Bloom’s)
difficulty_levelVARCHAR(50)DEFAULT ‘intermediate’‘beginner’, ‘intermediate’, ‘advanced’
estimated_duration_minsINTNULLTypical lesson duration
order_indexINTNOT NULLSequence within topic
created_atTIMESTAMPDEFAULT NOW()Audit trail

Example Data:

lesson_id: aa0e8400-e29b-41d4-a716-446655440005
topic_id: 990e8400-e29b-41d4-a716-446655440004
title: Converting Decimal to Binary
learning_objective: Students will convert decimal numbers to binary (base 2) using division method
difficulty_level: intermediate
estimated_duration_mins: 45
order_index: 1

LessonContent

Content assets and resources for lessons (text, videos, quizzes, examples).

FieldTypeConstraintsNotes
content_idUUIDPKGenerated UUID
lesson_idUUIDFK (Lesson.lesson_id)NOT NULL
content_typeVARCHAR(50)NOT NULL‘text’, ‘video’, ‘quiz’, ‘example’, ‘image’, ‘pdf’
content_bodyTEXTNULLMarkdown text, formatted content
resource_urlVARCHAR(512)NULLURL to external resource (video, PDF)
ai_promptTEXTNULLPre-crafted prompt for AI context generation
order_indexINTNOT NULLSequence within lesson
created_atTIMESTAMPDEFAULT NOW()Audit trail

Example Data:

content_id: bb0e8400-e29b-41d4-a716-446655440006
lesson_id: aa0e8400-e29b-41d4-a716-446655440005
content_type: text
content_body: "To convert 45 (decimal) to binary: 45÷2=22 r1, 22÷2=11 r0, ..."
order_index: 1

content_id: bb0e8400-e29b-41d4-a716-446655440007
lesson_id: aa0e8400-e29b-41d4-a716-446655440005
content_type: video
resource_url: "https://storage.grio.ai/videos/decimal-to-binary-en.mp4"
order_index: 2

content_id: bb0e8400-e29b-41d4-a716-446655440008
lesson_id: aa0e8400-e29b-41d4-a716-446655440005
content_type: quiz
content_body: "[Quiz JSON: questions about decimal-to-binary conversion]"
order_index: 3

3. AI & Context Tables

AI_Context_Rules

Parameterized system prompts and constraints for AI responses, scoped by subject/class/topic.

FieldTypeConstraintsNotes
rule_idUUIDPKGenerated UUID
subject_idUUIDFK (Subject.subject_id)NULL (if global)
class_idUUIDFK (Class.class_id)NULL (if subject-wide)
topic_idUUIDFK (Topic.topic_id)NULL (if class-wide)
system_promptTEXTNOT NULLE.g., “You are teaching Senior 1 Math…”
constraintsJSONBNULL{“max_tokens”: 500, “tone”: “encouraging”}
knowledge_sourcesJSONBNULL{“include”: [“curriculum_docs”], “exclude”: [“external_web”]}
created_atTIMESTAMPDEFAULT NOW()Audit trail

Hierarchy: Topic rules override Class rules; Class rules override Subject rules; Subject rules override global.

Example Data:

rule_id: cc0e8400-e29b-41d4-a716-446655440009
subject_id: 770e8400-e29b-41d4-a716-446655440002  (Mathematics)
class_id: 660e8400-e29b-41d4-a716-446655440001    (Senior 1)
topic_id: 990e8400-e29b-41d4-a716-446655440004    (Number Bases)
system_prompt: "You are a patient math tutor teaching Senior 1 students about number systems..."
constraints: {"max_tokens": 800, "difficulty_adjust": "intermediate"}

SubjectPaper (Referenced in Legacy Docs)

Optional record linking subjects to official curriculum documents or exam papers.

FieldTypeConstraintsNotes
paper_idUUIDPKGenerated UUID
subject_idUUIDFK (Subject.subject_id)NOT NULL
curriculum_idUUIDFK (Curriculum.curriculum_id)NOT NULL
paper_typeVARCHAR(100)NULL‘curriculum_guide’, ‘exam_paper’, ‘sample_questions’
document_urlVARCHAR(512)NULLLink to PDF or document
academic_yearVARCHAR(10)NULL“2023”, “2024”
created_atTIMESTAMPDEFAULT NOW()Audit trail

4. Session & Progress Tables

ClassSession

Represents teaching/learning sessions, linking teacher, class, subject, and lesson.

FieldTypeConstraintsNotes
session_idUUIDPKGenerated UUID
class_idUUIDFK (Class.class_id)NOT NULL
subject_idUUIDFK (Subject.subject_id)NOT NULL
topic_idUUIDFK (Topic.topic_id)NULL (if topic not selected yet)
lesson_idUUIDFK (Lesson.lesson_id)NULL (if lesson not selected yet)
teacher_idUUIDFK (Users.user_id)NULL (for home learning, NULL)
start_timeTIMESTAMPNOT NULLSession start
end_timeTIMESTAMPNULLSession end (NULL if ongoing)
statusVARCHAR(50)DEFAULT ‘active’‘active’, ‘completed’, ‘paused’
notesTEXTNULLTeacher notes, session summary
created_atTIMESTAMPDEFAULT NOW()Audit trail

Example Data:

session_id: dd0e8400-e29b-41d4-a716-446655440010
class_id: 660e8400-e29b-41d4-a716-446655440001
subject_id: 770e8400-e29b-41d4-a716-446655440002
topic_id: 990e8400-e29b-41d4-a716-446655440004
lesson_id: aa0e8400-e29b-41d4-a716-446655440005
teacher_id: ee0e8400-e29b-41d4-a716-446655440011
start_time: 2026-03-24 09:00:00
status: active

StudentProgress

Tracks student completion and performance per topic.

FieldTypeConstraintsNotes
progress_idUUIDPKGenerated UUID
student_idUUIDFK (Users.user_id)NOT NULL
topic_idUUIDFK (Topic.topic_id)NOT NULL
completion_percentageINT0–100% lessons completed in topic
average_scoreDECIMAL(5,2)0.00–100.00Average quiz/assessment score
statusVARCHAR(50)‘not_started’, ‘in_progress’, ‘completed’Progress state
last_accessed_atTIMESTAMPNULLLast activity timestamp
created_atTIMESTAMPDEFAULT NOW()Audit trail
updated_atTIMESTAMPDEFAULT NOW()Updated on progress change

Unique Index: (student_id, topic_id)


LearningHistory

Detailed interaction log for analytics and “Continue Learning” feature (Grio Continuity).

FieldTypeConstraintsNotes
history_idUUIDPKGenerated UUID
student_idUUIDFK (Users.user_id)NOT NULL
session_idUUIDFK (ClassSession.session_id)NOT NULL
lesson_idUUIDFK (Lesson.lesson_id)NOT NULL
interaction_typeVARCHAR(50)NOT NULL‘view’, ‘quiz_attempt’, ‘ask_question’, ‘complete’
duration_secondsINTNULLTime spent on lesson
quiz_scoreDECIMAL(5,2)NULLScore if interaction is quiz
ai_interaction_logJSONBNULL{“prompt”: “…”, “response”: “…”, “timestamp”: “…”}
timestampTIMESTAMPNOT NULLWhen interaction occurred

5. User & Access Tables

Users

Platform users across all roles and schools.

FieldTypeConstraintsNotes
user_idUUIDPKGenerated UUID
emailVARCHAR(255)NOT NULL, UNIQUEUnique login identifier
nameVARCHAR(255)NOT NULLFull name
roleVARCHAR(50)NOT NULL‘student’, ‘teacher’, ‘school_admin’, ‘super_admin’, ‘independent_learner’
phone_numberVARCHAR(20)NULLOptional contact
password_hashVARCHAR(512)NOT NULLbcrypt or similar
is_activeBOOLEANDEFAULT TRUESoft-delete flag
created_atTIMESTAMPDEFAULT NOW()Audit trail
updated_atTIMESTAMPDEFAULT NOW()Profile updates

Schools

Educational institutions using the Grio platform.

FieldTypeConstraintsNotes
school_idUUIDPKGenerated UUID
nameVARCHAR(255)NOT NULLSchool name
curriculum_idUUIDFK (Curriculum.curriculum_id)NOT NULL
locationVARCHAR(255)NULLCity/region, used for analytics
countryVARCHAR(100)NULLE.g., “Uganda”, “Kenya”
admin_user_idUUIDFK (Users.user_id)NULL (principal/admin)
is_activeBOOLEANDEFAULT TRUESoft-delete flag
created_atTIMESTAMPDEFAULT NOW()Audit trail

SchoolEnrollment

Links students to schools; enables multi-tenancy and row-level security.

FieldTypeConstraintsNotes
enrollment_idUUIDPKGenerated UUID
student_idUUIDFK (Users.user_id)NOT NULL
school_idUUIDFK (Schools.school_id)NOT NULL
enrollment_dateDATENOT NULLWhen student joined school
statusVARCHAR(50)DEFAULT ‘active’‘active’, ‘graduated’, ‘transferred’
class_idUUIDFK (Class.class_id)NULL (may change)
created_atTIMESTAMPDEFAULT NOW()Audit trail

Unique Index: (student_id, school_id)

Multi-Tenancy & RLS: - Query filter: WHERE school_id IN (user_school_ids) ensures data isolation - Session context: User school IDs passed in JWT token for efficient filtering - Teachers see only their school’s students and classes


6. Analytics Tables

SchoolAnalytics (Aggregated)

Daily/weekly aggregations of student engagement and performance by school.

FieldTypeConstraintsNotes
metric_idUUIDPKGenerated UUID
school_idUUIDFK (Schools.school_id)NOT NULL
dateDATENOT NULLMetric date
total_active_studentsINTNULLCount of active learners
lessons_completedINTNULLTopics completed in date window
average_quiz_scoreDECIMAL(5,2)NULLSchool-wide average
engagement_rateDECIMAL(5,2)NULL% students active in period

NationalAnalytics (Aggregated)

Country-level metrics for curriculum oversight.

FieldTypeConstraintsNotes
metric_idUUIDPKGenerated UUID
curriculum_idUUIDFK (Curriculum.curriculum_id)NOT NULL
dateDATENOT NULLMetric date
total_schoolsINTNULLSchools using curriculum
total_studentsINTNULLStudents across all schools
average_topic_completionDECIMAL(5,2)NULL% completion per topic

7. Data Flow Examples

Example 1: Teacher Starts Senior 1 Math, Number Bases Lesson

Flow: 1. Teacher navigates to Class (Senior 1) and selects Subject (Mathematics) - Query: ClassSubject WHERE class_id = 'Senior 1' AND subject_id = 'Math'

  1. System displays Terms for curriculum
    • Query: Term WHERE curriculum_id = 'Uganda NCDC' ORDER BY order_index
  2. Teacher selects Term 1, sees Topics
    • Query: Topic WHERE class_subject_id = <S1-Math> AND term_id = 'Term 1' ORDER BY order_index
  3. Teacher picks Number Bases topic, sees Lessons
    • Query: Lesson WHERE topic_id = 'Number Bases' ORDER BY order_index
  4. Teacher clicks “Converting Decimal to Binary” lesson
    • Query: LessonContent WHERE lesson_id = 'Decimal-to-Binary' ORDER BY order_index
  5. System creates ClassSession
    • INSERT INTO ClassSession (class_id, subject_id, topic_id, lesson_id, teacher_id, start_time, status)
  6. AI system fetches AI_Context_Rules matching (Topic, Class, Subject)
    • Hierarchy: Topic rule > Class rule > Subject rule > Global rule
    • Constructs system prompt for “Senior 1 Math, Number Bases” context

Example 2: Student Continues Learning at Home (Grio Continuity)

Flow: 1. Student (independent_learner or school student outside class hours) opens Grio app 2. System queries LearningHistory for recent sessions - SELECT DISTINCT lesson_id FROM LearningHistory WHERE student_id = ? ORDER BY timestamp DESC LIMIT 5

  1. System displays “Continue Learning” — last lesson accessed
  2. Student clicks “Continue” → redirects to that Lesson and LessonContent
  3. Student progresses through quiz, AI interaction logged to LearningHistory with interaction_type = 'quiz_attempt'
  4. System updates StudentProgress
    • Recalculates completion_percentage and average_score for the Topic

8. Multi-Curriculum Design

Supporting Uganda NCDC, Zambia ZEC, Kenya CBC

The schema decouples structural hierarchy from curriculum details:

Query Pattern:

-- Fetch curriculum for a school
SELECT c.* FROM Curriculum c
JOIN Schools s ON s.curriculum_id = c.curriculum_id
WHERE s.school_id = ?

-- Fetch classes in curriculum
SELECT * FROM Class WHERE curriculum_id = ? ORDER BY grade_level

-- Fetch subjects offered to a class
SELECT s.* FROM Subject s
JOIN ClassSubject cs ON cs.subject_id = s.subject_id
WHERE cs.class_id = ? ORDER BY cs.order_index

9. Indexing & Performance Notes

TableIndexRationale
ClassSubject(class_id, subject_id)Enforce uniqueness; common query
StudentProgress(student_id, topic_id)Enforce uniqueness; query by student
StudentProgress(topic_id)Analytics — completion by topic
LearningHistory(student_id, timestamp DESC)Recent interactions, continuity
LearningHistory(session_id)Fetch history for a session
ClassSession(teacher_id, start_time DESC)Teacher’s session timeline
ClassSession(class_id, status)Active sessions per class
SchoolEnrollment(school_id, status)Students in school, by status
SchoolEnrollment(student_id, status)Student’s enrollment
LessonContent(lesson_id, order_index)Fetch content in sequence
Topic(class_subject_id, term_id, order_index)Topics per term per class-subject
Users(email)Login lookups
Schools(curriculum_id)Schools per curriculum

Caching Strategy


10. Data Integrity & Constraints

Foreign Key Integrity

Business Logic Constraints


End of Database Schema Document

Last reviewed: 2026-03-24