Helm is your personal academic command center that puts you in control of your time, coursework, and energy.
| Layer | Technology |
|---|---|
| Frontend | React 19, TanStack Start, Vite, Tailwind CSS |
| Backend | FastAPI, SQLAlchemy 2.0, Pydantic |
| Database | PostgreSQL (Neon for production) |
| Auth | Google OAuth + JWT |
| Service | Platform | URL |
|---|---|---|
| Frontend | Vercel | https://helm-bice.vercel.app |
| Backend | Render | https://helm-api-ynxq.onrender.com |
| Database | Neon | (connection string in Render env vars) |
- Node.js 18+
- Python 3.11+
- pnpm
- uv (Python package manager)
- Docker (for local PostgreSQL)
cd backend
# Start PostgreSQL
docker-compose up -d
# Install dependencies
uv sync
# Run migrations
uv run alembic upgrade head
# Start server
uv run uvicorn app.main:app --reload --port 8000cd frontend
# Install dependencies
pnpm install
# Start dev server
pnpm devBackend (backend/.env):
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_USER=helm
POSTGRES_PASSWORD=helm_dev_password
POSTGRES_DB=helm
JWT_SECRET_KEY=<generate with: openssl rand -hex 32>
GOOGLE_CLIENT_ID=<your-google-client-id>.apps.googleusercontent.com
ENVIRONMENT=development
DEBUG=true
CORS_ORIGINS=["http://localhost:3000"]Frontend (frontend/.env):
VITE_API_URL=http://localhost:8000
VITE_GOOGLE_CLIENT_ID=<your-google-client-id>.apps.googleusercontent.com- Create account at neon.tech
- Create a new project
- Copy the connection string (looks like
postgresql://user:pass@ep-xxx.region.aws.neon.tech/neondb?sslmode=require)
-
Create account at render.com
-
New → Web Service → Connect your GitHub repo
-
Configure:
- Root Directory:
backend - Build Command:
pip install uv && uv sync - Start Command:
uv run uvicorn app.main:app --host 0.0.0.0 --port $PORT
- Root Directory:
-
Set environment variables:
| Variable | Value |
|---|---|
DATABASE_URL_OVERRIDE |
Your Neon connection string |
JWT_SECRET_KEY |
Generate with openssl rand -hex 32 |
GOOGLE_CLIENT_ID |
Your Google OAuth client ID |
ENVIRONMENT |
production |
DEBUG |
false |
CORS_ORIGINS |
["https://helm-bice.vercel.app"] |
COOKIE_CROSS_DOMAIN |
true |
-
Create account at vercel.com
-
Import your GitHub repo
-
Configure:
- Root Directory:
frontend - Framework Preset: Vite
- Root Directory:
-
Set environment variables:
| Variable | Value |
|---|---|
VITE_API_URL |
https://helm-api-ynxq.onrender.com |
VITE_GOOGLE_CLIENT_ID |
Your Google OAuth client ID |
- Go to Google Cloud Console
- Create OAuth 2.0 Client ID
- Add to Authorized JavaScript origins:
http://localhost:3000(dev)https://helm-bice.vercel.app(prod)
- Add to Authorized redirect URIs:
http://localhost:3000(dev)https://helm-bice.vercel.app(prod)
- Verify
CORS_ORIGINSon Render includes your exact Vercel URL withhttps:// - No trailing slash
- Must be a JSON array:
["https://your-app.vercel.app"]
- Check Render logs for actual error
- Verify
GOOGLE_CLIENT_IDmatches on both Vercel and Render - Verify
JWT_SECRET_KEYis set on Render - Auth uses localStorage token as fallback for mobile browsers that block cross-site cookies
- Neon connection string must include
?sslmode=require - Variable name must be
DATABASE_URL_OVERRIDE(notDATABASE_URL) - Don't wrap value in quotes in Render UI
- Cross-site cookies are blocked by default on iOS Safari
- The app uses localStorage + Authorization header as fallback
- If login redirects back to login page, check browser console for errors
- Free tier sleeps after 15 min of inactivity
- First request takes ~30 seconds
- Upgrade to paid tier ($7/mo) for always-on
# Option 1: Local with Neon connection
cd backend
# Set DATABASE_URL_OVERRIDE in .env to Neon connection string
uv run alembic upgrade head
# Option 2: Render Shell
# Go to Render dashboard → your service → Shell
uv run alembic upgrade head| Endpoint | Method | Description |
|---|---|---|
/health |
GET | Health check |
/auth/google |
POST | Google OAuth login |
/auth/logout |
POST | Logout |
/auth/me |
GET | Get current user |
/classes |
GET/POST | List/create classes |
/classes/{id} |
GET/PATCH/DELETE | Class operations |
/assignments |
GET/POST | List/create assignments |
/notes |
GET/POST | List/create notes |
/transactions |
GET/POST | List/create transactions |
helm/
├── backend/
│ ├── app/
│ │ ├── api/routes/ # API endpoints
│ │ ├── db/ # Database models & session
│ │ ├── schemas/ # Pydantic schemas
│ │ ├── config.py # Settings
│ │ └── main.py # FastAPI app
│ ├── alembic/ # Database migrations
│ └── pyproject.toml
├── frontend/
│ ├── src/
│ │ ├── components/ # React components
│ │ ├── lib/ # API client, auth, utils
│ │ └── routes/ # TanStack Router pages
│ └── package.json
└── README.md