Development Workflow
Task Runner (Justfile)
A root-level Justfile provides a single entry point for all workflows. Run just --list to see all available recipes.
Services
just up # Start all services (db, server, mobile)
just down # Stop all services
just server # Start Django server (with db only)
just mobile # Start Expo / Metro bundler only
just logs [service] # Tail logs (optionally for a specific service)
just build # Rebuild Docker images
Testing
just test # Run all tests (server + mobile)
just test-server # Server tests (supports args: just test-server -k "test_auth")
just test-mobile # Mobile tests only
just check # Full lint + type-check + tests
Linting
just lint # ESLint on mobile client
just type-check # TypeScript type-check on mobile client
Database
just migrate # Run Django migrations (supports args: just migrate users)
just makemigrations # Create Django migrations
just seed # Seed default categories
just db-generate # Generate Drizzle ORM migrations for mobile
just manage <cmd> # Django manage.py passthrough
just reset-db # Drop db volume, re-migrate, re-seed
Shell Access
just shell-server # Bash shell in server container
just shell-mobile # Shell in mobile container
Documentation
just docs-dev # Start docs dev server (localhost:3000)
just docs-build # Build docs for production
just docs-serve # Serve production build locally
just docs-gen-api # Generate API reference from OpenAPI schema
Git Workflow
Conventional Commits
Commits are enforced by commitlint via a Husky commit-msg hook:
feat: add budget notifications
fix: correct token refresh race condition
chore: update dependencies
refactor: extract sync encryption module
test: add receipt upload tests
docs: update API reference
perf: memoize transaction list items
style: format with prettier
Rules:
- Lowercase subject
- Maximum 100 characters
- No period at the end
Pre-commit Hooks
Husky runs lint-staged on pre-commit, which checks:
- ESLint on staged
.ts/.tsxfiles - TypeScript type-checking
Development Tips
- Use
just checkbefore pushing to run the full lint + type-check + test suite - The mobile client's ESLint config enforces a max of 70 lines per function -- extract sub-components or hooks when functions grow
- All API calls go through the
src/api/layer with Axios interceptors for JWT handling - Database changes require running
pnpm db:generatein the mobile client to create Drizzle migrations