# Project export: graider

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: Our AI grading system automates grading for essays and exams, reducing workload and offering personalized feedback to students, highlighting mistakes and giving guidance on how to improve.
- Devpost: https://devpost.com/software/graider-axtu51
- GitHub: https://github.com/saumyajain1/graider
- Team: 0 GitHub contributor(s) — 

## Devpost submission (written by the team)

### Inspiration

We realized that grading papers is time-consuming and repetitive, often lacking meaningful feedback for students. This inspired us to create a solution that automates grading and enhances student feedback.

### What it does

Graider grades essays, assignments, and exams based on a provided rubric or one generated from the exam sheet. It also includes a feedback section for both students and graders, making the process more efficient and insightful.

### How we built it

We built the platform entirely using Python, leveraging Reflex to develop both the frontend and backend seamlessly. We also utilized the Groq LLM library to handle the complexities of grading papers accurately and efficiently

### Challenges we ran into

Working with Reflex, a new technology, was challenging. As we adapted to it, we faced a steep learning curve in scaling our project quickly using only our knowledge of Python.

### Accomplishments we're proud of

We’re proud of building an entire system using Python (thanks to Reflex). Additionally, we explored new tools provided by our sponsors—VAPI, Groq, and Fetch AI—which helped us enhance the project by integrating advanced AI capabilities.

### What we learned

We gained a deep understanding of Reflex and how to build frontend applications entirely in Python. We also explored different LLM models, refining our approach to achieve optimal latency rates suitable for the project’s needs.

### What's next

We plan to add a chatbot feature that allows graders to adjust student grades via voice commands. Additionally, we aim to incorporate image scanning to grade handwritten papers automatically. Our goal is to scale Graider to educational institutions across the country.

## README (from the GitHub repository)

# Graider

Graider helps teachers turn assignments into structured questions, prepare reference answers and rubrics, grade student submissions, and review the results before exporting them.

[Live demo](https://graider-xt2w.onrender.com/login) · [Docker image](https://hub.docker.com/r/saumyaj1/graider) · [Documentation](#documentation)

The demo runs on a sleeping free service; the first visit can be slow. Use sample student data.

## Features

- Create assignments from text, TXT files or PDFs, with editable questions and mark allocations.
- Generate reference answers and rubrics with AI, or write them manually.
- Import submissions individually, from files or through CSV.
- Grade with AI against the saved reference answer and every rubric criterion; review and edit criterion scores and feedback with calculated totals.
- Run AI actions in persistent background jobs, with progress, cancellation, controlled retries and recovery after restart.
- Publish each student's complete result independently while other students continue grading.
- Sign in with passwords or Google, explicitly connect accounts, and manage profile and credentials.
- Keep uploads private and enforce teacher access, upload limits and AI usage quotas.
- Explore the automatically generated API through Swagger UI at `/api/docs/`.

## Engineering results

- A **production 10-student × 10-question grading run finished in 1 minute 54 seconds**, including answer mapping and **110 real OpenAI calls**, on Render's **0.1-CPU / 512-MB Free service**; sampled peak memory was **313.8 MiB**.
- Container restart preserved **100 question results, 200 criterion breakdowns and 110 successful usage records**, without repeating provider calls.
- Process-death and connection-loss checks cover checkpoint recovery, atomic publication, concurrent workers and uncertain billing.
- GitHub Actions verifies the repository, publishes Docker images for Intel/AMD and Apple Silicon, and triggers Render with the passing commit image.

The production benchmark uses short synthetic arithmetic answers, real GPT-6 Luna and Neon PostgreSQL; setup and startup are outside its timer. Local concurrency and process-failure experiments use simulated calls. See [benchmarks and their limits](docs/BENCHMARKS.md).

## Tech stack

| Layer                 | Technology                                                                                   |
| --------------------- | -------------------------------------------------------------------------------------------- |
| Frontend              | React, TypeScript, Vite, Tailwind CSS                                                        |
| Backend               | Django, Django REST Framework, Gunicorn, WhiteNoise                                          |
| Identity and API docs | django-allauth, Google OIDC, drf-spectacular                                                 |
| Persistence           | Neon PostgreSQL and private S3-compatible Object Storage; SQLite/local files for development |
| AI                    | OpenAI SDK, task-specific model and reasoning configuration                                  |
| Delivery              | Docker, Docker Hub, GitHub Actions, Render                                                   |

## Documentation

| Page                                                         | Contents                                                                                            |
| ------------------------------------------------------------ | --------------------------------------------------------------------------------------------------- |
| [Architecture](docs/ARCHITECTURE.md)                         | System and data diagrams, component boundaries, security and design decisions                       |
| [Grading workflow](docs/GRADING.md)                          | Assignment preparation, answer mapping, criterion scoring, concurrency, recovery and teacher review |
| [Benchmarks](docs/BENCHMARKS.md)                             | Current and historical grading timings, test conditions, recovery evidence and reproduction         |
| [Setup and deployment](docs/SETUP.md)                        | Docker quickstart, source development, environment settings, accounts, Render and maintenance       |
| [Issues and roadmap](docs/ROADMAP.md)                        | Unresolved limitations, upcoming features and proposed improvements                                 |
| [Production grading report](docs/ai-grading-production.json) | Real-provider timings, resource samples, usage and restart evidence                                 |
| [Raw grading benchmarks](docs/ai-grading-concurrency.json)   | Concurrency experiments, isolated grading measurements and runtime image ID                         |
| [Earlier capacity report](docs/ai-job-capacity.json)         | Historical full-workflow, startup and restart measurements                                          |

These pages describe this checkout; the deployed demo and published `latest` image may lag it.

Start with the [Docker quickstart](docs/SETUP.md#run-locally-with-docker) to use the app, or [source development](docs/SETUP.md#develop-from-source) to change it.


## Detected evidence (automated analysis)

Indexed codebase: 76 recognized source files, 313 KB.
- CSS (language) — detected in the code
- Django (technology) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- OpenAI (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
- Google Gemini (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (84 of 84)

```
.env.example
.gitignore
backend/apps/__init__.py
backend/apps/accounts/__init__.py
backend/apps/accounts/admin.py
backend/apps/accounts/apps.py
backend/apps/accounts/migrations/__init__.py
backend/apps/accounts/migrations/0001_initial.py
backend/apps/accounts/models.py
backend/apps/accounts/serializers.py
backend/apps/accounts/tests.py
backend/apps/accounts/urls.py
backend/apps/accounts/views.py
backend/apps/assignments/__init__.py
backend/apps/assignments/admin.py
backend/apps/assignments/apps.py
backend/apps/assignments/migrations/__init__.py
backend/apps/assignments/migrations/0001_initial.py
backend/apps/assignments/models.py
backend/apps/assignments/serializers.py
backend/apps/assignments/services.py
backend/apps/assignments/tests.py
backend/apps/assignments/urls.py
backend/apps/assignments/views.py
backend/apps/grading/__init__.py
backend/apps/grading/admin.py
backend/apps/grading/apps.py
backend/apps/grading/migrations/__init__.py
backend/apps/grading/migrations/0001_initial.py
backend/apps/grading/models.py
backend/apps/grading/serializers.py
backend/apps/grading/services/__init__.py
backend/apps/grading/services/generation.py
backend/apps/grading/services/grading_pipeline.py
backend/apps/grading/services/openai_client.py
backend/apps/grading/services/schemas.py
backend/apps/grading/services/submission_io.py
backend/apps/grading/services/submission_workflow.py
backend/apps/grading/tests.py
backend/apps/grading/urls.py
backend/apps/grading/views.py
backend/config/__init__.py
backend/config/asgi.py
backend/config/settings.py
backend/config/urls.py
backend/config/wsgi.py
backend/manage.py
backend/requirements.txt
frontend/.gitignore
frontend/eslint.config.js
frontend/index.html
frontend/package.json
frontend/postcss.config.js
frontend/README.md
frontend/src/api/assignments.ts
frontend/src/api/auth.ts
frontend/src/api/client.ts
frontend/src/api/errors.ts
frontend/src/api/grading.ts
frontend/src/app/providers.tsx
frontend/src/app/routeGuards.tsx
frontend/src/app/router.tsx
frontend/src/components/layout/AppShell.tsx
frontend/src/hooks/useAuth.ts
frontend/src/index.css
frontend/src/main.tsx
frontend/src/pages/AssignmentCreatePage.tsx
frontend/src/pages/AssignmentOverviewPage.tsx
frontend/src/pages/AssignmentQuestionsPage.tsx
frontend/src/pages/AssignmentReferenceAnswersPage.tsx
frontend/src/pages/AssignmentReviewPage.tsx
frontend/src/pages/AssignmentRubricPage.tsx
frontend/src/pages/AssignmentSubmissionsPage.tsx
frontend/src/pages/DashboardPage.tsx
frontend/src/pages/LoginPage.tsx
frontend/src/pages/SubmissionReviewPage.tsx
frontend/src/vite-env.d.ts
frontend/tailwind.config.js
frontend/tsconfig.app.json
frontend/tsconfig.json
frontend/tsconfig.node.json
frontend/vite.config.ts
graider_v_1_design_doc.md
README.md
```

### Dependencies

- backend/requirements.txt: Django@==5.2.12, django-cors-headers@==4.9.0, djangorestframework@==3.17.1, openai@==2.29.0, pydantic@==2.12.5, pypdf@==6.9.2, python-dotenv@==1.2.2, reportlab@==4.4.10
- frontend/package.json: @eslint/js@^9.13.0, @tanstack/react-query@^5.95.2, @types/node@^25.5.0, @types/react@^18.3.12, @types/react-dom@^18.3.1, @vitejs/plugin-react@^4.3.3, autoprefixer@^10.4.27, clsx@^2.1.1, eslint@^9.13.0, eslint-plugin-react-hooks@^5.0.0, eslint-plugin-react-refresh@^0.4.14, globals@^15.11.0, postcss@^8.5.8, react@^18.3.1, react-dom@^18.3.1, react-router-dom@^6.30.3, tailwindcss@^3.4.17, typescript@~5.6.2, typescript-eslint@^8.11.0, vite@^5.4.10

### Recent commits (newest first)

- docs: refine the public V1 design overview
- Update README.md
- feat: add submission review and export screens
- feat: grade imported student submissions end to end
- feat: add reference answers and rubric authoring
- feat: generate question maps from assignment source text
- feat: add assignment authoring and manual question setup
- feat: build teacher authentication and a protected workspace
- chore: scaffold the Django and React workspaces
- chore: establish the public repository baseline

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

### graider_v_1_design_doc.md

```markdown
# Graider V1 Design Overview

## Purpose

Graider is an AI-assisted grading MVP for teachers. It helps a teacher turn an assignment into structured grading artifacts, run an initial grading pass over student submissions, and review the results before finalizing marks.

The product is intentionally teacher-controlled:

1. Create an assignment from pasted text, `.txt`, or `.pdf`.
2. Build or generate question parts.
3. Create reference answers and rubric criteria.
4. Add student submissions manually, from uploaded files, or by CSV.
5. Run AI-assisted grading.
6. Review, edit, finalize, and export results.

AI output is never the final authority. Teachers can edit every important artifact before using it.

## Product Principles

- **Human in the loop:** AI proposes; the teacher decides.
- **Structured workflow:** grading artifacts are stored as data, not as chat transcripts.
- **Editable outputs:** questions, answers, rubric criteria, scores, and feedback remain teacher-editable.
- **Teacher-scoped data:** assignments and grading records are only accessible to their owner.
- **Simple MVP scope:** the system favors a clear end-to-end workflow over production-scale infrastructure.

## Current MVP Scope

### Included

- Teacher registration, login, logout, and session-protected routes
- Assignment creation from text, `.txt`, or `.pdf`
- Manual question editing plus AI-assisted question decomposition
- Reference-answer generation and editing
- Rubric generation and editing
- Manual, file, and CSV submission intake
- AI-assisted answer mapping and grading
- Teacher review of scores and feedback
- Finalization and CSV export

### Deliberately out of scope

- Student accounts or student-facing submission flows
- LMS integrations
- Multi-teacher collaboration
- Advanced analytics
- Background job infrastructure
- Production storage, deployment, and compliance hardening

## System Shape

### Frontend

- React
- TypeScript
- Vite
- Tailwind CSS
- React Router
- TanStack Query

The frontend is organized around the assignment workflow:

- dashboard
- assignment overview
- questions
- reference answers
- rubric
- submissions
- review

### Backend

- Django
- Django REST Framework
- SQLite for the current MVP
- OpenAI API integration
- Pydantic schemas for structured model outputs

The backend is split into three application areas:

- `accounts`: teacher authentication and identity
- `assignments`: assignment source text and question-part setup
- `grading`: generated artifacts, submissions, grading workflow, review, and export

LLM-facing work is kept behind service modules so request handlers stay focused on HTTP concerns and the model provider can be changed later without rewriting the rest of the app.

## Key Design Decisions

### Fixed workflow instead of autonomous agents

Graider uses a predictable grading pipeline rather than giving an agent open-ended control over grading. That keeps the workflow easier to test, easier to review, and easier for teachers t
[truncated — 8526 more characters]
```

### backend/requirements.txt

```
Django==5.2.12
django-cors-headers==4.9.0
djangorestframework==3.17.1
openai==2.29.0
pydantic==2.12.5
pypdf==6.9.2
python-dotenv==1.2.2
reportlab==4.4.10

```

### frontend/package.json

```
{
  "name": "frontend",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "tsc -b && vite build",
    "lint": "eslint .",
    "preview": "vite preview"
  },
  "dependencies": {
    "@tanstack/react-query": "^5.95.2",
    "clsx": "^2.1.1",
    "react": "^18.3.1",
    "react-dom": "^18.3.1",
    "react-router-dom": "^6.30.3"
  },
  "devDependencies": {
    "@eslint/js": "^9.13.0",
    "@types/node": "^25.5.0",
    "@types/react": "^18.3.12",
    "@types/react-dom": "^18.3.1",
    "@vitejs/plugin-react": "^4.3.3",
    "autoprefixer": "^10.4.27",
    "eslint": "^9.13.0",
    "eslint-plugin-react-hooks": "^5.0.0",
    "eslint-plugin-react-refresh": "^0.4.14",
    "globals": "^15.11.0",
    "postcss": "^8.5.8",
    "tailwindcss": "^3.4.17",
    "typescript": "~5.6.2",
    "typescript-eslint": "^8.11.0",
    "vite": "^5.4.10"
  }
}

```

### frontend/src/main.tsx

```typescript
import ReactDOM from 'react-dom/client'
import { RouterProvider } from 'react-router-dom'

import { AppProviders } from './app/providers'
import { router } from './app/router'
import './index.css'

ReactDOM.createRoot(document.getElementById('root')!).render(
  <AppProviders>
    <RouterProvider router={router} />
  </AppProviders>,
)

```

### frontend/postcss.config.js

```javascript
export default {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
}

```

### frontend/tailwind.config.js

```javascript
/** @type {import('tailwindcss').Config} */
export default {
  content: ['./index.html', './src/**/*.{ts,tsx}'],
  theme: {
    extend: {},
  },
  plugins: [],
}

```

### frontend/vite.config.ts

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

export default defineConfig({
  plugins: [react()],
  server: {
    proxy: {
      '/api': {
        target: 'http://127.0.0.1:8000',
        changeOrigin: true,
      },
    },
  },
})

```

### frontend/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>Vite + React + TS</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>

```

### backend/manage.py

```python
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys


def main():
    """Run administrative tasks."""
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
    try:
        from django.core.management import execute_from_command_line
    except ImportError as exc:
        raise ImportError(
            "Couldn't import Django. Are you sure it's installed and "
            "available on your PYTHONPATH environment variable? Did you "
            "forget to activate a virtual environment?"
        ) from exc
    execute_from_command_line(sys.argv)


if __name__ == "__main__":
    main()

```

### frontend/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 tseslint from 'typescript-eslint'

export default tseslint.config(
  { ignores: ['dist'] },
  {
    extends: [js.configs.recommended, ...tseslint.configs.recommended],
    files: ['**/*.{ts,tsx}'],
    languageOptions: {
      ecmaVersion: 2020,
      globals: globals.browser,
    },
    plugins: {
      'react-hooks': reactHooks,
      'react-refresh': reactRefresh,
    },
    rules: {
      ...reactHooks.configs.recommended.rules,
      'react-refresh/only-export-components': [
        'warn',
        { allowConstantExport: true },
      ],
    },
  },
)

```

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