Development Workflow
Learn the day-to-day commands, QA expectations, and collaboration practices for Raypx.
Environment Setup
Initial Setup
-
Install dependencies
pnpm install -
Configure environment variables
cp .env.example .envEdit
.envwith required values:DATABASE_URL- PostgreSQL connection stringBETTER_AUTH_SECRET- Min 32 characters for auth encryptionBETTER_AUTH_URL- Your app URL (http://localhost:3000 for dev)- Optional: Redis, OAuth, Analytics, AI services (137+ env vars available)
-
Setup database
pnpm --filter @raypx/db run db:migrate -
Start development
pnpm dev # All apps (web + docs) # or pnpm --filter web dev # Just web app
Environment Variables
The project uses type-safe environment variables via @raypx/env:
- Validation: All env vars validated with Zod schemas
- Organization: Grouped by category (app, feature flags, database, auth, etc.)
- Type safety: Full TypeScript support in code
- Examples: See
.env.examplefor all 137+ available variables
Common Scripts
| Command | Description |
|---|---|
pnpm dev | Start all apps (web + docs) with hot reload |
pnpm --filter web dev | Just the TanStack Start web app |
pnpm --filter docs dev | Just the Fumadocs documentation site |
pnpm --filter email dev | Email template preview server |
pnpm build | Production build of all apps (validates everything) |
pnpm typecheck | TypeScript validation across workspace |
pnpm check | Biome linting and formatting check |
pnpm format | Auto-format all code with Biome |
pnpm test | Run Vitest unit tests |
pnpm coverage | Generate HTML coverage reports |
pnpm clean | Remove build artifacts and caches |
pnpm --filter @raypx/db run db:studio | Open Drizzle Studio (database GUI) |
pnpm --filter @raypx/db run db:migrate | Run database migrations |
pnpm --filter @raypx/db run db:generate | Generate new migration from schema changes |
pnpm shadcn | Add shadcn/ui components to @raypx/ui |
Coding Standards
TypeScript
- Strict mode enabled: All projects use strict TypeScript settings
- Explicit types: Prefer explicit return types in shared packages
- Type over interface: Use
typeoverinterfacefor consistency - Avoid
any: Useunknowninstead and narrow with type guards
Code Style
- Formatting: Biome handles all formatting (replaces Prettier)
- Linting: Biome enforces code quality rules (replaces ESLint)
- Pre-commit hooks: Lefthook runs
pnpm formatbefore commits - Variable names: Use clear, descriptive names over short abbreviations
Project Structure
- Tests: Co-locate tests next to modules (
*.test.ts[x]) or in__tests__/ - Routes: TanStack Start file-based routing in
apps/web/src/routes/ - Components: React components in
apps/web/src/components/ - No build for packages: All packages consumed as TypeScript source
Git Practices
Commit Convention
Follow Conventional Commits format:
<type>(<scope>): <description>
[optional body]Types: feat, fix, docs, refactor, perf, test, chore, ci
Examples:
git commit -m "feat(auth): add OAuth providers"
git commit -m "fix(ui): resolve button hover state"
git commit -m "docs: update environment setup guide"
git commit -m "feat(web,auth): add login flow"Pre-push Checklist
Always run before pushing:
pnpm typecheck # TypeScript validation
pnpm check # Linting
pnpm test # Unit tests
pnpm build # Verify production buildBuild time is only 10-15 seconds, so always build before commits.
Branch Strategy
- Work on feature branches (
feature/add-oauth) - Avoid force-pushing shared branches
- Use
git push --force-with-leaseif necessary (coordinate with team)
Testing
Current State
⚠️ Testing is a critical gap (15% coverage):
- ✅ Vitest framework configured
- ✅ CI runs tests automatically
- ❌ Minimal test coverage
- ❌ No E2E tests
Testing Guidelines
When adding tests:
-
Unit tests: Test business logic and utilities
// packages/shared/__tests__/utils.test.ts import { describe, it, expect } from 'vitest' import { yourFunction } from '../utils' describe('yourFunction', () => { it('should handle valid input', () => { expect(yourFunction('test')).toBe('expected') }) }) -
Integration tests: Test API endpoints, database operations
-
E2E tests: Use Playwright (to be implemented)
Running Tests
pnpm test # All tests
pnpm test --watch # Watch mode
pnpm coverage # Generate coverage reportCoverage reports are uploaded to Codecov in CI.
Database Development
Workflow
- Modify schema in
packages/db/src/schemas/ - Generate migration:
pnpm --filter @raypx/db run db:generate - Review migration in
packages/db/drizzle/ - Apply migration:
pnpm --filter @raypx/db run db:migrate - Verify in Drizzle Studio:
pnpm --filter @raypx/db run db:studio
Database Tips
- Use Drizzle's type-safe query builder
- Leverage PostgreSQL features (JSONB, arrays, etc.)
- Add indexes for frequently queried columns
- Use migrations for all schema changes (never manual ALTER TABLE)
📘 Production Setup: See Database Hosting Guide for setting up PostgreSQL in production environments (Neon, Supabase, Railway, etc.)
Working with Documentation
- Documentation lives in
apps/docs/content/docs/ - Write documentation in MDX format (Markdown + JSX)
- Run
pnpm --filter docs devto preview docs at http://localhost:3001 - Fumadocs auto-generates navigation from file structure and frontmatter
Troubleshooting
Build Issues
# Clear all caches and rebuild
pnpm clean
rm -rf node_modules .turbo
pnpm install
pnpm buildTypeScript Errors
- Restart TypeScript server (VS Code: Cmd+Shift+P → "Restart TS Server")
- Clear TypeScript cache:
rm -rf tsconfig.tsbuildinfo - Reinstall dependencies:
pnpm install
Common Errors
- "Cannot find module '@raypx/...'" → Run
pnpm install - "Port 3000 in use" → Kill process:
lsof -ti:3000 | xargs kill -9 - "Type error in node_modules" → Delete
node_modulesand reinstall - Biome errors → Run
pnpm formatto auto-fix
Getting Help
Last updated on
