Skip to content

bshashank07/StudySync

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

40 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

hooHacks2026

Repo for HooHacks 2026.

Deploy (Vercel + API)

See DEPLOY.md for deploying the frontend/ app on Vercel and wiring env vars, CORS, and Firebase.

Backend setup

Working directory: Run backend commands with your shell’s current directory set to backend/ (the folder that contains requirements.txt and the app/ package). If you run uvicorn from the repo root, Python will not find the app module—cd backend first.

Option A — automated (recommended)

From the project root:

cd backend
bash setup_backend.sh

This creates backend/.venv and installs pinned dependencies from requirements.txt.

Option B — manual venv + install

From the project root:

cd backend
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

To activate the virtual environment later in a new terminal:

cd backend
source .venv/bin/activate

Run the API server (with auto-reload)

With the venv activated and current directory backend/:

uvicorn app.main:app --reload --host 127.0.0.1 --port 8000

Then open http://127.0.0.1:8000/health in a browser or use the interactive docs at http://127.0.0.1:8000/docs.

Database (SQLite)

StudySync stores imports under backend/studysync.db (SQLite file; gitignored). Tables are created automatically on API startup (create_all). To use a different database (e.g. in tests), set:

export STUDYSYNC_DATABASE_URL="sqlite:////absolute/path/to/file.db"

Stop the server before deleting studysync.db if you want a clean reset (avoid file locks).

CORS (frontend dev)

Browsers allow your Vite/Next dev app to call this API when its origin is listed. Defaults: http://localhost:5173, http://localhost:3000. Override with a comma-separated list:

export STUDYSYNC_CORS_ORIGINS="http://localhost:5173,http://localhost:3000,http://127.0.0.1:5173"

Environment variables (.env)

  1. Copy .env.example to .env. Never commit .env — it is gitignored.
  2. Put .env in either place (both are loaded): the repository root (next to README.md) or backend/.env (next to requirements.txt). If the key was only in backend/.env before, it was previously ignored — that is fixed now.
  3. Set GOOGLE_API_KEY for the Gemini developer API, or GEMINI_API_KEY (same value; both names work).
  4. Restart Uvicorn after changing .env (env is loaded at app startup).

Optional: STUDYSYNC_GEMINI_MODEL (default gemini-2.0-flash).

Firebase authentication — backend (Part B)

The API verifies Firebase ID tokens only; profile rows live in SQLite (see Phase 2 — user profiles below). Configure the Admin SDK with one of:

Variable Purpose
GOOGLE_APPLICATION_CREDENTIALS Absolute path to the service account JSON (Firebase Console → Project settings → Service accounts → Generate new private key).
STUDYSYNC_FIREBASE_CREDENTIALS_JSON The same JSON pasted as a single-line string (useful when a file path is awkward).

If neither is set, the app still starts; protected routes respond with 503 until you add credentials. Store local keys under e.g. backend/secrets/ (gitignored).

  • GET /auth/me — requires header Authorization: Bearer <Firebase ID token>. Returns JSON including uid and email from verified claims. Missing/invalid token → 401; Firebase not initialized → 503.

See backend/.env.example for copy-paste names.

Phase 2 — user profiles (SQLite)

Environment: Same as Part B (no new env vars). The users table is created on startup with the rest of the schema.

Clients must send Authorization: Bearer <Firebase ID token> on profile routes.

Method Path Description
GET /users/me Returns the signed-in user’s SQLite profile: internal id, firebase_uid, email, display_name, college, canvas_ics_url, created_at, updated_at. On each call, the server upserts the row for claims["uid"] and refreshes email when the token includes it.
PATCH /users/me JSON body with any of display_name, college, canvas_ics_url (all optional). Omitted fields are unchanged; send null to clear a nullable field. canvas_ics_url is validated with the same rules as POST /import-canvas-ics (invalid URL → 422).

Auth errors match Part B (401 / 503). Passwords are not stored; Firebase remains auth-only.

AI study plan (Gemini)

POST /sessions/{session_id}/ai-plan loads all assignments and courses for that session, computes same-day “load” in your planning window (using the same date precedence as elsewhere: personal_targetofficial_dueofficial_startofficial_end), and asks Gemini for a structured JSON plan. The response is suggestions only — nothing is written to the DB (use existing PATCH routes to apply your own changes).

Request JSON:

  • window_start, window_end — ISO dates (YYYY-MM-DD). End must be ≥ start (422 if not).
  • user_goal (optional) — short free text (availability, finals focus, etc.).

Response JSON: summary, suggestions (list), warnings (list; may include overload / missing-date notes), truncated_input (true when more than 80 assignments were trimmed for the prompt).

Without a configured API key (GOOGLE_API_KEY or GEMINI_API_KEY), the endpoint returns 503 with a clear message (no stack trace).

Try in /docs: expand POST /sessions/{session_id}/ai-plan, paste a real session_id from an import, body e.g. {"window_start":"2025-01-06","window_end":"2025-01-12","user_goal":"Study after 5pm weekdays"}.

curl example (set SID after an import):

curl -s -X POST "http://127.0.0.1:8000/sessions/$SID/ai-plan" \
  -H "Content-Type: application/json" \
  -d '{"window_start":"2025-01-06","window_end":"2025-01-12","user_goal":"Light week — prioritize high-priority courses"}' | jq .

Import a Canvas (or any) ICS feed

POST /import-canvas-ics accepts JSON { "ics_url": "..." }, persists a new session plus courses and assignments, and returns:

  • session_id — use this for later GET/PATCH routes.
  • count_assignments, count_courses — rows created for this import.
  • count and events — same shape as before (immediate preview for the UI). Duplicate ICS UIDs in one feed are deduped (first wins). Optional query params date_from / date_to (ISO dates) still filter before persistence.

Course dedupe rule: Within a session, one Course row per inferred name (case-insensitive). We infer from, in order: first iCal CATEGORIES entry; else a [CODE] prefix in SUMMARY; else text after an em dash in SUMMARY; else a shared bucket Uncategorized.

Example: import → read session_id from JSON (here shown with jq):

RESP=$(curl -s -X POST "http://127.0.0.1:8000/import-canvas-ics" \
  -H "Content-Type: application/json" \
  -d '{"ics_url":"https://example.com/calendar.ics"}')
echo "$RESP" | jq .
SID=$(echo "$RESP" | jq -r .session_id)

curl -s "http://127.0.0.1:8000/sessions/$SID/assignments" | jq .
curl -s "http://127.0.0.1:8000/sessions/$SID/courses" | jq .

# Update personal study target and notes (replace ASSIGNMENT_UUID from assignments list)
curl -s -X PATCH "http://127.0.0.1:8000/sessions/$SID/assignments/ASSIGNMENT_UUID" \
  -H "Content-Type: application/json" \
  -d '{"personal_target":"2025-06-10T18:00:00Z","notes":"Review chapter 3"}' | jq .

# Optional: download merged personal calendar (personal_target if set, else official due/start)
curl -s "http://127.0.0.1:8000/sessions/$SID/calendar.ics" -o studysync.ics

Assignment date filter: GET .../assignments?date_from=&date_to= uses, per row, the first available of personal_target, official_due, official_start, official_end (calendar day, inclusive). Rows with none of these are omitted when either query param is set.

Fetching: The server uses requests with a 10s connect / 30s read timeout so a dead host fails quickly while a slow but valid download can still finish. Errors: invalid URL → 422; bad iCal body → 400; upstream non-2xx → 502; timeout → 504.

Response time fields: Timed events use UTC ISO 8601 with a Z suffix (YYYY-MM-DDTHH:MM:SSZ). All-day events use a date-only string (YYYY-MM-DD) with no timezone, per iCalendar DATE semantics. description is capped at 8,000 characters to keep payloads bounded (full text in feed may be longer).

Frontend setup

Run this from the project root:

cd frontend
npm install

Copy frontend/.env.example to frontend/.env and set VITE_STUDYSYNC_API_URL (FastAPI base, e.g. http://127.0.0.1:8000) plus Firebase Web App keys from the Firebase Console (VITE_FIREBASE_API_KEY, VITE_FIREBASE_AUTH_DOMAIN, VITE_FIREBASE_PROJECT_ID, etc.). Restart Vite after changes.

The UI uses Firebase Auth (email/password) for sign-in; the app sends Authorization: Bearer <Firebase ID token> on API calls. Profile data comes from GET/PATCH /users/me (SQLite). Passwords never go to FastAPI. ICS import (POST /import-canvas-ics) does not require auth on the backend. Manual check: sign up → open Settings and save display name / college / Canvas URL → import calendar (modal or /onboarding) → confirm requests in DevTools include Authorization on /users/me and session routes.

Start the frontend dev server:

npm run dev

Run this to confirm the verions

node checkVersions.js

Optional useful commands (no need now)

npm run build
npm run preview

About

HooHacks 2026

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors