Development Guide¶
This guide covers setting up your development environment and working with the Metricis codebase.
Prerequisites¶
- Node.js 24.16.0 from
.nvmrc(for client, portal, patient portal, landing, and Capacitor tooling) - Python 3.11+ (for server)
- PostgreSQL 15+ (for database)
- Redis 5.0+ (for session storage and Celery)
- Git (for version control)
Initial Setup¶
1. Clone the Repository¶
2. Install Dependencies¶
Frontend Dependencies¶
Backend Dependencies¶
cd server
python -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
pip install -r requirements.txt
3. Database Setup¶
Create a PostgreSQL database:
Set up environment variables in server/.env:
DATABASE_URL=postgresql+asyncpg://user:pass@localhost:5432/metricis
JWT_SECRET_KEY=$(python -c "import secrets; print(secrets.token_urlsafe(32))")
SESSION_SECRET_KEY=$(python -c "import secrets; print(secrets.token_urlsafe(32))")
Run migrations:
4. Redis Setup¶
Install and start Redis:
# macOS
brew install redis
brew services start redis
# Linux
sudo apt-get install redis-server
sudo systemctl start redis
Configure Redis in server/.env:
Development Servers¶
Start All Services¶
This starts: - Client: http://localhost:5173 (jsPsych assessment interface) - Portal: http://localhost:3000 (researcher admin portal) - Patient Portal: http://localhost:3001 (patient/caregiver interface) - Server: http://localhost:8030 (FastAPI backend)
Start Services Individually¶
# Client only
npm run dev:client
# Portal only
npm run dev:portal
# Patient Portal only
npm run dev:patient-portal
# Server only
npm run dev:server
# Client + Server (original dev command)
npm run dev
Verification Source of Truth¶
Local verification is the authoritative development gate for now. GitHub Actions may still run on pushes and PRs, but remote CI is advisory until the project explicitly switches back to remote CI as the deployment gate closer to release.
For each change, choose the smallest local command set that covers the touched surface and record the commands/results in the handoff:
| Change surface | Local verification |
|---|---|
| Client, portal, patient portal, or landing | npm run lint:all, npm run typecheck:all, targeted workspace tests, and affected workspace build |
| Server API, models, services, or migrations | cd server && source .venv/bin/activate, then targeted pytest, ruff check app tests, and alembic upgrade head when migrations change |
| Docs | python3 -m mkdocs build --strict --site-dir /private/tmp/metricis-docs |
| Capacitor/mobile | npm run cap:sync:android, npm run cap:sync:ios, affected web build, and native Gradle/Xcode build when platform files change |
| Release packaging | Local Fastlane/native dry runs first; GitHub release workflow becomes authoritative only for deployment/release-candidate work |
Do not block ongoing development solely on a remote GitHub Actions failure unless the failure reproduces locally or the current milestone is explicitly a release/deployment milestone.
Background Workers¶
For reminder notifications and background tasks:
# In a separate terminal
cd server
source .venv/bin/activate
# Start Celery worker
celery -A app.celery_app worker -Q reminders -l info
# Start Celery beat (periodic tasks)
celery -A app.celery_app beat -l info
Project Structure¶
metricis/
├── client/ # jsPsych assessment frontend (TypeScript + Vite)
├── portal/ # Researcher admin portal (React 18)
├── patient-portal/ # Patient/caregiver portal (React 18)
├── server/ # FastAPI backend (Python 3.11+)
├── docs/ # Documentation (MkDocs)
├── e2e/ # Playwright E2E tests
└── scripts/ # Utility scripts (screenshot capture, etc.)
Common Development Tasks¶
Database Migrations¶
Create a new migration:
Apply migrations:
Rollback one migration:
Running Tests¶
# Server tests (pytest)
cd server
source .venv/bin/activate
pytest tests/ -v
# Portal tests (Vitest)
cd portal
npm run test
# Patient Portal tests (Vitest)
cd patient-portal
npm run test
# E2E tests (Playwright - requires dev servers running)
npm run test:e2e
npm run test:e2e:ui # With Playwright UI
npm run test:e2e:headed # With browser visible
Linting¶
# Client
cd client && npm run lint
# Portal
cd portal && npm run lint
# Server
cd server && ruff check app/
Building for Production¶
# All web frontends
npm run build:all
# Individual apps
npm run build
npm run build:portal
npm run build:patient-portal
npm run build:landing
Capacitor 8 Native Builds¶
# Sync native projects
npm run cap:sync
npm run cap:sync:android
npm run cap:sync:ios
# Run or open native projects
npm run cap:run:android -- --list
npm run cap:run:ios -- --list
npm run cap:open:android
npm run cap:open:ios
# Validate native build paths
npm run build:android --workspace=client
npm run build:ios --workspace=client
Android native builds use Java 21, Android SDK 36, Android Gradle Plugin 8.13.0, and Gradle 8.14.3. Release packaging and store uploads are documented in Release Automation and Mobile Deployment.
Code Style and Conventions¶
Naming Conventions¶
| Context | Convention | Examples |
|---|---|---|
| TypeScript files | kebab-case | simple-rt.ts, digit-span.ts |
| TypeScript variables/functions | camelCase | sessionId, createTimeline() |
| TypeScript interfaces/types | PascalCase | SessionConfig, SimpleRTSummary |
| TypeScript constants | UPPER_SNAKE_CASE | API_BASE_URL, TASK_CONFIG |
| Python files | snake_case | session_store.py |
| Python variables/functions | snake_case | session_id, get_session() |
| Python classes | PascalCase | SessionStore, REDCapService |
| API paths | kebab-case | /api/session/start |
| API request/response fields | snake_case | session_id, task_summaries |
Git Workflow¶
-
Create a feature branch:
-
Make your changes and commit:
-
Push and create a pull request:
Commit Message Format¶
Use conventional commits:
feat:- New featurefix:- Bug fixdocs:- Documentation changesrefactor:- Code refactoringtest:- Test additions or changeschore:- Build process or tooling changes
Environment Variables¶
Required for Development¶
Server (.env)¶
# Database
DATABASE_URL=postgresql+asyncpg://localhost:5432/metricis
# Security (generate with: python -c "import secrets; print(secrets.token_urlsafe(32))")
JWT_SECRET_KEY=your-secret-key
SESSION_SECRET_KEY=your-session-secret
# Redis
SESSION_STORAGE_BACKEND=redis
REDIS_URL=redis://localhost:6379/0
# Local API port used by root npm scripts
API_PORT=8030
# CORS
ALLOWED_ORIGINS=http://localhost:5173,http://localhost:3000,http://localhost:3001
# Rate Limiting
RATE_LIMIT_PER_MINUTE=60
AUTH_RATE_LIMIT_PER_MINUTE=10
Client (.env.local)¶
# API URL
VITE_API_URL=http://localhost:8030/api
# For mobile development (use your Mac's IP)
VITE_NATIVE_API_URL=http://192.168.1.xxx:8030/api
Troubleshooting¶
Port Already in Use¶
If you get "port already in use" errors:
# Find process using port 5173 (or 3000, 3001, 8030)
lsof -ti:5173
# Kill the process
kill -9 $(lsof -ti:5173)
Database Connection Issues¶
-
Verify PostgreSQL is running:
-
Check database exists:
-
Verify connection string in
server/.env
Redis Connection Issues¶
-
Verify Redis is running:
-
Check Redis URL in
server/.env
Import Errors in Python¶
Make sure you're in the virtual environment:
Next Steps¶
- Testing Guide - Learn about testing practices
- Deployment Guide - Deploy to production
- Mobile Deployment - Build for iOS/Android
- API Reference - API documentation