Copy the template and populate the environment variables:
cp config/env/.env.example config/env/.envInstall the required utilities using brew:
docker(container runtime)watchexec(file watcher for API regeneration)gnu-getopt(for parsing GNU-style flags)uv(Python dependency manager)pnpm(JavaScript package manager)zizmor(GitHub Actions workflow linter used by the pre-commit hook)
./scripts/dev.sh orchestrates infrastructure + optional client/server processes. By default it:
- verifies the
.envfile exists underconfig/env - installs backend dependencies via
uv syncand frontend dependencies viapnpm i - runs
watchexeconserver/appto regenerate the OpenAPI spec + client whenever Python files change - starts Docker Compose for the required infrastructure services while watching for termination
Options you can pass:
--skip-install-deps– skipuv sync/pnpm i(useful when dependencies already installed)--mode docker(default) – run client and server containers along with infrastructure services--mode local– only runs infrastructure containers, but runsmake devandpnpm run devdirectly on your host--mode noneor-n– only runs infrastructure containers (no client/server)
For example, to keep your host client/server running directly while still using the infra containers:
./scripts/dev.sh --mode localdev.sh traps SIGINT/TERM and tears down running compose, watchexec, and local processes automatically.
scripts/generate_api.sh dumps the FastAPI OpenAPI spec, copies it to config/openapi_spec.json, and runs pnpm run generate-api in client. It skips client generation when the spec is unchanged unless you force it.
./scripts/generate_api.sh # regenerate when FastAPI changes
./scripts/generate_api.sh -f # force regeneration even if the spec already matchesUse act to run workflows locally for quick validation.
List all workflows:
act -lRun a specific job:
act -j {job-id}shadcn adds components under client/src/components/ui/
To ensure custom styles & behavior survive component updates, follow these conventions:
- Create custom component overrides under
client/src/components/ui/overrides/ - Import override components in app code instead of generated shadcn components
- Add ESLint rules to prevent direct imports of generated components & point to override paths
All writes should go through SQLAlchemy
Alembic updates & bulk SQLAlchemy updates must explicitly set updated_at
