# Project export: SchedMaster

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: CruzHacks 2026
- Tagline: Build your perfect schedule
- Devpost: https://devpost.com/software/schedmaster
- GitHub: https://github.com/charviidesaii/ScheduleAI.git
- Video: https://www.youtube.com/embed/5kacHYqijRo?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 2 GitHub contributor(s) — charviidesaii (3 commits), saanvinadendla (1 commits)

## Devpost submission (written by the team)

No Devpost description available.

## README (from the GitHub repository)

# SchedMaster

**SchedMaster** is an AI-assisted course scheduling web application created for UC Santa Cruz students who want to build better class schedules with less stress. By combining professor ratings with course and time preferences, SchedMaster helps students make more confident academic decisions during quarterly enrollment.

Designed around the UCSC student experience, SchedMaster transforms informal professor feedback into clear and actionable schedule recommendations.

---

## What SchedMaster Does

SchedMaster guides students through a simple, step-by-step workflow to generate an optimized class schedule. Users begin by rating professors on a five-point scale based on personal experience or preference. They then select the courses they plan to take for the upcoming quarter. Using this input, the application generates a recommended schedule that prioritizes higher-rated professors, avoids time conflicts, and explains why each class was selected.

This approach reduces guesswork during enrollment and helps students feel more confident about their final schedule.

---

## Features

SchedMaster follows a guided three-step flow that mirrors how UCSC students typically plan their schedules. The application uses AI-assisted logic to rank and filter course options based on professor ratings and schedule compatibility. The interface is colorful yet professional and fully responsive, making it easy to use.

---

## Tech Stack

SchedMaster is built with a modern JavaScript frontend using **React** and **Vite** for fast development and performance. Styling is handled with **Tailwind CSS** to maintain a clean and consistent design. The backend is powered by **Node.js**, which handles scheduling logic, data processing, and communication with the AI layer. Antigravity is used to assist with ranking schedules based on user input. The project runs locally and does not rely on third-party hosting platforms.

---

## How the AI Works

SchedMaster uses Antigravity to assist with analyzing professor ratings and course preferences provided by the user. The system ranks course-professor combinations, filters out scheduling conflicts, and selects the most optimal schedule based on quality and compatibility. To maintain transparency, the application provides brief explanations describing why each class was recommended.

All course and professor data is mock data, and no real UCSC enrollment systems are accessed.

---

## Running Locally

To run SchedMaster locally, clone the repository from GitHub and install the required dependencies. After installation, start the development server and open the application in your browser at ` (http://169.233.121.48:5173/)`. This allows you to explore and modify the project in a local development environment.

---

## Future Improvements

Future versions of SchedMaster could include persistent storage for professor ratings, user accounts to save schedules across quarters, and additional scheduling preferences such as avoiding early morning classes or creating more compact schedules. Integration with real UCSC course data and a mobile-first version could be potential expansions.

---

## Inspiration

UCSC students often rely on spreadsheets, Reddit threads, or word of mouth when choosing professors. SchedMaster was created to centralize that decision-making process into a single, simple tool that makes scheduling clearer, faster, and less stressful.

---

## Team

SchedMaster was built for Cruzhacks with the UCSC community in mind. Feel free to explore the repository, fork the project, and build upon it.


## Detected evidence (automated analysis)

Indexed codebase: 23 recognized source files, 74 KB.
- CSS (language) — detected in the code
- Express (technology) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- React (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code
- Node.js (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (27 of 27)

```
.gitignore
eslint.config.js
index.html
package.json
postcss.config.js
README.md
server/cleanup_db.js
server/database.js
server/dedup_biology.js
server/fix_bio_time.js
server/fix_schedule_details.js
server/index.js
server/package.json
server/restore_course.js
src/App.jsx
src/components/AIBadge.jsx
src/components/Layout.jsx
src/components/Navbar.jsx
src/components/StepIndicator.jsx
src/index.css
src/main.jsx
src/pages/CourseSelectionPage.jsx
src/pages/LandingPage.jsx
src/pages/RateProfessorsPage.jsx
src/pages/ResultsPage.jsx
src/pages/ScheduleAI-1.code-workspace
vite.config.js
```

### Dependencies

- package.json: @eslint/js@^9.39.1, @tailwindcss/postcss@^4.1.18, @types/react@^19.2.5, @types/react-dom@^19.2.3, @vitejs/plugin-react@^5.1.1, autoprefixer@^10.4.23, eslint@^9.39.1, eslint-plugin-react-hooks@^7.0.1, eslint-plugin-react-refresh@^0.4.24, globals@^16.5.0, lucide-react@^0.562.0, postcss@^8.5.6, react@^19.2.0, react-dom@^19.2.0, react-router-dom@^7.12.0, tailwindcss@^4.1.18, vite@^7.2.4
- server/package.json: cors@^2.8.5, express@^4.19.2, nodemon@^3.1.0, sqlite3@^5.1.7

### Recent commits (newest first)

- Update README.md
- Update README.md
- Merge branch 'main' of https://github.com/charviidesaii/ScheduleAI
- Update application with latest changes
- Change local application URL in README
- Enable remote access and update reviewer name
- Update README.md
- Fix localhost proxy configuration
- feat: complete schedule app implementation
- Add files via upload
- Initial commit

## Key source files (fetched from GitHub, selected and truncated for size)

### package.json

```
{
  "name": "student-app",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite --host",
    "build": "vite build",
    "lint": "eslint .",
    "preview": "vite preview"
  },
  "dependencies": {
    "lucide-react": "^0.562.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "react-router-dom": "^7.12.0"
  },
  "devDependencies": {
    "@eslint/js": "^9.39.1",
    "@tailwindcss/postcss": "^4.1.18",
    "@types/react": "^19.2.5",
    "@types/react-dom": "^19.2.3",
    "@vitejs/plugin-react": "^5.1.1",
    "autoprefixer": "^10.4.23",
    "eslint": "^9.39.1",
    "eslint-plugin-react-hooks": "^7.0.1",
    "eslint-plugin-react-refresh": "^0.4.24",
    "globals": "^16.5.0",
    "postcss": "^8.5.6",
    "tailwindcss": "^4.1.18",
    "vite": "^7.2.4"
  }
}
```

### server/package.json

```
{
    "name": "schedule-ai-server",
    "version": "1.0.0",
    "description": "Backend for Schedule AI",
    "main": "index.js",
    "type": "module",
    "scripts": {
        "start": "node index.js",
        "dev": "nodemon index.js"
    },
    "dependencies": {
        "cors": "^2.8.5",
        "express": "^4.19.2",
        "sqlite3": "^5.1.7"
    },
    "devDependencies": {
        "nodemon": "^3.1.0"
    }
}
```

### src/main.jsx

```javascript
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import './index.css'

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
)

```

### src/App.jsx

```javascript
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import LandingPage from './pages/LandingPage';
import RateProfessorsPage from './pages/RateProfessorsPage';
import CourseSelectionPage from './pages/CourseSelectionPage';
import ResultsPage from './pages/ResultsPage';

import Layout from './components/Layout';

function App() {
    return (
        <Router>
            <Routes>
                <Route element={<Layout />}>
                    <Route path="/" element={<LandingPage />} />
                    <Route path="/rate" element={<RateProfessorsPage />} />
                    <Route path="/courses" element={<CourseSelectionPage />} />
                    <Route path="/schedule" element={<ResultsPage />} />
                </Route>
            </Routes>
        </Router>
    );
}

export default App;

```

### server/index.js

```javascript
import express from 'express';
import cors from 'cors';
import db from './database.js';

const app = express();
const PORT = 3001; // Running on port 3001 to avoid conflict with Vite (3000/5173)

app.use(cors());
app.use(express.json());

// Get all professors
app.get('/api/professors', (req, res) => {
    const sql = "SELECT * FROM professors";
    db.all(sql, [], (err, rows) => {
        if (err) {
            res.status(400).json({ "error": err.message });
            return;
        }
        res.json({
            "message": "success",
            "data": rows
        });
    });
});

// Add a new professor
app.post('/api/professors', (req, res) => {
    const { name, department } = req.body;

    const checkSql = "SELECT * FROM professors WHERE name = ?";
    db.get(checkSql, [name], (err, row) => {
        if (err) return res.status(400).json({ "error": err.message });
        if (row) {
            return res.json({
                "message": "success",
                "data": row
            });
        }

        const sql = 'INSERT INTO professors (name, department) VALUES (?,?)';
        const params = [name, department];
        db.run(sql, params, function (err, result) {
            if (err) {
                res.status(400).json({ "error": err.message });
                return;
            }
            res.json({
                "message": "success",
                "data": { id: this.lastID, name, department }
            });
        });
    });
});

// Get all courses
app.get('/api/courses', (req, res) => {
    const sql = "SELECT * FROM courses";
    db.all(sql, [], (err, rows) => {
        if (err) {
            res.status(400).json({ "error": err.message });
            return;
        }
        res.json({
            "message": "success",
            "data": rows
        });
    });
});

// Add a new course
app.post('/api/courses', (req, res) => {
    const { id, name, credits, days, start_time, end_time } = req.body;

    const checkSql = "SELECT * FROM courses WHERE id = ?";
    db.get(checkSql, [id], (err, row) => {
        if (err) return res.status(400).json({ "error": err.message });
        if (row) {
            return res.json({
                "message": "success",
                "data": row
            });
        }

        const sql = 'INSERT INTO courses (id, name, credits, days, start_time, end_time) VALUES (?,?,?,?,?,?)';
        const params = [id, name, credits, days, start_time, end_time];
        db.run(sql, params, function (err, result) {
            if (err) {
                res.status(400).json({ "error": err.message });
                return;
            }
            res.json({
                "message": "success",
                "data": { id, name, credits, days, start_time, end_time }
            });
        });
    });
});

// Get reviews (with optional filtering by professor)
app.get('/api/reviews', (req, res) => {
    const sql = "SELECT * FROM reviews ORDER BY timestamp DESC";
    db.all(sql, [], (err, rows) => {
        if (err) {
            res.status(400).json({ "error": err.message });
            return;
        }
        res.json({
            "message": "success",
            "data": rows
        });
    });
});

// Add a new review
app.post('/api/reviews', (req, res) => {
    const { professor_name, user_name, rating, comment, course_id } = req.body;
    const sql = 'INSERT INTO reviews (professor_name, user_name, rating, comment, course_id) VALUES (?,?,?,?,?)';
    const params = [professor_name, user_name, rating, comment, course_id];
    db.run(sql, params, function (err, result) {
        if (err) {
            res.status(400).json({ "error": err.message });
            return;
        }
        res.json({
            "message": "success",
            "data": { id: this.lastID, professor_name, user_name, rating, comment, course_id }
        });
    });
});

app.listen(PORT, () => {
    console.log(`Server running on port ${PORT}`);
});

```

### postcss.config.js

```javascript
export default {
    plugins: {
        '@tailwindcss/postcss': {},
        autoprefixer: {},
    },
}

```

### vite.config.js

```javascript
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

// https://vite.dev/config/
export default defineConfig({
  plugins: [react()],
  server: {
    proxy: {
      '/api': {
        target: 'http://127.0.0.1:3001',
        changeOrigin: true,
      },
    },
  },
})

```

### index.html

```html
<!doctype html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <link rel="icon" type="image/svg+xml" href="/vite.svg" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>student-app</title>
</head>

<body>
  <div id="root"></div>
  <script type="module" src="/src/main.jsx"></script>
</body>

</html>
```

### eslint.config.js

```javascript
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import { defineConfig, globalIgnores } from 'eslint/config'

export default defineConfig([
  globalIgnores(['dist']),
  {
    files: ['**/*.{js,jsx}'],
    extends: [
      js.configs.recommended,
      reactHooks.configs.flat.recommended,
      reactRefresh.configs.vite,
    ],
    languageOptions: {
      ecmaVersion: 2020,
      globals: globals.browser,
      parserOptions: {
        ecmaVersion: 'latest',
        ecmaFeatures: { jsx: true },
        sourceType: 'module',
      },
    },
    rules: {
      'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }],
    },
  },
])

```

### src/index.css

```css
@import "tailwindcss";

@theme {
  --color-primary: #4f46e5; /* indigo-600 */
  --color-secondary: #0d9488; /* teal-600 */
}

body {
  margin: 0;
  font-family: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  background-color: #f8fafc; /* slate-50 */
}

```

[14 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]