# Project export: Binder

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: Cal Hacks 11.0
- Tagline: The all-in-one academic collaboration platform designed to revolutionize the way students learn and interact.
- Devpost: https://devpost.com/software/binder-ethf9u
- GitHub: https://github.com/kpradjinata/Binder
- Team: 4 GitHub contributor(s) — kpradjinata (67 commits), BrentonO (38 commits), Ryan Tan (24 commits), David Tan (16 commits)

## Devpost submission (written by the team)

### Inspiration

Binder was inspired by the challenges faced by students in online and hybrid learning environments. We recognized the need for a comprehensive platform that could bridge the gap between virtual classrooms and collaborative study sessions, fostering a sense of community and enhancing the learning experience.

### What it does

Binder is an all-in-one academic collaboration platform that: Connects students to study groups with diverse skill sets Facilitates course-specific discussions through threaded forums Provides tools for scheduling and organizing group study sessions Integrates with Google Calendar and Zoom for seamless meeting planning Offers post-study quizzes to reinforce learning and track progress Recommends relevant study groups based on user interests and courses

### How we built it

We built Binder using: React for the frontend, leveraging functional components and hooks TypeScript for type-safe code React Router for navigation CSS for styling, with a focus on modern, clean design Integration with external APIs like Google Calendar Custom components for features like discussion threads, group management, and study session scheduling

### Challenges we ran into

Implementing real-time updates for discussions and comments Designing an intuitive user interface that accommodates various features without overwhelming users Integrating external services like Google Calendar and Zoom securely Ensuring smooth animations and transitions for a polished user experience Managing state across multiple components and pages

### Accomplishments we're proud of

Created a cohesive platform that addresses multiple aspects of collaborative learning Implemented a clean, modern UI with smooth animations and transitions Successfully integrated external services to enhance functionality Developed a flexible and scalable architecture that can accommodate future features

### What we learned

Advanced React patterns and state management techniques The importance of user experience in educational technology Strategies for integrating third-party services into a web application Techniques for optimizing performance in a feature-rich web app

### What's next

Adding real-time collaboration features, such as shared document editing Developing a mobile app version for on-the-go access Integrating AI-powered study recommendations and personalized learning paths Expanding quiz functionality to include more comprehensive assessment tools Partnering with educational institutions for wider adoption and integration with existing learning management systems

## README (from the GitHub repository)

# Binder - Your All-in-One Study Companion

## Description
Binder is a comprehensive educational platform designed to enhance collaborative learning and academic success. Our platform revolutionizes the way students learn by combining course management, interactive discussions, and automated quiz generation in one seamless interface.

## Problem Statement
Students face several challenges in modern education:
1. Lack of structured collaboration in online learning environments
2. Difficulty in organizing and managing study groups
3. Inefficient study session planning and follow-up

## Features

### Course Management
- View detailed course information and track progress
- Upload and analyze homework assignments (PDF format)
- Automated quiz generation from uploaded materials
- Track upcoming and completed assessments
- Visual progress tracking per course

### Discussion System
- Create and participate in course-specific discussions
- Real-time thread updates and commenting
- Anonymous posting options
- Organized thread navigation
- Animated UI feedback for user interactions

### Study Groups
- Join or create course-specific study groups
- Track group activity and participation
- Integrated study session scheduling
- Group progress monitoring

### Smart Features
- PDF analysis for homework and quiz generation
- Student grouping based on quiz performance
- Progress tracking across courses
- Personalized learning recommendations

## Technical Stack

### Frontend
- React with TypeScript
- React Router for navigation
- React Hooks for state management
- Custom CSS with modern animations

### Backend Integration
- Convex for API management
- PDF to Text conversion
- Quiz generation system
- Student performance analytics

## Installation

```bash
# Clone the repository
git clone [repository-url]

# Navigate to project directory
cd binder

# Install dependencies
npm install

# Start development server
npm run dev

## Detected evidence (automated analysis)

Indexed codebase: 103 recognized source files, 228 KB.
- CSS (language) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- Next.js (technology) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code
- TypeScript (language) — detected in the code
- Flask (technology) — claimed on Devpost, not found in the code
- OpenAI (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (120 of 122)

```
.gitignore
backend/README.md
frontend/.gitignore
frontend/convex/_generated/api.d.ts
frontend/convex/_generated/api.js
frontend/convex/_generated/dataModel.d.ts
frontend/convex/_generated/server.d.ts
frontend/convex/_generated/server.js
frontend/convex/auth.config.ts
frontend/convex/courses.ts
frontend/convex/discussions.ts
frontend/convex/groups.ts
frontend/convex/homeworks.ts
frontend/convex/quizzes.ts
frontend/convex/README.md
frontend/convex/schema.ts
frontend/convex/student_courses.ts
frontend/convex/student_quiz_res.ts
frontend/convex/student_skills.ts
frontend/convex/students.ts
frontend/convex/tasks.ts
frontend/convex/tsconfig.json
frontend/eslint.config.js
frontend/index.html
frontend/package.json
frontend/README.md
frontend/src/App.css
frontend/src/App.tsx
frontend/src/components/CourseOverview.tsx
frontend/src/components/EventDetailsPopup.tsx
frontend/src/components/GroupDetailsOverlay.tsx
frontend/src/components/GroupSession.tsx
frontend/src/components/InboxPopup.tsx
frontend/src/components/QuizQuestion.tsx
frontend/src/components/Sidebar.tsx
frontend/src/components/TrendingDiscussion.tsx
frontend/src/components/UpcomingEvents.tsx
frontend/src/index.css
frontend/src/main.tsx
frontend/src/pages/Analytics.tsx
frontend/src/pages/ContentLibrary.tsx
frontend/src/pages/CoursePage.tsx
frontend/src/pages/Dashboard.tsx
frontend/src/pages/Discussion.tsx
frontend/src/pages/Groups.tsx
frontend/src/pages/LandingPage.tsx
frontend/src/pages/Profile.tsx
frontend/src/pages/Quiz.tsx
frontend/src/pages/ThreadPage.tsx
frontend/src/styles/ContentLibrary.css
frontend/src/styles/CourseOverview.css
frontend/src/styles/CoursePage.css
frontend/src/styles/Dashboard.css
frontend/src/styles/Discussion.css
frontend/src/styles/EventDetailsPopup.css
frontend/src/styles/Groups.css
frontend/src/styles/GroupSession.css
frontend/src/styles/InboxPopup.css
frontend/src/styles/LandingPage.css
frontend/src/styles/Profile.css
frontend/src/styles/Quiz.css
frontend/src/styles/QuizQuestion.css
frontend/src/styles/Sidebar.css
frontend/src/styles/TrendingDiscussion.css
frontend/src/styles/UpcomingEvents.css
frontend/src/vite-env.d.ts
frontend/tsconfig.app.json
frontend/tsconfig.json
frontend/tsconfig.node.json
frontend/vite.config.ts
LICENSE
LLM/create_groups.py
LLM/generateCategories.py
LLM/skill1.csv
LLM/skill2.csv
LLM/skill3.csv
LLM/test_requests.py
my-app/.eslintrc.json
my-app/.gitignore
my-app/app/api/getStudentId/route.ts
my-app/app/api/store-quiz/route.ts
my-app/app/ConvexClientProvider.tsx
my-app/app/globals.css
my-app/app/header.tsx
my-app/app/layout.tsx
my-app/app/page.tsx
my-app/app/providers.tsx
my-app/app/quiz/page.tsx
my-app/components.json
my-app/components/QuizQuestion.tsx
my-app/components/theme-provider.tsx
my-app/components/ui/button.tsx
my-app/components/ui/dropdown-menu.tsx
my-app/components/ui/mode-toggle.tsx
my-app/convex/_generated/api.d.ts
my-app/convex/_generated/api.js
my-app/convex/_generated/dataModel.d.ts
my-app/convex/_generated/server.d.ts
my-app/convex/_generated/server.js
my-app/convex/auth.config.ts
my-app/convex/courses.ts
my-app/convex/discussions.ts
my-app/convex/groups.ts
my-app/convex/homeworks.ts
my-app/convex/quizzes.ts
my-app/convex/README.md
my-app/convex/schema.ts
my-app/convex/student_skills.ts
my-app/convex/studentCourses.ts
my-app/convex/students.ts
my-app/convex/tasks.ts
my-app/convex/tsconfig.json
my-app/lib/utils.ts
my-app/next.config.mjs
my-app/package.json
my-app/postcss.config.mjs
my-app/README.md
my-app/styles/Quiz.css
my-app/styles/QuizQuestion.css
my-app/tailwind.config.ts
[2 more files omitted for size]
```

### Dependencies

- frontend/package.json: @clerk/clerk-react@^5.12.0, @eslint/js@^9.11.1, @radix-ui/react-icons@^1.3.0, @types/react@^18.3.10, @types/react-dom@^18.3.0, @vitejs/plugin-react@^4.3.2, axios@^1.7.7, convex@^1.16.6, eslint@^9.11.1, eslint-plugin-react-hooks@^5.1.0-rc.0, eslint-plugin-react-refresh@^0.4.12, framer-motion@^11.11.9, globals@^15.9.0, react@^18.3.1, react-dom@^18.3.1, react-intersection-observer@^9.13.1, react-pdftotext@^1.3.3, react-router-dom@^6.27.0, recharts@^2.13.0, typescript@^5.5.3, typescript-eslint@^8.7.0, vite@^5.4.9
- my-app/package.json: @clerk/nextjs@^5.7.2, @radix-ui/react-dropdown-menu@^2.1.2, @radix-ui/react-icons@^1.3.0, @radix-ui/react-slot@^1.1.0, @types/node@^20, @types/react@^18, @types/react-dom@^18, class-variance-authority@^0.7.0, clsx@^2.1.1, convex@^1.16.5, eslint@^8, eslint-config-next@14.2.15, lucide-react@^0.453.0, next@14.2.15, next-themes@^0.3.0, pdf.js-extract@^0.2.1, postcss@^8, react@^18, react-dom@^18, tailwind-merge@^2.5.4, tailwindcss@^3.4.1, tailwindcss-animate@^1.0.7, typescript@^5

### Recent commits (newest first)

- Update README
- update
- Remove unused import of useEffect in CoursePage component
- Merge pull request #51 from kpradjinata/idfk
- Merge pull request #50 from kpradjinata/count
- inbox
- Update group member counts for accuracy
- Merge pull request #49 from kpradjinata/david3
- Merge branch 'main' into david3
- Update sidebar path to lowercase and enhance event descriptions for clarity
- modify convex schemas and store user skill
- Merge pull request #48 from kpradjinata/x
- Add thread loading animation and new comment fade-in effect
- Sidebar Animation
- Landing Change and Discussion Animation
- Merge pull request #47 from kpradjinata/wa
- Dashboard animations
- Merge pull request #46 from kpradjinata/newnr
- Merge pull request #45 from kpradjinata/oy
- added more pictures

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

### my-app/package.json

```
{
  "name": "my-app",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "@clerk/nextjs": "^5.7.2",
    "@radix-ui/react-dropdown-menu": "^2.1.2",
    "@radix-ui/react-icons": "^1.3.0",
    "@radix-ui/react-slot": "^1.1.0",
    "class-variance-authority": "^0.7.0",
    "clsx": "^2.1.1",
    "convex": "^1.16.5",
    "lucide-react": "^0.453.0",
    "next": "14.2.15",
    "next-themes": "^0.3.0",
    "pdf.js-extract": "^0.2.1",
    "react": "^18",
    "react-dom": "^18",
    "tailwind-merge": "^2.5.4",
    "tailwindcss-animate": "^1.0.7"
  },
  "devDependencies": {
    "@types/node": "^20",
    "@types/react": "^18",
    "@types/react-dom": "^18",
    "eslint": "^8",
    "eslint-config-next": "14.2.15",
    "postcss": "^8",
    "tailwindcss": "^3.4.1",
    "typescript": "^5"
  }
}

```

### frontend/package.json

```
{
  "name": "my-react-app",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "tsc -b && vite build",
    "lint": "eslint .",
    "preview": "vite preview"
  },
  "dependencies": {
    "@clerk/clerk-react": "^5.12.0",
    "@radix-ui/react-icons": "^1.3.0",
    "axios": "^1.7.7",
    "convex": "^1.16.6",
    "framer-motion": "^11.11.9",
    "react": "^18.3.1",
    "react-dom": "^18.3.1",
    "react-intersection-observer": "^9.13.1",
    "react-pdftotext": "^1.3.3",
    "react-router-dom": "^6.27.0",
    "recharts": "^2.13.0"
  },
  "devDependencies": {
    "@eslint/js": "^9.11.1",
    "@types/react": "^18.3.10",
    "@types/react-dom": "^18.3.0",
    "@vitejs/plugin-react": "^4.3.2",
    "eslint": "^9.11.1",
    "eslint-plugin-react-hooks": "^5.1.0-rc.0",
    "eslint-plugin-react-refresh": "^0.4.12",
    "globals": "^15.9.0",
    "typescript": "^5.5.3",
    "typescript-eslint": "^8.7.0",
    "vite": "^5.4.9"
  }
}

```

### frontend/src/main.tsx

```typescript
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import App from './App.tsx'
import './index.css'
import { ClerkProvider } from '@clerk/clerk-react'
import { ConvexProviderWithClerk } from 'convex/react-clerk'
import { ConvexReactClient } from 'convex/react'
import { useAuth } from '@clerk/clerk-react'
const PUBLISHABLE_KEY = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY

const convexClient = new ConvexReactClient(import.meta.env.VITE_CONVEX_URL)

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <ClerkProvider publishableKey={PUBLISHABLE_KEY} afterSignOutUrl="/auth">
      <ConvexProviderWithClerk client={convexClient} useAuth={useAuth}>
        <App />
      </ConvexProviderWithClerk>
    </ClerkProvider>
  </StrictMode>,
)

```

### my-app/app/layout.tsx

```typescript
import type { Metadata } from "next";
import localFont from "next/font/local";
import "./globals.css";
import { Providers } from "./providers";
import { Header } from "./header";


const geistSans = localFont({
  src: "./fonts/GeistVF.woff",
  variable: "--font-geist-sans",
  weight: "100 900",
});
const geistMono = localFont({
  src: "./fonts/GeistMonoVF.woff",
  variable: "--font-geist-mono",
  weight: "100 900",
});

export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en" suppressHydrationWarning>
      <body
        className={`${geistSans.variable} ${geistMono.variable} antialiased`}
      >
        <Providers>
          <Header />
          {children}
        </Providers>
      </body>
    </html>
  );
}

```

### frontend/src/App.tsx

```typescript
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import Dashboard from './pages/Dashboard';
import Groups from "./pages/Groups";
import CoursePage from "./pages/CoursePage";
import ContentLibrary from "./pages/ContentLibrary";
import Analytics from "./pages/Analytics"
import Profile from "./pages/Profile"
import LandingPage from "./pages/LandingPage";


import Quiz from './pages/Quiz';

import Discussion from './pages/Discussion';

import './App.css';

function App() {
  return (
    <Router>
      <Routes>
        <Route path="/" element={<LandingPage />} />
        <Route path="/discussion/*" element={<Discussion />} />
        <Route path="/quiz" element={<Quiz />} />
        <Route path="/groups" element={<Groups />} />
        <Route path="/course/:courseName" element={<CoursePage />} />
        <Route path="/content-library" element={<ContentLibrary />} />
        <Route path="/analytics" element={<Analytics />} />
        <Route path="/profile" element={<Profile />} />
        <Route path="/dashboard" element={<Dashboard />} />
      </Routes>
    </Router>
  );
}

export default App;
```

### my-app/app/page.tsx

```typescript
"use client";

import { api } from "@/convex/_generated/api";
import { SignInButton, UserButton } from "@clerk/nextjs";
import { Authenticated, Unauthenticated, useMutation, useQuery } from "convex/react";
import { useState } from "react";

import { useUser } from "@clerk/clerk-react";

import { Button } from "@/components/ui/button"


export default function Home() {
  const [task, setTask] = useState("");
  const createTask = useMutation(api.tasks.createTask);
  const tasks = useQuery(api.tasks.getTasks);
  const studentCourses = useQuery(api.courses.getStudentCourses);
  // const userId = useQuery(api.students.getCurrentStudentId);

  // const createHomework = useMutation(api.homeworks.createHomework);
  // const createQuiz = useMutation(api.quizzes.createQuiz);

  const { user } = useUser();

  // function createHomeworkHandler() {
  //   homework = fetch()

  //   createHomework({
  //     id: "1",
  //     courseId: "1",
  //   })
  // }

  // function createQuizHandler() {
  //   quiz = fetch()

  //   createHomework({
  //     id: "1",
  //     courseId: "1",
  //   })
  // }


  // function createDiscussionHandler() {

  // }

  const [courseTitle, setCourseTitle] = useState("");
  const [courseNumber, setCourseNumber] = useState("");
  const createCourse = useMutation(api.courses.createCourse);


  function createCourseHandler(e: React.FormEvent) {
    e.preventDefault();
    createCourse({
      id: Math.random().toString(36).slice(2, 9), // Generate a random ID
      collegeId: "default_college_id", // You might want to make this dynamic
      subject: courseTitle,
      courseNumber: courseNumber,
      syllabus: "", // You can add this later if needed
    });
    setCourseTitle("");
    setCourseNumber("");
  }


  function homeworkHandler(e: React.FormEvent) {
    e.preventDefault();

    homework_questions = fetch()

    createHomework({
      id: "1",
      courseId: "1",
      name: "1",
      questions: homework_questions,
    })

    quiz = fetch()




  }




  return (
    <div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)]">
      <main className="flex flex-col gap-8 row-start-2 items-center sm:items-start">


        <div className="flex gap-4 items-center flex-col sm:flex-row">
          <form
            onSubmit={(e) => {
              e.preventDefault();
              createTask({ text: task });
              setTask("");
            }}
          >
            <input type="text" onChange={(e) => setTask(e.target.value)} value={task} placeholder="New Task" className="border-2 border-gray-300 rounded-md p-2" />
            <Button type="submit" className="bg-blue-500 text-white p-2 rounded-md">Add Task</Button>
            <Button>Click me</Button>
          </form>
        </div>
        <ul className="flex flex-col gap-4">
          {tasks?.map((task) => (
            <li key={task._id}>{task.text}</li>
          ))}
        </ul>
        <ul className="flex flex-col gap-4">
          {tasks?.map((task) => (
            <li key={task._id}>{task.text}</li>
          ))}
        </ul>

        <ul className="flex flex-col gap-4">
          {studentCourses?.map((course) => (
            <li key={course._id}>{course.courseId}{course.subject}</li>
          ))}
        </ul>
        {/* <span>Logged in as {user?.fullName}</span>; */}

        <form onSubmit={createCourseHandler} className="flex flex-col gap-4">
          <input
            type="text"
            value={courseTitle}
            onChange={(e) => setCourseTitle(e.target.value)}
            placeholder="Course Title"
            className="border-2 border-gray-300 rounded-md p-2"
          />
          <input
            type="text"
            value={courseNumber}
            onChange={(e) => setCourseNumber(e.target.value)}
            placeholder="Course Number"
            className="border-2 border-gray-300 rounded-md p-2"
          />
          <Button type="submit" className="bg-blue-500 text-white p-2 rounded-md">
            Create Course
          </Button>
        </form>

      </main>
    </div>
  );
}

```

### my-app/app/quiz/page.tsx

```typescript
"use client"

import React, { useState } from 'react';
import QuizQuestion from '../../components/QuizQuestion';
import '../../styles/Quiz.css';

interface QuizData {
    questions: string[];
    options: string[][];
    answers: string[];
}

const quizData: QuizData = {
    questions: [
        "What is 5 + 3?",
        "What is the square root of 16?",
        "Solve for x: 2x + 3 = 7",
        "What is the value of π (Pi) rounded to two decimal places?",
        "What is 9 * 6?",
        "What is the derivative of x^2?",
        "What is the value of cos(0)?",
        "What is 15 % 4 (15 modulo 4)?",
        "What is the sum of angles in a triangle?",
        "What is the area of a circle with radius 3?"
    ],
    options: [
        ["6", "7", "8", "9"],
        ["2", "3", "4", "5"],
        ["x = 1", "x = 2", "x = 3", "x = 4"],
        ["3.12", "3.14", "3.16", "3.18"],
        ["42", "48", "54", "56"],
        ["x", "2x", "2", "x^2"],
        ["0", "1", "-1", "undefined"],
        ["1", "2", "3", "4"],
        ["90 degrees", "180 degrees", "270 degrees", "360 degrees"],
        ["9π", "12π", "18π", "36π"]
    ],
    answers: ["8", "4", "x = 2", "3.14", "54", "2x", "1", "3", "180 degrees", "9π"]
};

const Quiz: React.FC = () => {
    const [userAnswers, setUserAnswers] = useState<string[]>(new Array(quizData.questions.length).fill(''));
    const [quizSubmitted, setQuizSubmitted] = useState(false);

    const handleAnswerSelect = (questionIndex: number, answer: string) => {
        const newAnswers = [...userAnswers];
        newAnswers[questionIndex] = answer;
        setUserAnswers(newAnswers);
    };

    const handleSubmitQuiz = () => {
        const unansweredQuestions = userAnswers.filter(answer => answer === '').length;

        if (unansweredQuestions > 0) {
            const confirmSubmit = window.confirm(
                `You haven't answered all questions. There are ${unansweredQuestions} unanswered questions. Do you want to submit anyway?`
            );
            if (!confirmSubmit) {
                return;
            }
        }

        setQuizSubmitted(true);
    };

    const calculateScore = () => {
        let correctAnswers = 0;
        userAnswers.forEach((answer, index) => {
            if (answer === quizData.answers[index]) {
                correctAnswers++;
            }
        });
        return `${correctAnswers}/${quizData.questions.length}`;
    };

    return (
        <div className="quiz-container">
            <h2>Quiz (Number)</h2>
            {quizData.questions.map((question, index) => (
                <QuizQuestion
                    key={index}
                    questionNumber={index + 1}
                    question={question}
                    options={quizData.options[index]}
                    onAnswerSelect={(answer) => handleAnswerSelect(index, answer)}
                    selectedAnswer={userAnswers[index]}
                    isSubmitted={quizSubmitted}
                    correctAnswer={quizData.answers[index]}
                />
            ))}
            {!quizSubmitted && (
                <button className="submit-button" onClick={handleSubmitQuiz}>Submit Quiz</button>
            )}
            {quizSubmitted && (
                <div className="quiz-results">
                    <h3>Quiz Completed!</h3>
                    <p>Your score: {calculateScore()}</p>
                </div>
            )}
        </div>
    );
};

export default Quiz;
```

### frontend/convex/_generated/server.js

```javascript
/* prettier-ignore-start */

/* eslint-disable */
/**
 * Generated utilities for implementing server-side Convex query and mutation functions.
 *
 * THIS CODE IS AUTOMATICALLY GENERATED.
 *
 * To regenerate, run `npx convex dev`.
 * @module
 */

import {
  actionGeneric,
  httpActionGeneric,
  queryGeneric,
  mutationGeneric,
  internalActionGeneric,
  internalMutationGeneric,
  internalQueryGeneric,
} from "convex/server";

/**
 * Define a query in this Convex app's public API.
 *
 * This function will be allowed to read your Convex database and will be accessible from the client.
 *
 * @param func - The query function. It receives a {@link QueryCtx} as its first argument.
 * @returns The wrapped query. Include this as an `export` to name it and make it accessible.
 */
export const query = queryGeneric;

/**
 * Define a query that is only accessible from other Convex functions (but not from the client).
 *
 * This function will be allowed to read from your Convex database. It will not be accessible from the client.
 *
 * @param func - The query function. It receives a {@link QueryCtx} as its first argument.
 * @returns The wrapped query. Include this as an `export` to name it and make it accessible.
 */
export const internalQuery = internalQueryGeneric;

/**
 * Define a mutation in this Convex app's public API.
 *
 * This function will be allowed to modify your Convex database and will be accessible from the client.
 *
 * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
 * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
 */
export const mutation = mutationGeneric;

/**
 * Define a mutation that is only accessible from other Convex functions (but not from the client).
 *
 * This function will be allowed to modify your Convex database. It will not be accessible from the client.
 *
 * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
 * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
 */
export const internalMutation = internalMutationGeneric;

/**
 * Define an action in this Convex app's public API.
 *
 * An action is a function which can execute any JavaScript code, including non-deterministic
 * code and code with side-effects, like calling third-party services.
 * They can be run in Convex's JavaScript environment or in Node.js using the "use node" directive.
 * They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}.
 *
 * @param func - The action. It receives an {@link ActionCtx} as its first argument.
 * @returns The wrapped action. Include this as an `export` to name it and make it accessible.
 */
export const action = actionGeneric;

/**
 * Define an action that is only accessible from other Convex functions (but not from the client).
 *
 * @param func - The function. It receives an {@link ActionCtx} as its first argument.
 * @returns The wrapped function. Include this as an `export` to name it and make it accessible.
 */
export const internalAction = internalActionGeneric;

/**
 * Define a Convex HTTP action.
 *
 * @param func - The function. It receives an {@link ActionCtx} as its first argument, and a `Request` object
 * as its second.
 * @returns The wrapped endpoint function. Route a URL path to this function in `convex/http.js`.
 */
export const httpAction = httpActionGeneric;

/* prettier-ignore-end */

```

### my-app/convex/_generated/server.js

```javascript
/* prettier-ignore-start */

/* eslint-disable */
/**
 * Generated utilities for implementing server-side Convex query and mutation functions.
 *
 * THIS CODE IS AUTOMATICALLY GENERATED.
 *
 * To regenerate, run `npx convex dev`.
 * @module
 */

import {
  actionGeneric,
  httpActionGeneric,
  queryGeneric,
  mutationGeneric,
  internalActionGeneric,
  internalMutationGeneric,
  internalQueryGeneric,
} from "convex/server";

/**
 * Define a query in this Convex app's public API.
 *
 * This function will be allowed to read your Convex database and will be accessible from the client.
 *
 * @param func - The query function. It receives a {@link QueryCtx} as its first argument.
 * @returns The wrapped query. Include this as an `export` to name it and make it accessible.
 */
export const query = queryGeneric;

/**
 * Define a query that is only accessible from other Convex functions (but not from the client).
 *
 * This function will be allowed to read from your Convex database. It will not be accessible from the client.
 *
 * @param func - The query function. It receives a {@link QueryCtx} as its first argument.
 * @returns The wrapped query. Include this as an `export` to name it and make it accessible.
 */
export const internalQuery = internalQueryGeneric;

/**
 * Define a mutation in this Convex app's public API.
 *
 * This function will be allowed to modify your Convex database and will be accessible from the client.
 *
 * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
 * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
 */
export const mutation = mutationGeneric;

/**
 * Define a mutation that is only accessible from other Convex functions (but not from the client).
 *
 * This function will be allowed to modify your Convex database. It will not be accessible from the client.
 *
 * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
 * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
 */
export const internalMutation = internalMutationGeneric;

/**
 * Define an action in this Convex app's public API.
 *
 * An action is a function which can execute any JavaScript code, including non-deterministic
 * code and code with side-effects, like calling third-party services.
 * They can be run in Convex's JavaScript environment or in Node.js using the "use node" directive.
 * They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}.
 *
 * @param func - The action. It receives an {@link ActionCtx} as its first argument.
 * @returns The wrapped action. Include this as an `export` to name it and make it accessible.
 */
export const action = actionGeneric;

/**
 * Define an action that is only accessible from other Convex functions (but not from the client).
 *
 * @param func - The function. It receives an {@link ActionCtx} as its first argument.
 * @returns The wrapped function. Include this as an `export` to name it and make it accessible.
 */
export const internalAction = internalActionGeneric;

/**
 * Define a Convex HTTP action.
 *
 * @param func - The function. It receives an {@link ActionCtx} as its first argument, and a `Request` object
 * as its second.
 * @returns The wrapped endpoint function. Route a URL path to this function in `convex/http.js`.
 */
export const httpAction = httpActionGeneric;

/* prettier-ignore-end */

```

### my-app/app/api/getStudentId/route.ts

```typescript
import { NextResponse } from 'next/server';
import { ConvexHttpClient } from "convex/browser";
import { api } from "@/convex/_generated/api";

const convex = new ConvexHttpClient(process.env.NEXT_PUBLIC_CONVEX_URL!);

export async function GET() {
    try {
        const result = await convex.query(api.students.getCurrentStudentId);
        return NextResponse.json({ userId: result });
    } catch (error) {
        console.error('Error fetching user ID:', error);
        return NextResponse.json({ error: 'Failed to fetch user ID' }, { status: 500 });
    }
}

```

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