Skip to content

YianXie/path-finder

PathFinder

PathFinder helps SAS high school students discover extracurricular opportunities—from competitions and clubs to internships and tutoring—tailored to their interests, goals, and past engagement.

Table of Contents

Other README files

Overview

  • Personalized discovery: Uses onboarding data, saved items, and LLM-assisted ranking to tailor recommendations.
  • Integrated experience: Google-backed authentication keeps access limited to SAS students and staff.
  • Feedback loop: Ratings, reviews, and saved items feed the recommendation engine.
  • Operations ready: Automated Google Sheet ingestion keeps the catalog current.

Production site

Tech Stack

Backend

  • Python 3.11, Django 5.2+, Django REST Framework 3.16+
  • Async APIs via adrf for personalized recommendations
  • PostgreSQL (prod) and SQLite (local default)
  • Background ingestion via management commands and logging under backend/var/log

Frontend

  • React 19 with Vite 7 for fast DX
  • React Router 7, Material UI 7, Tailwind CSS 4
  • Axios-powered API client with automatic token refresh

Tooling & DevOps

  • Ruff (formatter and linter), isort, Bandit, Safety for Python quality and security
  • ESLint, Prettier, and Tailwind plugins for the frontend
  • Makefile helpers and scripts/ci-local.sh to mirror CI locally

Project Structure

path-finder/
├── backend/                     # Django project
│   ├── accounts/                # Google auth + profile APIs
│   ├── social/                  # Ratings and reviews APIs
│   ├── suggestions/             # Suggestion models, serializers, views
│   │   └── management/commands/ # Data ingestion utilities (Google Sheets, tagging)
│   ├── pathfinder_api/          # Django settings, URLs, ASGI/WSGI config
│   ├── var/log/                 # Import logs (created at runtime)
│   ├── manage.py
│   └── pyproject.toml           # Dependencies managed via uv
├── frontend/                    # React single-page app
│   ├── src/
│   │   ├── components/          # UI primitives, layout, shared widgets
│   │   ├── contexts/            # Auth, snackbar, item detail providers
│   │   ├── hooks/               # Data fetching and UX hooks
│   │   └── pages/               # Route-level screens (Home, Onboarding, Saved, etc.)
│   ├── public/
│   ├── package.json
│   └── vite.config.js
├── scripts/                     # Local CI helper scripts
├── Makefile                     # Common dev commands
├── LICENSE
└── README.md

Getting Started

Prerequisites

  • Python 3.11
  • Node.js 18+ (Node 20 recommended) and npm
  • Google OAuth client configured for the SAS Google Workspace

Backend Setup

Install UV

curl -LsSf https://astral.sh/uv/install.sh | sh
cd path-finder/backend
uv venv
source .venv/bin/activate  # Windows: .venv\Scripts\activate
uv sync
python manage.py migrate
python manage.py runserver

The API listens on http://localhost:8000.

Create backend/.env following the values listed in Environment Variables before running the server.

Frontend Setup

cd path-finder/frontend
npm install
npm run dev

The SPA is served from http://localhost:5173.

Create frontend/.env.local (or .env) with the keys in Environment Variables before starting Vite.

Run Both Apps

Use separate terminals for backend and frontend, or rely on the Makefile:

cd path-finder
make install        # installs backend + frontend deps
make backend-prod   # optional: run backend with gunicorn

For routine development, run python manage.py runserver (from backend/) and npm run dev (from frontend/) concurrently.

Environment Variables

Create a .env file in backend/:

ENVIRONMENT=""  # the environment where your backend is running, for local development, use 'development'
SECRET_KEY=""  # your Django secret_key, can be re-generated if needed
ALLOWED_HOSTS=""  # your domain (without https:// or http://)
CORS_ALLOWED_ORIGINS=""  # your domain (with https:// or http://)
CSRF_TRUSTED_ORIGINS=""  # your domain (with https:// or http://)
DATABASE_URL=""  # the url to access your PostgreSQL database

CLOUDINARY_CLOUD_NAME=""  # Your Cloudinary Cloud Name, can be found on the Cloudinary website
CLOUDINARY_API_KEY=""  # Your Cloudinary API Key, can be found on the Cloudinary website
CLOUDINARY_API_SECRET=""  # Your Cloudinary API Secret, can be found on the Cloudinary website

GOOGLE_CLIENT_ID=""  # your Google Client ID for google login (should match with frontend)
ALLOWED_GOOGLE_HD=""  # (optional) only allow specific email address domain to login (e.g., your-company.com)
SHEET_ID=""  # the Google Spreadsheet ID, can be found in the url of the sheet, sheet must be set to publicly visible

OPENAI_API_KEY=""  # your OpenAI API Key, can be found on the OpenAI website

Create a .env file in frontend/:

VITE_ENVIRONMENT=""  # the environment (default is 'development')
VITE_API_URL=""  # the url where you backend (Django Rest Framework) runs
VITE_GOOGLE_CLIENT_ID=""  # your Google Client's ID (should match with backend)

The backend falls back to SQLite when ENVIRONMENT=development. Provide DATABASE_URL for production or local Postgres.

Developer Tooling

Makefile Commands

  • make install – install backend and frontend dependencies
  • make lint – run Ruff and frontend ESLint checks
  • make format – apply Ruff format, isort, and Prettier
  • make security – run Safety and Bandit plus npm audit
  • make test – execute Django test suite
  • make ci-local – replicate CI pipeline locally (scripts/ci-local.sh)
  • make clean – prune caches and build artifacts

Management Commands

Run from backend/ with the virtual environment activated:

  • python manage.py sync_sheet – ingest the latest opportunities from the configured Google Sheet (SHEET_ID)
  • python manage.py add_missing_tags – backfill tags with help from the LLM
  • python manage.py collectstatic – prepare static assets for production deployments

Log files for ingestion live under backend/var/log/.

API Surface

Suggestions

  • GET /api/suggestions/health/ – service health check
  • GET /api/suggestions/suggestions/ – paginated list of all opportunities (public)
  • GET /api/suggestions/suggestions/<external_id>/ – opportunity detail (public)
  • GET /api/suggestions/personalized-suggestions/ – personalized feed (auth, async)
  • GET /api/suggestions/suggestions-with-saved-status/<external_id>/ – detail including saved flag (auth)

Accounts

  • POST /accounts/google/ – sign-in/up with Google OAuth credential
  • POST /accounts/parse-token/ – decode an arbitrary JWT (debugging utility)
  • GET /accounts/profile/ – retrieve enriched profile data (auth)
  • POST /accounts/save-item/ – toggle saved items (auth)
  • POST /accounts/check-item-saved/ – check saved state (auth)
  • POST /accounts/saved-items/ – list saved opportunities (auth)
  • POST /accounts/update-user-information/ – persist onboarding data (auth)

Social

  • POST /api/social/rate/ – create or update a rating/comment for an opportunity (auth)
  • GET /api/social/reviews/?external_id=<id> – fetch reviews for an opportunity (public)
  • GET /api/social/user-review/ – get the current user's review for an opportunity (auth)

Auth

  • POST /api/token/ – obtain access + refresh tokens (username/password flow)
  • POST /api/token/refresh/ – refresh an access token

Current Features

  • Google-based authentication restricted to SAS email domains
  • Guided onboarding that captures interests, goals, and basic profile data
  • LLM-assisted personalized recommendations with caching for repeat requests
  • Saved items dashboard with optimistic UI updates
  • Ratings and written reviews for each opportunity
  • Light/dark theme toggle and responsive layout

Support

Questions or issues? Email yianxie52@gmail.com or open a GitHub Issue on this repository.

License

This project is licensed under the MIT License. See LICENSE for details.

About

Help SAS students to select better activities based on their interests

Topics

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 3

  •  
  •  
  •