| """ |
| DRP Backend β SQLAlchemy Models |
| All 12+ tables as defined in the PRD and implementation plan. |
| """ |
|
|
| import uuid |
| from datetime import datetime |
|
|
| from sqlalchemy import ( |
| Column, String, Integer, Float, Boolean, DateTime, Text, |
| ForeignKey, JSON |
| ) |
| from sqlalchemy.orm import relationship |
| from database import Base |
|
|
|
|
| def generate_uuid(): |
| return str(uuid.uuid4()) |
|
|
|
|
| |
| |
| |
|
|
| class Programme(Base): |
| __tablename__ = "programme" |
|
|
| programme_id = Column(String, primary_key=True, default=generate_uuid) |
| name = Column(String, nullable=False) |
| state_code = Column(String, nullable=False) |
| year = Column(Integer, nullable=False) |
| created_at = Column(DateTime, default=datetime.utcnow) |
|
|
| schools = relationship("School", back_populates="programme") |
|
|
|
|
| class District(Base): |
| __tablename__ = "district" |
|
|
| district_id = Column(String, primary_key=True, default=generate_uuid) |
| name = Column(String, nullable=False) |
| state_code = Column(String, nullable=False) |
|
|
| schools = relationship("School", back_populates="district") |
|
|
|
|
| class School(Base): |
| __tablename__ = "school" |
|
|
| school_id = Column(String, primary_key=True, default=generate_uuid) |
| udise_code = Column(String, unique=True, nullable=False) |
| name = Column(String, nullable=False) |
| district_id = Column(String, ForeignKey("district.district_id")) |
| block = Column(String) |
| programme_id = Column(String, ForeignKey("programme.programme_id")) |
| whatsapp_group_link = Column(String, nullable=True) |
| created_at = Column(DateTime, default=datetime.utcnow) |
|
|
| programme = relationship("Programme", back_populates="schools") |
| district = relationship("District", back_populates="schools") |
| classes = relationship("ClassAccount", back_populates="school") |
| teachers = relationship("TeacherAccount", back_populates="school") |
|
|
|
|
| |
| |
| |
|
|
| class ClassAccount(Base): |
| __tablename__ = "class_account" |
|
|
| class_id = Column(String, primary_key=True, default=generate_uuid) |
| school_id = Column(String, ForeignKey("school.school_id"), nullable=False) |
| grade = Column(Integer, nullable=False) |
| section = Column(String, nullable=False) |
| year = Column(Integer, nullable=False) |
| state = Column(String, default="not_started") |
| current_cluster_id = Column(String, ForeignKey("cluster.cluster_id"), nullable=True) |
| reading_level = Column(String, nullable=True) |
| whatsapp_group_link = Column(String, nullable=True) |
| created_at = Column(DateTime, default=datetime.utcnow) |
|
|
| school = relationship("School", back_populates="classes") |
| journey = relationship("ClassJourney", back_populates="class_account", uselist=False) |
| sessions = relationship("SessionLog", back_populates="class_account") |
| achievements = relationship("Achievement", back_populates="class_account") |
| teacher_mappings = relationship("TeacherClassMapping", back_populates="class_account") |
|
|
|
|
| class TeacherAccount(Base): |
| __tablename__ = "teacher_account" |
|
|
| teacher_id = Column(String, primary_key=True, default=generate_uuid) |
| name = Column(String, nullable=False) |
| mobile_hash = Column(String, nullable=True) |
| phone = Column(String, nullable=True) |
| email = Column(String, unique=True, nullable=True) |
| password_hash = Column(String, nullable=True) |
| school_id = Column(String, ForeignKey("school.school_id"), nullable=True) |
| role = Column(String, default="teacher") |
| activation_token = Column(String, unique=True, nullable=True) |
| is_active = Column(Boolean, default=False) |
| has_seen_onboarding = Column(Boolean, default=False) |
| created_at = Column(DateTime, default=datetime.utcnow) |
|
|
| school = relationship("School", back_populates="teachers") |
| class_mappings = relationship("TeacherClassMapping", back_populates="teacher") |
| sessions = relationship("SessionLog", back_populates="teacher") |
|
|
|
|
| class TeacherClassMapping(Base): |
| __tablename__ = "teacher_class_mapping" |
|
|
| id = Column(String, primary_key=True, default=generate_uuid) |
| teacher_id = Column(String, ForeignKey("teacher_account.teacher_id"), nullable=False) |
| class_id = Column(String, ForeignKey("class_account.class_id"), nullable=False) |
| role = Column(String, default="primary") |
| is_default = Column(Boolean, default=False) |
|
|
| teacher = relationship("TeacherAccount", back_populates="class_mappings") |
| class_account = relationship("ClassAccount", back_populates="teacher_mappings") |
|
|
|
|
| |
| |
| |
|
|
| class Book(Base): |
| __tablename__ = "book" |
|
|
| book_id = Column(String, primary_key=True, default=generate_uuid) |
| title = Column(String, nullable=False) |
| author = Column(String) |
| illustrator = Column(String) |
| level = Column(Integer, nullable=False) |
| theme = Column(String, nullable=False) |
| language = Column(String, default="English") |
| cover_url = Column(String) |
| has_readalong = Column(Boolean, default=False) |
| pages = Column(JSON, default=list) |
| activity_lets_talk = Column(Text, nullable=True) |
| activity_lets_understand = Column(JSON, nullable=True) |
| activity_lets_play = Column(JSON, nullable=True) |
| read_count = Column(Integer, default=0) |
|
|
|
|
| class Cluster(Base): |
| __tablename__ = "cluster" |
|
|
| cluster_id = Column(String, primary_key=True, default=generate_uuid) |
| grade = Column(Integer, nullable=False) |
| level = Column(Integer, nullable=False) |
| theme = Column(String, nullable=False) |
| book_ids = Column(JSON, nullable=False) |
| connecting_thread = Column(String, nullable=True) |
| secondary_theme = Column(String, nullable=True) |
|
|
|
|
| |
| |
| |
|
|
| class ClassJourney(Base): |
| __tablename__ = "class_journey" |
|
|
| journey_id = Column(String, primary_key=True, default=generate_uuid) |
| class_id = Column(String, ForeignKey("class_account.class_id"), unique=True, nullable=False) |
| cluster_sequence = Column(JSON, default=list) |
| completed_cluster_ids = Column(JSON, default=list) |
| current_book_index = Column(Integer, default=0) |
| total_books_read = Column(Integer, default=0) |
|
|
| class_account = relationship("ClassAccount", back_populates="journey") |
|
|
|
|
| class SessionLog(Base): |
| __tablename__ = "session_log" |
|
|
| session_id = Column(String, primary_key=True, default=generate_uuid) |
| class_id = Column(String, ForeignKey("class_account.class_id"), nullable=False) |
| teacher_id = Column(String, ForeignKey("teacher_account.teacher_id"), nullable=True) |
| substitute_name = Column(String, nullable=True) |
| book_id = Column(String, ForeignKey("book.book_id"), nullable=False) |
| cluster_id = Column(String, ForeignKey("cluster.cluster_id"), nullable=False) |
| timestamp = Column(DateTime, default=datetime.utcnow) |
| device_type = Column(String, default="web") |
| readalong_done = Column(Boolean, default=False) |
| activity_submitted = Column(Boolean, default=False) |
| completed = Column(Boolean, default=False) |
|
|
| class_account = relationship("ClassAccount", back_populates="sessions") |
| teacher = relationship("TeacherAccount", back_populates="sessions") |
| activity_submissions = relationship("ActivitySubmission", back_populates="session") |
| feedback = relationship("Feedback", back_populates="session", uselist=False) |
|
|
|
|
| class ActivitySubmission(Base): |
| __tablename__ = "activity_submission" |
|
|
| submission_id = Column(String, primary_key=True, default=generate_uuid) |
| session_id = Column(String, ForeignKey("session_log.session_id"), nullable=False) |
| activity_type = Column(String, nullable=False) |
| selected_option = Column(String, nullable=False) |
| is_correct = Column(Boolean, nullable=False) |
| score = Column(Float, default=0.0) |
| submitted_at = Column(DateTime, default=datetime.utcnow) |
|
|
| session = relationship("SessionLog", back_populates="activity_submissions") |
|
|
|
|
| class Feedback(Base): |
| __tablename__ = "feedback" |
|
|
| feedback_id = Column(String, primary_key=True, default=generate_uuid) |
| session_id = Column(String, ForeignKey("session_log.session_id"), unique=True, nullable=False) |
| feedback_emoji = Column(String, nullable=True) |
| feedback_quality = Column(String, nullable=True) |
|
|
| session = relationship("SessionLog", back_populates="feedback") |
|
|
|
|
| class Achievement(Base): |
| __tablename__ = "achievement" |
|
|
| achievement_id = Column(String, primary_key=True, default=generate_uuid) |
| class_id = Column(String, ForeignKey("class_account.class_id"), nullable=False) |
| type = Column(String, nullable=False) |
| badge_key = Column(String, nullable=True) |
| earned_at = Column(DateTime, default=datetime.utcnow) |
|
|
| class_account = relationship("ClassAccount", back_populates="achievements") |
|
|
|
|
| |
| |
| |
|
|
| class AdminAccount(Base): |
| __tablename__ = "admin_account" |
|
|
| admin_id = Column(String, primary_key=True, default=generate_uuid) |
| name = Column(String, nullable=False) |
| email = Column(String, unique=True, nullable=False) |
| password_hash = Column(String, nullable=False) |
| role = Column(String, nullable=False) |
| school_id = Column(String, ForeignKey("school.school_id"), nullable=True) |
| district_id = Column(String, ForeignKey("district.district_id"), nullable=True) |
| state_code = Column(String, nullable=True) |
| created_at = Column(DateTime, default=datetime.utcnow) |
|
|
|
|
| class EscalationTicket(Base): |
| __tablename__ = "escalation_ticket" |
|
|
| ticket_id = Column(String, primary_key=True, default=generate_uuid) |
| type = Column(String, nullable=False) |
| severity = Column(String, default="medium") |
| school_id = Column(String, ForeignKey("school.school_id"), nullable=True) |
| class_id = Column(String, ForeignKey("class_account.class_id"), nullable=True) |
| description = Column(Text, nullable=False) |
| status = Column(String, default="open") |
| created_by = Column(String, nullable=True) |
| assigned_to = Column(String, nullable=True) |
| created_at = Column(DateTime, default=datetime.utcnow) |
| resolved_at = Column(DateTime, nullable=True) |
|
|
|
|
| class SystemHealthLog(Base): |
| __tablename__ = "system_health_log" |
|
|
| log_id = Column(String, primary_key=True, default=generate_uuid) |
| timestamp = Column(DateTime, default=datetime.utcnow) |
| api_latency_ms = Column(Float, default=0.0) |
| error_count = Column(Integer, default=0) |
| active_sessions = Column(Integer, default=0) |
| sync_queue_depth = Column(Integer, default=0) |
| uptime_percent = Column(Float, default=100.0) |
|
|
|
|
| class EventLog(Base): |
| __tablename__ = "event_log" |
|
|
| event_id = Column(String, primary_key=True, default=generate_uuid) |
| event_type = Column(String, nullable=False) |
| actor_type = Column(String, nullable=True) |
| actor_id = Column(String, nullable=True) |
| metadata_json = Column(JSON, nullable=True) |
| timestamp = Column(DateTime, default=datetime.utcnow) |
|
|
|
|
| class Notification(Base): |
| __tablename__ = "notification" |
|
|
| notification_id = Column(String, primary_key=True, default=generate_uuid) |
| teacher_id = Column(String, ForeignKey("teacher_account.teacher_id"), nullable=True) |
| class_id = Column(String, ForeignKey("class_account.class_id"), nullable=True) |
| type = Column(String, nullable=False) |
| message = Column(Text) |
| status = Column(String, default="pending") |
| created_at = Column(DateTime, default=datetime.utcnow) |
|
|
|
|
| |
| |
| |
|
|
| class FieldStaff(Base): |
| __tablename__ = "field_staff" |
|
|
| staff_id = Column(String, primary_key=True, default=generate_uuid) |
| name = Column(String, nullable=False) |
| phone = Column(String, nullable=True) |
| email = Column(String, unique=True, nullable=False) |
| password_hash = Column(String, nullable=False) |
| district_id = Column(String, ForeignKey("district.district_id"), nullable=False) |
| assigned_blocks = Column(JSON, default=list) |
| is_active = Column(Boolean, default=True) |
| created_at = Column(DateTime, default=datetime.utcnow) |
|
|
| school_mappings = relationship("SchoolStaffMapping", back_populates="staff") |
|
|
|
|
| class SchoolStaffMapping(Base): |
| __tablename__ = "school_staff_mapping" |
|
|
| id = Column(String, primary_key=True, default=generate_uuid) |
| staff_id = Column(String, ForeignKey("field_staff.staff_id"), nullable=False) |
| school_id = Column(String, ForeignKey("school.school_id"), nullable=False) |
| is_primary = Column(Boolean, default=True) |
|
|
| staff = relationship("FieldStaff", back_populates="school_mappings") |
|
|
|
|
| class TrainingLog(Base): |
| __tablename__ = "training_log" |
|
|
| log_id = Column(String, primary_key=True, default=generate_uuid) |
| staff_id = Column(String, ForeignKey("field_staff.staff_id"), nullable=False) |
| school_id = Column(String, ForeignKey("school.school_id"), nullable=False) |
| date = Column(DateTime, default=datetime.utcnow) |
| teachers_trained_count = Column(Integer, default=0) |
| notes = Column(Text, nullable=True) |
|
|
|
|
| class SupportLog(Base): |
| __tablename__ = "support_log" |
|
|
| log_id = Column(String, primary_key=True, default=generate_uuid) |
| staff_id = Column(String, ForeignKey("field_staff.staff_id"), nullable=False) |
| teacher_id = Column(String, ForeignKey("teacher_account.teacher_id"), nullable=True) |
| issue_type = Column(String, nullable=False) |
| description = Column(Text, nullable=False) |
| resolution = Column(Text, nullable=True) |
| timestamp = Column(DateTime, default=datetime.utcnow) |
|
|