A dating app-style course selection web app for Harvard students. Discover courses by swiping, save your favorites, and rank them through an interactive comparison game.
Watch a demonstration of Class Cupid in action: YouTube Video
Install all required Python packages:
pip install -r requirements.txt
This will install:
The database will be created automatically when you first run the application. To explicitly create it:
python app.py
This creates the SQLite database file at instance/classcupid.db with all necessary tables (users, courses, user_course_preferences, sort_comparisons).
Note: If you need to recreate the database from scratch, delete the instance/classcupid.db file and run the above command again.
Import course catalog data from JSON files. You can import multiple semesters:
# Import Fall 2025 courses
flask import-courses data/json/2025_Fall_courses.json
# Import Spring 2026 courses
flask import-courses data/json/2026_Spring_courses.json
The import command will:
Import complete: X imported, Y updated, Z skippedImportant: The same course can exist in multiple semesters (e.g., a course offered in both Fall and Spring). Each semester’s version is stored separately using a composite unique constraint on (course_id, term_description).
Start the Flask development server:
flask run
Or alternatively:
python app.py
The application will start on http://localhost:5000 (default Flask port). If port 5000 is already in use, Flask will automatically use the next available port and display it in the terminal.
Open your web browser and navigate to:
http://localhost:5000
Register an Account: Click “Register” on the login page and create a username and password.
Configure Your Settings (required before using Discover):
Navigate to the Discover page from the navigation bar (fire icon).
First Visit: You’ll see a welcome popup explaining the action buttons. Click “Got it!” to dismiss it.
Navigate to the Matches page (compass icon) after you’ve saved some courses (hearted or starred).
max(3, min(10, total_courses - 1)):
The recommendation algorithm uses a multi-stage weighted selection process:
Term Filtering: Only shows courses from your selected terms
Concentration Filtering: If selected, shows courses from those departments. Can select multiple concentrations or use “Select all”.
Gen Ed Categories: Uses external JSON files (data/json/*_Geneds.json) to find specific course codes (e.g., “GENED 1145”) matching selected categories. Important: Gen Eds are open to all grade levels - grade-level restrictions are bypassed for Gen Ed courses.
Divisional Distribution: Filters by Arts & Humanities, Social Sciences, or Science & Engineering. Excludes Tutorial courses. Click the (i) info icon to see that selecting a division will show ALL concentrations within that division.
First Year Seminar: Special filter for courses with catalogSubject = "FYSEMR". Only freshmen can see these. Uses union logic - if you select FYSEMR + a concentration, you’ll see all FYSEMR courses OR all courses in that concentration (not just FYSEMR courses in that concentration).
The algorithm uses completely different school-specific filtering (no year-based weighting):
catalogSchoolDescription = "Faculty of Arts & Sciences" ANDHarvard Business School: Shows courses where catalogSchoolDescription includes “Business School” (matches both “Business School Doctoral” and “Business School MBA”)
Harvard School of Dental Medicine: Shows courses where catalogSchoolDescription = "School of Dental Medicine"
Harvard T.H. Chan School of Public Health: Shows courses where catalogSchoolDescription = "Harvard Chan School"
catalogSchoolDescriptionOnce you swipe a course (heart, star, or discard), it is permanently removed from your recommendation pool. This ensures you never see the same course twice. The course will only reappear if you:
The application uses SQLite with SQLAlchemy ORM. The database file is located at:
instance/classcupid.db
The database is automatically backed up to the backups/ directory when you run certain commands. To manually backup:
cp instance/classcupid.db backups/classcupid_backup_$(date +%Y%m%d_%H%M%S).db
To restore from a backup, stop the application and replace the database file:
cp backups/classcupid_backup_YYYYMMDD_HHMMSS.db instance/classcupid.db
Check your Settings: Make sure you’ve selected at least one term preference. Click your username → Settings and verify your selections.
# Check the database (requires sqlite3 command-line tool)
sqlite3 instance/classcupid.db "SELECT COUNT(*) FROM courses;"
Check your preferences: Very specific filtering (e.g., single concentration + multiple requirements) may result in few or no matches. Try expanding your selections.
This occurs if the database was recreated and your user account no longer exists. Simply log out and register a new account, or log back in if your account still exists.
data/json/ directory and use the full path: flask import-courses data/json/FILENAME.jsonIf port 5000 is busy, Flask will automatically use another port. Check the terminal output for the actual port number, or specify a different port:
flask run --port 5001
If you’ve updated the code and need to add new columns to existing tables, you may need to recreate the database:
cp instance/classcupid.db backups/backup.dbinstance/classcupid.dbpython app.py to recreate tablesflask import-courses data/json/2025_Fall_courses.json (and Spring if needed)class_cupidv1/
├── app.py # Main Flask application (routes, algorithms, CLI commands)
├── models.py # Database models (User, Course, UserCoursePreference, SortComparison)
├── helpers.py # Utility functions (login_required decorator, apology helper)
├── requirements.txt # Python dependencies
├── README.md # This file (user manual)
├── DESIGN.md # Technical design document
├── templates/ # HTML templates
│ ├── base.html # Base template with navigation, footer, flash messages
│ ├── login.html # Authentication page
│ ├── register.html # User registration
│ ├── profile.html # Settings/preferences page
│ ├── discover.html # Course discovery (swipe interface)
│ └── matches.html # Comparison game and saved courses list
├── static/
│ ├── css/
│ │ └── style.css # Global styles (Apple system font, responsive layout)
│ ├── js/
│ │ └── main.js # Client-side JavaScript (tooltips, popup dismissal)
│ └── images/
│ ├── icons/ # Navigation icons (fire, compass, user-circle)
│ ├── Class Cupid Logo V3-3.png # Header logo and favicon
│ ├── Class Cupid Text-4.png # Header text logo
│ └── Class Cupid Logo.png # Footer logo
├── data/ # Organized data files
│ ├── images/ # Logo files and icons (duplicates from root)
│ └── json/ # Course catalogs and reference data
│ ├── 2025_Fall_courses.json
│ ├── 2026_Spring_courses.json
│ ├── 2025_Fall_Geneds.json
│ ├── 2026_Spring_Geneds.json
│ ├── harvard_college_concentrations.json
│ └── harvard_schools.json
├── instance/
│ └── classcupid.db # SQLite database (created at runtime)
├── flask_session/ # Session files (created at runtime)
└── backups/ # Database backups (created as needed)
Course Data: Course information is imported from Harvard’s course catalog JSON files. These files should be updated each semester and placed in data/json/.
Gen Ed Categories: Gen Ed category mappings are stored in separate JSON files (data/json/*_Geneds.json). These files map categories to specific course codes (e.g., “GENED 1145”).
Font and Styling: The application uses the Apple system font family for consistent typography across devices. The background features a subtle pattern for visual interest.
Session Storage: User sessions are stored in the flask_session/ directory as files. You can clear all sessions by deleting files in this directory.
Logo and Branding: The Class Cupid logo appears in the header (with text) and as a favicon. A footer logo appears at the bottom of pages with copyright information.
Error Handling: Error messages are displayed directly on login/register pages using flash messages (not separate error pages) for better user experience.
For detailed technical implementation information, algorithms, and architecture decisions, see DESIGN.md.
Code © 2025 Carissa Chen and Haotian Pan
Course metadata © 2025-2026 President and Fellows of Harvard College