From 13f83e1dfb5a062f124091ff46288c8e0cae50b2 Mon Sep 17 00:00:00 2001
From: Zaid Ahmad <109442753+zaidahmad16@users.noreply.github.com>
Date: Wed, 27 May 2026 14:53:50 -0400
Subject: [PATCH 2/2] feat: RMP reviews, features section, UI polish, and DB
fixes
---
README.md | 56 +++++------
frontend/app/icon.svg | 31 ++++--
frontend/app/page.js | 217 ++++++++++++++++++++++++------------------
3 files changed, 170 insertions(+), 134 deletions(-)
diff --git a/README.md b/README.md
index 389c3f2..ea9e8b8 100644
--- a/README.md
+++ b/README.md
@@ -1,56 +1,52 @@
# CarletonCourseMap
-An interactive course map that helps Carleton University students visualize their program requirements and course prerequisites. See your entire four-year program at a glance—understand which courses block what, which semesters are heavy, and how your choices cascade.
+Prerequisite maps for every Carleton undergrad program. Pick a degree, see four years of courses laid out as a graph — what you need, when, and what unlocks what.
-**Live site:** https://www.carletoncoursemap.ca
+**Live:** https://carletoncoursemap.ca/ | **GitHub:** https://github.com/zaidahmad16/CarletonCourseMap
----
+Used by 500+ Carleton students.
-## Why This Exists
+---
-Planning a degree is harder than it should be. Carleton's calendar lists requirements, but doesn't show the structure. This tool does.
+## What it does
-Students shouldn't have to manually trace prerequisites across departments. Advisors shouldn't repeat the same explanations. Course dependencies should be visual, not mental math.
+- Prerequisite chains drawn from the actual 2026-2027 calendar
+- Courses arranged by year and term, not just listed
+- Elective and breadth slots marked so you can see where you have flexibility
+- Click any course for the description, credit weight, term offerings, and prerequisites
+- Professor info for Fall 2026 / Winter 2027, with RMP ratings, difficulty scores, and recent student reviews
+- 240+ programs, including streams and concentrations
-CarletonCourseMap puts the actual course structure in front of you—50+ programs, all visualized the same way.
+No account needed. Just open it.
---
-## What You Get
+## Stack
-- **See your entire program** - All four years, all requirements, in one interactive map
-- **Understand prerequisites** - Click a course to see what you need before taking it
-- **Plan ahead** - Know which semesters will be heavy and which courses unlock what
-- **Compare programs** - Switch between majors to see how requirements differ
-- **Browse 50+ programs** - Computer Science, Biology, Law, Engineering, and more
+| Layer | Tech |
+|---|---|
+| Frontend | Next.js 15 (App Router), ReactFlow, deployed on Vercel |
+| Backend | FastAPI, deployed on Fly.io |
+| Database | PostgreSQL on Neon |
+| Scraper | Python -- Carleton undergraduate calendar + Carleton Central timetable |
+| Professor ratings | `ratemyprofessors-client` via a Next.js API route |
---
-## How It Works
+## How the data gets in
-Pick a program. The map shows every course requirement, organized by year and semester. Gray lines connect courses to their prerequisites. That's it—no login, no tracking, no setup. Just open and explore.
+One JSON file per department, built by hand from the undergraduate calendar. Each one lists programs, requirements, credit weights, and layout positions for the graph. A scraper pulls Fall 2026 / Winter 2027 instructor assignments from Carleton Central and writes them to the database. Seeding scripts push everything into Neon.
---
-## Technical Stack
-
-- **Frontend:** React 19 with Next.js, deployed on Railway
-- **Backend:** FastAPI with rate limiting, input validation, and API key protection
-- **Data:** PostgreSQL on Neon, handling 50+ program structures and 10,000+ courses
-- **Visualization:** ReactFlow + Dagre for interactive course dependency diagrams
-- **Scraper:** Python with parsel (XPath + CSS) — scrapes the Carleton undergraduate calendar and the Registrar's class schedule for Fall 2026 / Winter 2027 offerings
+## Coming soon
-The backend includes production-grade security: rate limiting, SQL injection protection, CORS restrictions, API authentication, and comprehensive error handling.
+Elective recommendations. When your program has a free or breadth elective slot, the site will suggest courses that actually fit, like "any MATH 2000-level or above" resolved into a real list with ratings and prereqs attached.
---
+## Not affiliated with Carleton University
-## Status
-
-Live and in active use. Security and performance are continuously monitored.
+Student project. Data is from the public 2026-2027 undergraduate calendar. Verify your actual requirements with an advisor and the official calendar at https://calendar.carleton.ca.
---
-
-## License
-
-MIT
diff --git a/frontend/app/icon.svg b/frontend/app/icon.svg
index 6e9445d..025233e 100644
--- a/frontend/app/icon.svg
+++ b/frontend/app/icon.svg
@@ -1,11 +1,24 @@
diff --git a/frontend/app/page.js b/frontend/app/page.js
index 9cbeb19..3ffa6a3 100644
--- a/frontend/app/page.js
+++ b/frontend/app/page.js
@@ -4,21 +4,14 @@
import { useState, useEffect, useMemo, useCallback } from 'react'
import Link from 'next/link'
+import { useRouter } from 'next/navigation'
import { API } from './map/utils/constants'
-const trimDegree = (deg = '') => {
- const s = deg
- .replace(/^(Honours\s+)?Bachelor\s+of\s+\S+\s+/i, '')
- .replace(/,?\s*(Honours|Major|Minor|Concentration|Stream)\s*$/i, '')
- .trim()
- if (!s) return deg.split(' ').slice(0, 4).join(' ')
- return s.length > 38 ? s.slice(0, 36) + '…' : s
-}
export default function Home() {
- const [stats, setStats] = useState({ departments: null, programs: null, courses: null })
- const [featured, setFeatured] = useState([])
- const [depts, setDepts] = useState({})
+ const router = useRouter()
+ const [stats, setStats] = useState({ departments: null, programs: null, courses: null })
+ const [depts, setDepts] = useState({})
const [allPrograms, setAllPrograms] = useState(null)
const [searchQ, setSearchQ] = useState('')
const [searchOpen, setSearchOpen] = useState(false)
@@ -30,15 +23,13 @@ export default function Home() {
.then(d => { if (d) setStats(d) })
.catch(() => {})
- Promise.all([
- fetch(`${API}/departments`).then(r => r.json()),
- fetch(`${API}/programs/featured`).then(r => r.json()),
- ]).then(([deps, feat]) => {
- const deptMap = {}
- for (const d of deps) deptMap[d.dept_id] = d.name
- setDepts(deptMap)
- setFeatured(feat)
- }).catch(() => {})
+ fetch(`${API}/departments`)
+ .then(r => r.json())
+ .then(deps => {
+ const deptMap = {}
+ for (const d of deps) deptMap[d.dept_id] = d.name
+ setDepts(deptMap)
+ }).catch(() => {})
}, [])
const loadAllPrograms = useCallback(() => {
@@ -73,20 +64,17 @@ export default function Home() {
}}>
@@ -111,21 +99,47 @@ export default function Home() {
CarletonCourseMap