A Next.js App Router API-only service for reading biomechanics data from a Neon Postgres database using Prisma.
- Read-only API service (no database writes)
- Server-to-server API key authentication
- Cursor-based pagination
- Request validation with Zod
- Org-scoped data access
- Secure constant-time API key comparison
- Node.js 18+ and pnpm
- Neon Postgres database with existing data
- Read-only database connection string (recommended)
pnpm installCopy .env.example to .env.local:
cp .env.example .env.localSet the following variables:
DATABASE_URL: Your Neon Postgres connection string (preferably read-only)BIOMECH_API_KEYS: Comma-separated list of valid API keys (e.g.,"key1,key2")
Optional — Octane user lookup: To look up users in the Octane app by email (dashboard "Send payload" page and athlete email → app_db_uuid resolution), set OCTANE_APP_API_URL (Octane app base URL, HTTPS) and OCTANE_API_KEY (Bearer token). Treat the API key like a password: do not commit it or use it in client-side code; keep it in server-side env only.
Important: Prisma 7+ requires the connection URL to be passed to the PrismaClient constructor (not in the schema). The DATABASE_URL environment variable is used automatically.
If you have an existing database schema, pull it into Prisma:
# Make sure DATABASE_URL is set in your .env.local
pnpm prisma db pullThis will populate prisma/schema.prisma with your database structure. Note that prisma db pull reads the connection string from the DATABASE_URL environment variable.
pnpm prisma generateAfter running prisma db pull, update lib/biomech/repo.ts with your actual Prisma model names and field names. The file contains TODO comments indicating where changes are needed.
pnpm devThe API will be available at http://localhost:3000.
GET /api/healthReturns: { ok: true }
No authentication required.
GET /api/biomech/sessions?orgId=<orgId>&athleteId=<athleteId>&limit=50&cursor=<cursor>Query Parameters:
orgId(required): Organization ID for scopingathleteId(optional): Filter by athlete IDlimit(optional): Number of results per page (default: 50, max: 200)cursor(optional): Pagination cursor from previous response
Headers:
X-API-Key: Valid API key
Response:
{
"items": [...],
"nextCursor": "cursor-string-or-null"
}GET /api/biomech/sessions/<sessionId>?orgId=<orgId>Query Parameters:
orgId(required): Organization ID for scoping
Headers:
X-API-Key: Valid API key
Response:
{
"id": "...",
"orgId": "...",
"athleteId": "...",
"createdAt": "...",
...
}curl http://localhost:3000/api/healthcurl -H "X-API-Key: your-api-key-here" \
"http://localhost:3000/api/biomech/sessions?orgId=org123&limit=10"curl -H "X-API-Key: your-api-key-here" \
"http://localhost:3000/api/biomech/sessions/session123?orgId=org123"The service supports multiple API keys via the BIOMECH_API_KEYS environment variable (comma-separated). This enables zero-downtime key rotation:
- Add the new key to
BIOMECH_API_KEYS:"old-key,new-key" - Deploy the service
- Update clients to use the new key
- Remove the old key:
"new-key" - Deploy again
- API keys are validated using constant-time comparison to prevent timing attacks
- Request headers are never logged
- All biomech endpoints require API key authentication
- Org scoping is enforced on all queries
- Input validation is performed with Zod schemas
.
├── app/
│ ├── api/
│ │ ├── health/
│ │ │ └── route.ts
│ │ └── biomech/
│ │ └── sessions/
│ │ ├── route.ts
│ │ └── [sessionId]/
│ │ └── route.ts
│ ├── layout.tsx
│ └── page.tsx
├── lib/
│ ├── auth/
│ │ └── requireApiKey.ts
│ ├── biomech/
│ │ └── repo.ts
│ ├── db/
│ │ └── prisma.ts
│ ├── responses.ts
│ └── validation/
│ └── biomech.ts
├── prisma/
│ └── schema.prisma
├── .env.example
└── README.md
- Git Repository: Push your code to GitHub, GitLab, or Bitbucket
- Vercel Account: Sign up at vercel.com if you haven't already
-
Push Code to Git
git init git add . git commit -m "Initial commit" git remote add origin <your-repo-url> git push -u origin main
-
Import Project to Vercel
- Go to vercel.com/new
- Click "Import Git Repository"
- Select your repository
- Vercel will auto-detect Next.js settings
-
Configure Build Settings
- Framework Preset: Next.js (auto-detected)
- Build Command:
npm run build(orpnpm buildif using pnpm) - Output Directory:
.next(auto-detected) - Install Command:
npm install(orpnpm install)
-
Set Environment Variables In the Vercel project settings, add these environment variables:
-
DATABASE_URL- Value: Your Neon Postgres connection string (read-only recommended)
- Example:
postgresql://user:password@host:5432/database?sslmode=require
-
BIOMECH_API_KEYS- Value: Comma-separated list of API keys
- Example:
prod-key-abc123,prod-key-xyz789 - Important: No spaces after commas
-
-
Deploy
- Click "Deploy"
- Vercel will:
- Install dependencies
- Run
prisma generate(via postinstall script) - Build the Next.js app
- Deploy to production
-
Verify Deployment
- Check the deployment logs for any errors
- Test the health endpoint:
https://your-project.vercel.app/api/health - Test an authenticated endpoint with your API key
To add/update environment variables after deployment:
- Go to your project in Vercel dashboard
- Navigate to Settings → Environment Variables
- Add or edit variables
- Redeploy for changes to take effect
You can also deploy using the Vercel CLI:
# Install Vercel CLI
npm i -g vercel
# Login
vercel login
# Deploy
vercel
# Set environment variables
vercel env add DATABASE_URL
vercel env add BIOMECH_API_KEYS
# Deploy to production
vercel --prodThe project is configured to automatically generate the Prisma client:
postinstallscript runsprisma generateafternpm installbuildscript runsprisma generate && next build
This ensures Prisma client is available during the Vercel build process.
Prisma Client Not Found
- Ensure
prismais indevDependencies(it is) - Check that
prisma/schema.prismaexists and is valid - Verify build logs show
prisma generaterunning
Database Connection Issues
- Verify
DATABASE_URLis set correctly in Vercel - Check that your Neon database allows connections from Vercel's IPs
- Ensure SSL is enabled in the connection string (
?sslmode=require)
API Key Authentication Failing
- Verify
BIOMECH_API_KEYSis set in Vercel - Check for extra spaces in the comma-separated list
- Ensure you're sending the header as
X-API-Key(case-sensitive)
View and explore your database:
pnpm prisma studiopnpm run buildpnpm lint- This is a read-only service. No database writes are performed.
- The repository layer (
lib/biomech/repo.ts) contains placeholder implementations that must be updated after runningprisma db pull. - All API routes return appropriate HTTP status codes (4xx for client errors, 5xx for server errors).