Skip to main content

Overview

The application uses SQLAlchemy as the ORM (Object-Relational Mapping) layer with SQLite as the database backend. The database schema is designed to support adaptive interview sessions, user mastery tracking, and comprehensive performance analytics.

Database Technology Stack

  • ORM: Flask-SQLAlchemy (SQLAlchemy wrapper for Flask)
  • Database: SQLite (file-based relational database)
  • Location: Configured via SQLALCHEMY_DATABASE_URI environment variable
  • Migrations: Manual schema updates via SQLAlchemy model definitions

Core Models

User Model

The User model represents registered users in the system. It integrates with Flask-Login for authentication.
FieldTypeConstraintsDescription
idIntegerPrimary KeyUnique user identifier
usernameString(80)Unique, Not NullUnique username for login
emailString(120)Unique, Not NullUser’s email address
password_hashString(120)Not NullHashed password (bcrypt/werkzeug)
full_nameString(100)NullableUser’s full name
phoneString(20)NullableContact phone number
experience_yearsIntegerDefault: 0Years of professional experience
skillsTextNullableJSON-encoded list of skills
resume_filenameString(255)NullableUploaded resume filename
reset_tokenString(100)Unique, NullablePassword reset token
reset_token_expiryDateTimeNullableToken expiration timestamp
created_atDateTimeDefault: utcnowAccount creation timestamp
Relationships:
  • interviews → One-to-Many with InterviewSession
  • masteries → One-to-Many with UserMastery (via backref)
  • adaptive_sessions → One-to-Many with AdaptiveInterviewSession (via backref)
  • question_history → One-to-Many with QuestionHistory (via backref)
  • subtopic_masteries → One-to-Many with SubtopicMastery (via backref)
  • study_plans → One-to-Many with StudyActionPlan (via backref)
Example Usage:
from models import User, db
from werkzeug.security import generate_password_hash

# Create a new user
user = User(
    username="john_doe",
    email="[email protected]",
    password_hash=generate_password_hash("secure_password"),
    full_name="John Doe",
    experience_years=5,
    skills=json.dumps(["Python", "SQL", "Flask"])
)
db.session.add(user)
db.session.commit()

# Query user
user = User.query.filter_by(username="john_doe").first()
print(user.to_dict())

InterviewSession Model

Tracks traditional interview sessions (legacy model for basic interviews).
FieldTypeConstraintsDescription
idIntegerPrimary KeyUnique session identifier
user_idIntegerForeign Key (user.id), Not NullReference to User
session_typeString(50)Not NullType of interview (e.g., “technical”, “behavioral”)
questionsTextNullableJSON-encoded list of questions
scoreFloatNullableOverall interview score (0-1)
feedbackTextNullableInterview feedback text
durationIntegerNullableSession duration in seconds
created_atDateTimeDefault: utcnowSession start timestamp
completed_atDateTimeNullableSession completion timestamp
speech_metricsTextNullableJSON with research-grade speech metrics
Relationships:
  • user → Many-to-One with User

UserMastery Model

Critical Model: Tracks user’s mastery across topics with complete concept-level data.
FieldTypeConstraintsDescription
idIntegerPrimary KeyUnique mastery record ID
user_idIntegerForeign Key (user.id), Not NullReference to User
topicString(50)Not NullTopic name (e.g., “DBMS”, “OS”)
sessions_attemptedIntegerDefault: 0Number of sessions for this topic
last_session_dateDateTimeNullableLast session timestamp
Mastery Scores (0-1 range):
FieldTypeDefaultDescription
mastery_levelFloat0.0Overall mastery: semantic_avg * 0.7 + keyword_avg * 0.3
semantic_avgFloat0.0Exponential moving average of semantic scores
keyword_avgFloat0.0Exponential moving average of keyword scores
Statistics:
FieldTypeDefaultDescription
questions_attemptedInteger0Total questions answered for this topic
correct_countInteger0Questions with keyword score > 0.6
avg_response_timeFloat0.0Exponential moving average of response times
Learning Velocity:
FieldTypeDefaultDescription
mastery_velocityFloat0.0Rate of mastery change: mastery_level - last_mastery
last_masteryFloat0.0Previous mastery level before last update
Difficulty Tracking:
FieldTypeDefaultDescription
current_difficultyString(20)“medium”Current difficulty level: “easy”, “medium”, or “hard”
consecutive_goodInteger0Consecutive high-scoring answers (>0.7)
consecutive_poorInteger0Consecutive low-scoring answers (<0.4)
Concept-Level Data (JSON fields):
FieldTypeDefaultDescription
concept_masteriesText''PRIMARY: Complete concept-level mastery data (see User Mastery Tracking)
missing_conceptsText’[]‘LEGACY: List of weak concepts (derived from concept_masteries)
weak_conceptsText’[]‘LEGACY: List of weak concepts
strong_conceptsText’[]‘LEGACY: List of strong concepts
concept_stagnationText''LEGACY: Concept stagnation counts
Timestamps:
FieldTypeDefaultDescription
first_attemptDateTimeutcnowFirst attempt timestamp
last_attemptDateTimeutcnowMost recent attempt timestamp
last_seenFloat0.0Unix timestamp of last activity
Constraints:
  • Unique constraint on (user_id, topic) → One mastery record per user per topic
Relationships:
  • user → Many-to-One with User
Example Usage:
from models import UserMastery, db

# Get or create mastery record
mastery = UserMastery.query.filter_by(
    user_id=user.id,
    topic="DBMS"
).first()

if not mastery:
    mastery = UserMastery(user_id=user.id, topic="DBMS")
    db.session.add(mastery)

# Update mastery with new answer
mastery.update_mastery(
    semantic_score=0.85,
    keyword_score=0.75,
    response_time=45.0
)
db.session.commit()

# Access concept-level data
concepts = mastery.get_concept_masteries()
print(f"Total concepts tracked: {len(concepts)}")
print(f"Weak concepts: {mastery.get_weak_concepts()}")

AdaptiveInterviewSession Model

Tracks enhanced adaptive interview sessions with comprehensive metrics.
FieldTypeConstraintsDescription
idIntegerPrimary KeyUnique session identifier
user_idIntegerForeign Key (user.id), Not NullReference to User
session_idString(100)Unique, Not Null, IndexedUUID for session tracking
start_timeDateTimeDefault: utcnowSession start timestamp
end_timeDateTimeNullableSession end timestamp
durationIntegerDefault: 0Total duration in seconds
questions_askedIntegerDefault: 0Number of questions asked
avg_semanticFloatDefault: 0.0Average semantic similarity score
avg_keywordFloatDefault: 0.0Average keyword coverage score
overall_scoreFloatDefault: 0.0avg_semantic * 0.7 + avg_keyword * 0.3
learning_velocityFloatDefault: 0.0Rate of learning improvement
attention_scoreFloatDefault: 1.0Attention/engagement score
topics_coveredText’[]‘JSON list of topics covered
weakest_topicsText’[]‘JSON list of weakest 3 topics
strongest_topicsText’[]‘JSON list of strongest 3 topics
Relationships:
  • user → Many-to-One with User

QuestionHistory Model

Tracks every individual question asked across all sessions.
FieldTypeConstraintsDescription
idIntegerPrimary KeyUnique question record ID
user_idIntegerForeign Key (user.id), Not Null, IndexedReference to User
session_idString(100)Not Null, IndexedSession UUID
topicString(50)Not NullTopic name
subtopicString(100)NullableSubtopic name
questionTextNot NullQuestion text
answerTextNullableUser’s answer
expected_answerTextNullableAI-generated expected answer
sampled_conceptsText’[]‘JSON list of concepts sampled in question
semantic_scoreFloatDefault: 0.0Semantic similarity score (0-1)
keyword_scoreFloatDefault: 0.0Keyword coverage score (0-1)
depthString(20)Default: “medium”Answer depth analysis
confidenceString(20)Default: “medium”Answer confidence level
key_termsText’[]‘JSON list of key terms mentioned
difficultyString(20)Default: “medium”Question difficulty
response_timeFloatDefault: 0.0Response time in seconds
timestampDateTimeDefault: utcnow, IndexedQuestion timestamp
missing_conceptsText’[]‘JSON list of concepts missing from answer
Relationships:
  • user → Many-to-One with User

SubtopicMastery Model

Tracks mastery at the subtopic level within each topic.
FieldTypeConstraintsDescription
idIntegerPrimary KeyUnique record ID
user_idIntegerForeign Key (user.id), Not Null, IndexedReference to User
topicString(50)Not NullParent topic name
subtopicString(200)Not NullSubtopic name
mastery_levelFloatDefault: 0.0Subtopic mastery score (0-1)
attemptsIntegerDefault: 0Number of attempts
last_askedDateTimeDefault: utcnowLast question timestamp
subtopic_statusString(20)Default: ‘not_started’Status: ‘not_started’, ‘ongoing’, ‘mastered’
concept_dataText''JSON with concept-level data for quick access
Constraints:
  • Unique constraint on (user_id, topic, subtopic)
Relationships:
  • user → Many-to-One with User

StudyActionPlan Model

Stores AI-generated personalized study plans for users.
FieldTypeConstraintsDescription
idIntegerPrimary KeyUnique plan ID
user_idIntegerForeign Key (user.id), Not Null, IndexedReference to User
daysIntegerNot NullPlan duration in days
topicsString(255)Not NullComma-separated list of topics
plan_markdownTextNot NullFull plan in Markdown format
created_atDateTimeDefault: utcnow, IndexedCreation timestamp
Relationships:
  • user → Many-to-One with User
Example Usage:
plan = StudyActionPlan(
    user_id=user.id,
    days=30,
    topics="DBMS,OS,Networks",
    plan_markdown="# 30-Day Study Plan\n\n## Week 1..." 
)
db.session.add(plan)
db.session.commit()

DebuggingSession Model

Tracks full debugging interview sessions.
FieldTypeConstraintsDescription
idIntegerPrimary KeyUnique session ID
user_idIntegerForeign Key (user.id), Not NullReference to User
start_timeDateTimeDefault: utcnowSession start
end_timeDateTimeNullableSession end
countIntegerDefault: 0Number of challenges
avg_scoreFloatDefault: 0.0Average score across challenges
summaryTextNullableSession summary
Relationships:
  • challenges → One-to-Many with DebuggingChallenge (cascade delete)

DebuggingChallenge Model

Tracks individual debugging challenges within a session.
FieldTypeConstraintsDescription
idIntegerPrimary KeyUnique challenge ID
session_idIntegerForeign Key (debugging_session.id), Not NullReference to DebuggingSession
languageString(20)Default: ‘python’Programming language
topicString(100)NullableTopic/concept being tested
buggy_codeTextNot NullCode with bug
expected_answerTextNot NullExpected explanation
correct_codeTextNullableCorrected code
user_explanationTextNullableUser’s bug explanation
ai_scoreFloatDefault: 0.0AI-evaluated score
ai_feedbackTextNullableAI feedback
created_atDateTimeDefault: utcnowCreation timestamp
Relationships:
  • session → Many-to-One with DebuggingSession

Database Indexes

The following indexes are automatically created for optimal query performance:
  • user.username (unique index)
  • user.email (unique index)
  • user.reset_token (unique index)
  • adaptive_interview_session.session_id (unique index)
  • adaptive_interview_session.user_id
  • question_history.user_id
  • question_history.session_id
  • question_history.timestamp
  • subtopic_mastery.user_id
  • study_action_plan.user_id
  • study_action_plan.created_at

Common Database Operations

Initialize Database

from models import db
from app import app

with app.app_context():
    db.create_all()
    print("Database initialized!")

Query with Relationships

# Get user with all mastery records
user = User.query.filter_by(id=1).first()
for mastery in user.masteries:
    print(f"{mastery.topic}: {mastery.mastery_level:.2f}")

# Get recent question history
recent_questions = QuestionHistory.query.filter_by(
    user_id=user.id
).order_by(QuestionHistory.timestamp.desc()).limit(10).all()

Bulk Insert

questions = [
    QuestionHistory(
        user_id=user.id,
        session_id=session_id,
        topic="DBMS",
        question=q["text"],
        semantic_score=q["score"]
    )
    for q in question_data
]
db.session.bulk_save_objects(questions)
db.session.commit()

Database Configuration

Typical SQLAlchemy configuration in app.py:
app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv(
    'DATABASE_URL',
    'sqlite:///interview_app.db'
)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_ECHO'] = False  # Set to True for SQL logging

db.init_app(app)

Migration Best Practices

  1. Always backup the database before schema changes
  2. Test migrations on a development database first
  3. Use transactions for data migrations
  4. Add new fields as nullable first, then populate, then add constraints

Build docs developers (and LLMs) love