CourseCompiler helps UCLA Engineering students plan their 4-year degree path. You can drag and drop courses into a quarterly schedule, see which requirements you need to meet, what prerequisites each class has and track your progress toward graduation.
The app lets you search for your engineering major, see all the available classes, and build a plan by dragging courses into quarters. It checks prerequisites automatically and warns you if you're taking too many units. You can save multiple plans and switch between them.
Course Planning
- See all required courses for your major loaded from our database
- Drag courses into a 4-year quarterly schedule
- System blocks you from adding classes with a visual warning if:
- you haven't taken prerequisites
- a quarter would exceed 21 units
Progress Tracking
- See how much of your degree you've completed
- Track progress by requirement type (Prep, Major, Tech Breadth, Sci-Tech, GE, etc.)
- Progress bar shows completion percentage for each requirement category
Saving Plans
- Create an account to save your plans
- Save multiple plans and switch between them
- Your plans are stored in the database
Search
- Search for engineering majors with real-time suggestions
- Results are ranked by relevance (exact matches first, then partial matches)
The frontend is React with Vite. We use React Router for navigation and @dnd-kit for the drag-and-drop functionality. We utilized React Bits for some visual components such as the electric border on the classes and the dots on the homepage. State is managed with React Context (for auth and major selection) and custom hooks for different features.
The backend is Express.js with Prisma as our ORM. We use MySQL for the database. Authentication uses JWT tokens, and passwords are hashed with bcrypt. The server code is organized into separate folders for middleware, controllers, the routes, and the configuration.
We organized the code into custom hooks so each piece has a single, clear responsibility. API calls go through service functions, and protected routes use JWT middleware.
This diagram shows how React components and hooks are organized and how they interact with each other.
The App component wraps everything with AuthProvider and MajorProvider for global state management. The DegreePlan page uses the usePlanManager hook, which coordinates useCategorizedCourses (fetches and categorizes courses), useDragAndDrop (handles the drag-and-drop logic), and useCourseValidation (checks prerequisites). PlanGrid renders the 4×4 grid of quarters, and CourseSidebar displays the categorized courses. Components like SavePlanButton, SavedPlansButton, and ProgressBar interact with the plan manager to provide the full functionality.
This ER diagram shows how the database tables relate to each other.
Users can have multiple Plans. Each Plan belongs to one Major and has multiple Quarters. Each Quarter has multiple classes which are shown through the PlanClasses join table. Majors have Requirements through MajorRequirementGroup (which links to RequirementGroup), and Requirements link to Classes through RequirementClasses. Classes can have Prerequisites pointing to other Classes. The schema supports complex prerequisite relationships and tracks which classes fulfill which requirements.
This shows the different states the application can be in and how it transitions between them.
The application starts at HomeScreen where users can search for engineering majors. Selecting a major transitions to LoadingPlan, then to PlanReady where users can drag and drop courses. The PlanReady state includes nested states for dragging, validating drops, saving plans, and browsing saved plans. Users can also authenticate from HomeScreen, which transitions to the Authenticating state.
This sequence diagram shows how major search and course data retrieval works.
When a user types in the search bar, the app fetches all engineering majors from the server. The server queries the database through Prisma and returns a list of major names. The client filters and ranks suggestions locally. When a user selects an engineering major, the app navigates to the degree plan page and fetches detailed course data including classes, requirements, and prerequisites. The server performs complex joins to retrieve all related data and transforms it into the format the client needs.
This sequence diagram shows how user authentication (signup and login) works.
For signup, the client sends user credentials to the server, which hashes the password with bcrypt and creates a user record in the database. After successful signup, the app automatically logs the user in. For login, the server compares the provided password with the stored hash, and if valid, generates a JWT token. The client stores the token and user data in localStorage for future authenticated requests.
This sequence diagram shows how plans are saved, retrieved, and loaded.
When saving a plan, the client serializes the drag-and-drop zones into a quarters array and sends it to the server with authentication. The server validates the JWT token, looks up the major, and creates the plan with nested quarters and plan classes in a database transaction. When browsing plans, the server fetches all plans for the authenticated user with all related data. When loading a plan, the client deserializes the quarters back into the zone structure and updates the UI.
- npm
- The
.envfile (ask a team member for it)
-
Clone the repo
git clone <repository-url> cd CourseCompiler
-
Set up the server
cd server npm install npx prisma generateYou'll need a
.envfile in theserver/folder with your database info:DB_URL=mysql://user:password@host:port/database ACCESS_TOKEN_SECRET=your_jwt_secret_key OPENAI_API_KEY=your_openai_api_key # Optional: only needed for AI chat feature
-
Set up the client
cd ../client npm install
-
Start the server (in one terminal)
cd server node src/server.jsYou should see "Server running on port 3000" and "Connected to MySQL successfully."
-
Start the client (in another terminal)
cd client npm run devIt'll run on
http://localhost:5173 -
Open it in your browser
- Go to
http://localhost:5173 - Search for an engineering major (try "Computer Science" or "Computer Engineering")
- Start building your plan
- Log in to save your plan
- Go to
POST /users - Create account
{
"username": "username",
"password": "password123"
}Returns 201 with user data (no password).
POST /users/login - Log in
{
"username": "username",
"password": "password123"
}Returns 200 with user object and JWT token.
GET /majors - Get all engineering majors
Returns array of engineering major names: ["Computer Engineering", "Computer Science", ...]
GET /majors/:majorName - Get engineering major details Returns courses and requirements for that engineering major:
{
"availableClasses": [...],
"majorRequirementGroups": [...]
}POST /plans - Save a plan
Headers: Authorization: Bearer <token>
Body:
{
"name": "My Plan",
"majorName": "Computer Science",
"quarters": [
{
"quarterNumber": 1,
"classIds": [1, 2, 3]
}
]
}GET /plans - Get your saved plans
Headers: Authorization: Bearer <token>
Returns array of your plans with all the quarter and class data.
PUT /plans/:planId - Update a plan
Headers: Authorization: Bearer <token>
Body:
{
"name": "Updated Plan Name",
"quarters": [
{
"quarterNumber": 1,
"classIds": [1, 2, 3]
}
]
}PATCH /plans/:planId/name - Update plan name only
Headers: Authorization: Bearer <token>
Body:
{
"name": "New Plan Name"
}DELETE /plans/:planId - Delete a plan
Headers: Authorization: Bearer <token>
Returns 200 on successful deletion.
POST /ai/chat - Send a message to the AI assistant
Headers: Authorization: Bearer <token>
Body:
{
"messages": [
{
"role": "user",
"content": "What prerequisites do I need for CS 31?"
}
]
}Returns 200 with AI response. Requires OPENAI_API_KEY to be set in .env.
We have comprehensive end-to-end tests using Cucumber and Gherkin. The test suite includes both E2E UI tests (using Playwright) and API tests (using Supertest).
You must set up your .env.test file to run with our test database
DB_URL=mysql://user:password@host:port/database
Run all tests (API + E2E):
cd server
npm testNote: E2E tests require both client (http://localhost:5173) and server (http://localhost:3000) to be running. If they're not running, E2E tests will fail but API tests will still run.
Run E2E tests (requires both client and server running):
# Terminal 1: Start the client
cd client
npm run dev
# Client should be running on http://localhost:5173
# Terminal 2: Start the server
cd server
node src/server.js
# Server should be running on http://localhost:3000
# Terminal 3: Run E2E tests
cd server
# First time setup: Install Playwright browsers
npx playwright install
# Then run E2E tests
npm run test:e2e # Run all E2E tests
npm run test:scenario20 # Complete user journey test
npm run test:scenario21 # Plan management E2E testImportant Notes:
- E2E tests require Playwright browsers to be installed. Run
npx playwright installonce before running E2E tests. - Both client and server (
localhost:3000) must be running before E2E tests will work. - Port Auto-Detection: E2E tests automatically detect which port your client is running on (tries 5174, 5173, 5175, 5176). You can also set it manually:
E2E_BASE_URL=http://localhost:5174 npm run test:e2e
- If tests timeout, verify both servers are running and accessible.
- E2E tests have 60-second timeouts for steps and 30-second timeouts for page navigation.
Run individual API test scenarios by tag (all 19 API scenarios have individual scripts):
# User authentication (scenarios 1-4)
npm run test:scenario1 # User creation
npm run test:scenario2 # Duplicate user prevention
npm run test:scenario3 # User login
npm run test:scenario4 # Invalid login
# Major endpoints (scenarios 5-7)
npm run test:scenario5 # Get all majors
npm run test:scenario6 # Get major details
npm run test:scenario7 # Nonexistent major error
# Plan management (scenarios 8-13)
npm run test:scenario8 # Create plan
npm run test:scenario9 # Create plan without auth
npm run test:scenario10 # Get all plans
npm run test:scenario11 # Update plan
npm run test:scenario12 # Update plan name
npm run test:scenario13 # Delete plan
# Auth endpoints (scenarios 14)
npm run test:scenario15 # Update username
# AI endpoints (scenarios 15-17)
npm run test:scenario17 # AI chat message
npm run test:scenario18 # AI chat without auth
npm run test:scenario19 # Invalid AI message formatE2E Tests (Playwright + Cucumber) - 2 comprehensive scenarios:
e2e_user_journey.feature(scenario 20) - Complete user flow: signup → search major → create plan → drag and drop courses → save plane2e_plan_management.feature(scenario 21) - Plan management: load saved plan → modify plan → update plan
API Tests (Supertest) - 19 scenarios covering all 11 API routes:
can_users_be_created.feature(scenarios 1-2) - User registration and duplicate preventioncan_you_log_in.feature(scenarios 3-4) - User login and authenticationmajor_endpoints.feature(scenarios 5-7) - Major data retrieval (GET all majors, GET major details, error handling)plan_endpoints.feature(scenarios 8-14) - Plan CRUD operations (create, read, update, delete, authorization checks)auth_endpoints.feature(scenarios 15-16) - User account updates (username updates, authentication)ai_endpoints.feature(scenarios 17-19) - AI chat endpoint (authentication, message validation, error handling)
- Feature files:
server/features/*.feature(Gherkin syntax) - Step definitions:
server/features/step_definitions/stepdefs.js- Step definitions for user authentication tests (scenarios 1-4)api_stepdefs.js- Step definitions for API endpoint tests (scenarios 5-19)e2e_stepdefs.js- Step definitions for E2E UI tests using Playwright (scenarios 20-21)
E2E Test Requirements:
- Both client (
http://localhost:5173) and server (http://localhost:3000) must be running - E2E tests use Playwright to automate browser interactions
- Tests create users and plans via API, then verify UI behavior
- Tests are configured to run headless by default (set
E2E_HEADLESS=falseto see browser)
API Tests:
- All API tests use Supertest to make HTTP requests to the Express app
- Tests use a separate test database (configured via
NODE_ENV=test) - Tests automatically set up/tear down test data to ensure test isolation
Database connection fails
- Make sure the
.envfile exists inserver/ - Check your database credentials
- Make sure the server is running
Module not found errors
- Run
npm installin bothclient/andserver/directories
Prisma errors
- Run
npm run prisma:generateornpx prisma generatein theserver/directory
Port 3000 already in use
- Kill whatever's using port 3000, or change the PORT constant in
server/src/server.js
CORS errors
- Check the CORS config in
server/src/middleware/setup.middleware.jsmatches your client URL - The client uses Vite proxy (
/apiroutes) configured inclient/vite.config.js
Built for CS35L at UCLA.





