from datetime import datetime from sqlalchemy import DateTime, Float, ForeignKey, Integer, String, Text, UniqueConstraint from sqlalchemy.orm import Mapped, mapped_column, relationship from .database import Base class Student(Base): __tablename__ = "students" id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True) first_name: Mapped[str] = mapped_column(String(100)) age: Mapped[int] = mapped_column(Integer) grade: Mapped[str] = mapped_column(String(50)) created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow) messages = relationship("Message", back_populates="student", cascade="all, delete-orphan") mastery = relationship("StudentSkillMastery", back_populates="student", cascade="all, delete-orphan") class User(Base): __tablename__ = "users" id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True) username: Mapped[str] = mapped_column(String(120), unique=True, index=True) password_hash: Mapped[str] = mapped_column(String(255)) role: Mapped[str] = mapped_column(String(30), index=True) student_id: Mapped[int | None] = mapped_column(ForeignKey("students.id"), nullable=True, index=True) created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow) student = relationship("Student") class Message(Base): __tablename__ = "messages" id: Mapped[int] = mapped_column(Integer, primary_key=True) student_id: Mapped[int] = mapped_column(ForeignKey("students.id"), index=True) role: Mapped[str] = mapped_column(String(20)) content: Mapped[str] = mapped_column(Text) created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow) student = relationship("Student", back_populates="messages") class Skill(Base): __tablename__ = "skills" id: Mapped[int] = mapped_column(Integer, primary_key=True) code: Mapped[str] = mapped_column(String(100), unique=True) subject: Mapped[str] = mapped_column(String(50)) label: Mapped[str] = mapped_column(String(255)) description: Mapped[str] = mapped_column(Text) class StudentSkillMastery(Base): __tablename__ = "student_skill_mastery" __table_args__ = (UniqueConstraint("student_id", "skill_id", name="uq_student_skill"),) id: Mapped[int] = mapped_column(Integer, primary_key=True) student_id: Mapped[int] = mapped_column(ForeignKey("students.id"), index=True) skill_id: Mapped[int] = mapped_column(ForeignKey("skills.id"), index=True) mastery_score: Mapped[float] = mapped_column(Float, default=50.0) confidence: Mapped[float] = mapped_column(Float, default=0.2) evidence_count: Mapped[int] = mapped_column(Integer, default=0) updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) student = relationship("Student", back_populates="mastery") skill = relationship("Skill") class StudentProgramAssignment(Base): __tablename__ = "student_program_assignments" __table_args__ = (UniqueConstraint("student_id", name="uq_student_program_assignment"),) id: Mapped[int] = mapped_column(Integer, primary_key=True) student_id: Mapped[int] = mapped_column(ForeignKey("students.id"), index=True) lesson_id: Mapped[str] = mapped_column(String(500), index=True) title: Mapped[str] = mapped_column(String(255)) subject: Mapped[str] = mapped_column(String(100)) grade: Mapped[str] = mapped_column(String(50), index=True) start_asset_index: Mapped[int] = mapped_column(Integer, default=0) start_section_index: Mapped[int] = mapped_column(Integer, default=0) updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) student = relationship("Student") class LessonSessionLog(Base): __tablename__ = "lesson_session_logs" id: Mapped[int] = mapped_column(Integer, primary_key=True) student_id: Mapped[int] = mapped_column(ForeignKey("students.id"), index=True) lesson_id: Mapped[str] = mapped_column(String(500), index=True) lesson_title: Mapped[str] = mapped_column(String(255)) started_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow) ended_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow) conversation: Mapped[str] = mapped_column(Text) card_results: Mapped[str] = mapped_column(Text) student = relationship("Student") class LessonCardProgress(Base): __tablename__ = "lesson_card_progress" __table_args__ = ( UniqueConstraint("student_id", "lesson_id", "asset_path", "section_key", name="uq_student_lesson_card"), ) id: Mapped[int] = mapped_column(Integer, primary_key=True) student_id: Mapped[int] = mapped_column(ForeignKey("students.id"), index=True) lesson_id: Mapped[str] = mapped_column(String(500), index=True) asset_path: Mapped[str] = mapped_column(String(500), index=True) asset_title: Mapped[str] = mapped_column(String(255)) section_key: Mapped[str] = mapped_column(String(120), index=True) section_title: Mapped[str] = mapped_column(String(255)) comprehension_score: Mapped[float] = mapped_column(Float, default=0.0) attempts: Mapped[int] = mapped_column(Integer, default=0) validated_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True) updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) student = relationship("Student") class StudentAdaptiveProfile(Base): __tablename__ = "student_adaptive_profiles" __table_args__ = ( UniqueConstraint("student_id", "lesson_id", name="uq_student_adaptive_lesson"), ) id: Mapped[int] = mapped_column(Integer, primary_key=True) student_id: Mapped[int] = mapped_column(ForeignKey("students.id"), index=True) lesson_id: Mapped[str] = mapped_column(String(500), index=True) diagnostic_id: Mapped[str | None] = mapped_column(String(500), nullable=True) profile_id: Mapped[str] = mapped_column(String(500)) profile_title: Mapped[str] = mapped_column(String(255)) notes: Mapped[str] = mapped_column(Text, default="") source: Mapped[str] = mapped_column(String(50), default="teacher") updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) student = relationship("Student") class AssessmentAttempt(Base): __tablename__ = "assessment_attempts" id: Mapped[int] = mapped_column(Integer, primary_key=True) student_id: Mapped[int] = mapped_column(ForeignKey("students.id"), index=True) skill_code: Mapped[str] = mapped_column(String(100), index=True) question: Mapped[str] = mapped_column(Text) expected_answer: Mapped[str] = mapped_column(Text) student_answer: Mapped[str] = mapped_column(Text) is_correct: Mapped[int] = mapped_column(Integer) feedback: Mapped[str] = mapped_column(Text) created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)