Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/whitiue/logiMathApp/llms.txt

Use this file to discover all available pages before exploring further.

LogiMath stores all application data in a PostgreSQL 16 (Alpine) database managed by Docker Compose. The schema is defined in src/BackEnd/models.py using SQLAlchemy’s declarative ORM. Four tables cover user accounts, quiz catalogue entries, individual questions, and per-user scoring records. The database is persisted in a named Docker volume (postgres_data) so data survives container restarts.

Container configuration

The postgres service in docker-compose.yml uses postgres:16-alpine for a minimal image footprint and mounts an init script at container first-run.
docker-compose.yml
postgres:
  image: postgres:16-alpine
  container_name: logmath_db
  environment:
    POSTGRES_USER: ${POSTGRES_USER}
    POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    POSTGRES_DB: ${POSTGRES_DB}
  volumes:
    - postgres_data:/var/lib/postgresql/data
    - ./docker/init.sql:/docker-entrypoint-initdb.d/01-init.sql
  networks:
    - logmath_network

volumes:
  postgres_data:
    driver: local

SQLAlchemy base and session

models.py creates the engine from DATABASE_URL, normalises the postgres:// scheme to postgresql:// for SQLAlchemy 2.x compatibility, and calls Base.metadata.create_all to emit CREATE TABLE IF NOT EXISTS for all models on startup.
models.py
DATABASE_URL = os.getenv("DATABASE_URL")

if DATABASE_URL.startswith("postgres://"):
    DATABASE_URL = DATABASE_URL.replace("postgres://", "postgresql://", 1)

engine = create_engine(DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()

Models

User

Stores registered accounts. email has a unique constraint to prevent duplicate registrations.
models.py
class User(Base):
    __tablename__ = "users"
    id           = Column(Integer, primary_key=True, index=True)
    name         = Column(String, index=True)
    email        = Column(String, unique=True, index=True)
    password_hash = Column(String, index=True)
    created_at   = Column(DateTime, default=datetime.utcnow)
ColumnTypeConstraints
idIntegerPrimary key, indexed
nameStringIndexed
emailStringUnique, indexed
password_hashStringIndexed
created_atDateTimeDefaults to utcnow

Quiz

Represents a quiz in the catalogue. difficulty is a free-form string (e.g. "easy", "hard").
models.py
class Quiz(Base):
    __tablename__ = "quizzes"
    id         = Column(Integer, primary_key=True, index=True)
    title      = Column(String, index=True)
    subject    = Column(String)
    difficulty = Column(String)
    created_at = Column(DateTime, default=datetime.utcnow)
ColumnTypeConstraints
idIntegerPrimary key, indexed
titleStringIndexed
subjectString
difficultyString
created_atDateTimeDefaults to utcnow

Question

Belongs to a quiz via quiz_id. Carries its own difficulty field to support per-question adaptive difficulty independent of the parent quiz.
models.py
class Question(Base):
    __tablename__ = "questions"
    id             = Column(Integer, primary_key=True, index=True)
    quiz_id        = Column(Integer, index=True)
    question_text  = Column(String)
    correct_answer = Column(String)
    difficulty     = Column(String)
ColumnTypeConstraints
idIntegerPrimary key, indexed
quiz_idIntegerIndexed (FK intent)
question_textString
correct_answerString
difficultyString

UserScore

Records a user’s attempt on a quiz. completed tracks whether the attempt is finished, and completed_at is nullable to represent in-progress attempts.
models.py
class UserScore(Base):
    __tablename__ = "user_scores"
    id           = Column(Integer, primary_key=True, index=True)
    user_id      = Column(Integer, index=True)
    quiz_id      = Column(Integer, index=True)
    score        = Column(Float)
    completed    = Column(Boolean, default=False)
    completed_at = Column(DateTime, nullable=True)
ColumnTypeConstraints
idIntegerPrimary key, indexed
user_idIntegerIndexed (FK intent)
quiz_idIntegerIndexed (FK intent)
scoreFloat
completedBooleanDefaults to False
completed_atDateTimeNullable

Relationships between tables

The models use plain integer foreign key columns (quiz_id, user_id) without SQLAlchemy ForeignKey or relationship declarations. The logical relationships are:
User          (1) ──── (N) UserScore
Quiz          (1) ──── (N) Question
Quiz          (1) ──── (N) UserScore
  • A User can have many UserScore rows (one per quiz attempt).
  • A Quiz contains many Question rows.
  • A Quiz can appear in many UserScore rows (attempted by many users).
Foreign key constraints and relationship helpers are not yet defined at the SQLAlchemy level. Referential integrity is enforced only at the application layer for now.

Build docs developers (and LLMs) love