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.
- Overview
- Tech Stack
- Project Structure
- Getting Started
- Environment Variables
- Developer Tooling
- API Surface
- Current Features
- Support
- License
- 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.
Backend
- Python 3.11, Django 5.2+, Django REST Framework 3.16+
- Async APIs via
adrffor 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.shto mirror CI locally
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
- Python 3.11
- Node.js 18+ (Node 20 recommended) and npm
- Google OAuth client configured for the SAS Google Workspace
Install UV
curl -LsSf https://astral.sh/uv/install.sh | shcd path-finder/backend
uv venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
uv sync
python manage.py migrate
python manage.py runserverThe API listens on http://localhost:8000.
Create backend/.env following the values listed in Environment Variables before running the server.
cd path-finder/frontend
npm install
npm run devThe SPA is served from http://localhost:5173.
Create frontend/.env.local (or .env) with the keys in Environment Variables before starting Vite.
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 gunicornFor routine development, run python manage.py runserver (from backend/) and npm run dev (from frontend/) concurrently.
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 websiteCreate 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. ProvideDATABASE_URLfor production or local Postgres.
make install– install backend and frontend dependenciesmake lint– run Ruff and frontend ESLint checksmake format– apply Ruff format, isort, and Prettiermake security– run Safety and Bandit plusnpm auditmake test– execute Django test suitemake ci-local– replicate CI pipeline locally (scripts/ci-local.sh)make clean– prune caches and build artifacts
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 LLMpython manage.py collectstatic– prepare static assets for production deployments
Log files for ingestion live under backend/var/log/.
GET /api/suggestions/health/– service health checkGET /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)
POST /accounts/google/– sign-in/up with Google OAuth credentialPOST /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)
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)
POST /api/token/– obtain access + refresh tokens (username/password flow)POST /api/token/refresh/– refresh an access token
- 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
Questions or issues? Email yianxie52@gmail.com or open a GitHub Issue on this repository.
This project is licensed under the MIT License. See LICENSE for details.