Development Setup¶
This guide walks you through setting up a development environment for Farm.
Prerequisites¶
Required Software¶
| Software | Version | Purpose |
|---|---|---|
| Node.js | 20+ | JavaScript runtime |
| npm | 10+ | Package manager |
| Docker | 24+ | Containerization and environment isolation |
| Docker Compose | 2.20+ | Multi-container orchestration |
| Make | 4+ | Task automation and simplified commands |
| Git | Latest | Version control |
Recommended Tools¶
- Visual Studio Code with the following extensions:
- ESLint
- Prettier
- TypeScript and JavaScript Language Features
- Tailwind CSS IntelliSense
Getting Started¶
1. Clone the Repository¶
2. Install Dependencies¶
Copy the example environment file and adjust values as needed:
3. Start the Development Server¶
Option A: Full Stack with Docker (Recommended)¶
Start the entire stack (API, database, Redis, observability, docs, and web) with a single command:
This builds all images and starts all containers. Access points:
| Service | URL |
|---|---|
| Web UI | http://localhost:3001 |
| API | http://localhost:3000/api |
| Swagger UI | http://localhost:3000/api/docs (Basic Auth: farm / farm) |
| Grafana | http://localhost:3002 |
| Prometheus | http://localhost:9090 |
| MkDocs | http://localhost:8000 |
To stop and clean up:
Seeding Sample Data¶
After starting the application, populate the database with sample data:
This creates default users and sample catalog entries. The seeder is idempotent and only runs in development/test environments.
| User | Password | Role |
|---|---|---|
| admin | Admin1234 | admin |
| developer | Developer1 | user |
Option B: Backend Only (Docker)¶
This starts the API and PostgreSQL database. Use when working on backend features without the full observability stack.
Option C: Local Development (Node.js)¶
For local development with hot-reload, start the database with Docker and run the backend and frontend locally:
# Start PostgreSQL
docker compose up -d postgres
# Start backend (port 3000)
npm run start:dev
# Start frontend (port 3000, separate terminal)
cd web && npm run dev
Running Documentation Server¶
The documentation server is part of the main docker-compose.yml under the docs profile:
make docs-up # Start MkDocs at http://localhost:8000
make docs-down # Stop
make docs-build # Build static site into ./site
make docs-logs # Follow container logs
Project Structure¶
farm/
apps/
api/ # NestJS backend
src/
app.module.ts # Root application module
main.ts # Application entry point
common/ # Shared utilities (filters, health, logger)
config/ # Environment configuration
database/ # Seeds and database utilities
migrations/ # TypeORM migrations
modules/ # Feature modules
auth/ # Authentication module
catalog/ # Catalog module
documentation/ # Documentation module
environments/ # Environments and Deployments module
teams/ # Teams and Ownership module
audit-log/ # Audit log module
plugin-manager/ # Plugin manager module
test/ # End-to-end tests
web/ # Next.js frontend
src/
app/ # App Router pages
components/ # React components
contexts/ # Context providers
lib/ # API client, WebSocket, utilities
types/ # TypeScript types
vitest.config.ts # Vitest configuration
docs/ # MkDocs documentation source
Available Scripts¶
Backend¶
| Script | Description |
|---|---|
npm run start | Start the application |
npm run start:dev | Start with hot-reload |
npm run start:debug | Start with debugging enabled |
npm run build | Build the application |
npm run lint | Run ESLint |
npm run format | Format code with Prettier |
npm run test | Run unit tests |
npm run test:watch | Run tests in watch mode |
npm run test:cov | Run tests with coverage |
npm run test:e2e | Run end-to-end tests |
Frontend¶
| Script | Description |
|---|---|
cd web && npm run dev | Start dev server with hot-reload |
cd web && npm run build | Build for production |
cd web && npm run lint | Run ESLint |
cd web && npm test | Run Vitest tests |
cd web && npm run test:watch | Run tests in watch mode |
cd web && npm run test:coverage | Run tests with coverage |
Makefile Targets¶
| Target | Description |
|---|---|
make up-docker | Build and start API and PostgreSQL database |
make down-docker | Stop Docker containers |
make down-docker-clean | Stop containers and remove database volumes |
make up-observability | Start API + DB + Redis + Grafana + Prometheus + Tempo |
make up-all | Start the full stack (API + DB + Redis + Observability + Docs + Web) |
make down-all | Stop the full stack |
make healthcheck | Query the local API advanced health endpoint |
make seed | Seed the database with sample data |
make check | Run all checks (backend + frontend) |
make check-back | Run backend checks (fmt, lint, test, e2e) |
make check-front | Run frontend checks (lint, build, test) |
make web-dev | Start the frontend dev server |
make web-build | Build the frontend for production |
make web-lint | Lint the frontend code |
make web-test | Run frontend tests |
make docs-up | Start the documentation server (MkDocs) |
make docs-down | Stop documentation container |
make test-docker | Execute backend tests in a clean container |
make release | Create a new release using release-it |
Development Workflow¶
Making Changes¶
-
Create a new branch from
main: -
Make your changes
-
Run checks:
-
Commit your changes:
Code Style¶
Farm uses ESLint and Prettier to maintain consistent code style:
- Run
npm run lintto check for linting issues - Run
npm run formatto automatically format code - Most editors can be configured to format on save
Debugging¶
Backend (VS Code)¶
Create a .vscode/launch.json file:
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Debug Farm API",
"runtimeExecutable": "npm",
"runtimeArgs": ["run", "start:debug"],
"console": "integratedTerminal"
}
]
}
Backend (Command Line)¶
Environment Variables¶
Backend¶
| Variable | Default | Description |
|---|---|---|
NODE_ENV | development | Runtime environment |
PORT | 3000 | HTTP server port |
LOG_LEVEL | info | Minimum log level for Winston |
DATABASE_TYPE | postgres | Database engine (postgres, sqlite) |
DATABASE_HOST | localhost | Database hostname |
DATABASE_PORT | 5432 | Database port |
DATABASE_USER | postgres | Database username |
DATABASE_PASSWORD | postgres | Database password |
DATABASE_NAME | farm | Database name |
DATABASE_SYNC | false | Enable TypeORM auto-sync |
DATABASE_POOL_SIZE | 10 | Database connection pool size |
JWT_SECRET | (auto-generated in dev) | Secret key for JWT signing (min 32 chars in production) |
JWT_EXPIRATION | 3600s | JWT token expiration time |
ALLOWED_ORIGINS | * | CORS allowed origins |
SWAGGER_USER | farm | HTTP Basic Auth username for /api/docs |
SWAGGER_PASSWORD | farm | HTTP Basic Auth password for /api/docs |
THROTTLE_TTL | 60000 | Rate limit time window (ms) |
THROTTLE_LIMIT | 10 | Maximum requests per TTL window |
REDIS_HOST | (empty) | Redis hostname (empty for in-memory cache) |
REDIS_PORT | 6379 | Redis port |
CACHE_TTL | 30 | Cache time-to-live (seconds) |
SMTP_HOST | (empty) | SMTP server hostname (empty to disable email) |
SMTP_PORT | 587 | SMTP server port |
SMTP_SECURE | false | Use TLS (true for port 465) |
SMTP_USER | (empty) | SMTP authentication username |
SMTP_PASS | (empty) | SMTP authentication password |
SMTP_FROM | Farm <noreply@farm.local> | Default sender address |
OTEL_ENABLED | false | Enable OpenTelemetry trace export |
OTEL_EXPORTER_ENDPOINT | http://localhost:4318/v1/traces | OTLP HTTP endpoint |
OTEL_SERVICE_NAME | farm-api | Service name in trace metadata |
GRAFANA_URL | (empty) | Grafana base URL (leave empty to disable Grafana links) |
PROMETHEUS_URL | http://localhost:9090 | Prometheus endpoint for metrics proxy |
JAEGER_URL | http://localhost:16686 | Jaeger UI endpoint for traces proxy |
LOKI_URL | http://localhost:3100 | Loki endpoint for log aggregation proxy |
GITHUB_CLIENT_ID | (empty) | GitHub OAuth application client ID |
GITHUB_CLIENT_SECRET | (empty) | GitHub OAuth application client secret |
GITHUB_CALLBACK_URL | http://localhost:3000/api/v1/auth/github/callback | GitHub OAuth redirect URI |
GOOGLE_CLIENT_ID | (empty) | Google OAuth application client ID |
GOOGLE_CLIENT_SECRET | (empty) | Google OAuth application client secret |
GOOGLE_CALLBACK_URL | http://localhost:3000/api/v1/auth/google/callback | Google OAuth redirect URI |
SLACK_WEBHOOK_URL | (empty) | Slack incoming webhook URL for notifications (leave empty to disable) |
TEAMS_WEBHOOK_URL | (empty) | Microsoft Teams webhook URL for notifications (leave empty to disable) |
PLUGINS_DIR | ./plugins | Directory for external runtime plugins |
KUBECONFIG_PATH | (empty) | Path to a kubeconfig file; leave empty to use in-cluster config (Kubernetes, Helm, and CRD features) |
AWS_ACCESS_KEY_ID | (empty) | AWS IAM access key ID — only needed when using a single global AWS credential instead of per-org credentials |
AWS_SECRET_ACCESS_KEY | (empty) | AWS IAM secret access key — paired with AWS_ACCESS_KEY_ID |
AWS_REGION | us-east-1 | Default AWS region for cloud discovery and deployments |
GCP_PROJECT_ID | (empty) | Default GCP project ID — only needed for global GCP credential fallback |
AZURE_SUBSCRIPTION_ID | (empty) | Default Azure subscription ID — only needed for global Azure credential fallback |
Frontend¶
| Variable | Default | Description |
|---|---|---|
NEXT_PUBLIC_API_URL | (none) | Public API URL (fallback for rewrites) |
API_INTERNAL_URL | http://api:3000/api | Internal Docker API URL (build-time) |
NEXT_PUBLIC_WS_URL | http://localhost:3000 | WebSocket server URL |
NEXT_TELEMETRY_DISABLED | 1 | Disable Next.js anonymous telemetry (set in apps/web/.env.local) |
OAuth Social Login¶
Farm supports login via GitHub and Google using OAuth 2.0. Both providers are optional — if the credentials are not configured, the buttons are still rendered in the UI but will fail at the GitHub/Google authorization page. Leave all six variables empty to disable social login entirely.
GitHub OAuth¶
- Go to github.com → Settings → Developer settings → OAuth Apps → New OAuth App.
- Fill in the fields:
| Field | Value |
|---|---|
| Application name | Farm |
| Homepage URL | http://localhost:3000 (or your production domain) |
| Authorization callback URL | http://localhost:3000/api/v1/auth/github/callback |
- After creating the app, copy the Client ID and generate a Client Secret.
- Add to
apps/api/.env:
GITHUB_CLIENT_ID=your_client_id
GITHUB_CLIENT_SECRET=your_client_secret
GITHUB_CALLBACK_URL=http://localhost:3000/api/v1/auth/github/callback
Google OAuth¶
- Go to console.cloud.google.com → APIs & Services → Credentials → Create Credentials → OAuth 2.0 Client ID.
- Set application type to Web application.
- Add an authorized redirect URI:
http://localhost:3000/api/v1/auth/google/callback - Copy the Client ID and Client Secret.
- Add to
apps/api/.env:
GOOGLE_CLIENT_ID=your_client_id
GOOGLE_CLIENT_SECRET=your_client_secret
GOOGLE_CALLBACK_URL=http://localhost:3000/api/v1/auth/google/callback
Production¶
Replace http://localhost:3000 with your public domain in all callback URLs. Update the registered callback URL in the GitHub/Google developer console to match.
When running via Docker Compose, add the variables to the api service environment in docker-compose.yml or pass them via a .env file at the repository root.
How it works¶
- User clicks "Continue with GitHub" or "Continue with Google" on the login page.
- The browser navigates to
GET /api/v1/auth/github(or/google), which redirects to the provider's authorization page. - After the user authorizes, the provider redirects back to the callback URL.
- The API finds or creates the user account, then returns a JWT access token and refresh token.
- The browser is redirected to the Farm dashboard with the session established.
Troubleshooting¶
Port Already in Use¶
If port 3000 is already in use:
Dependency Issues¶
Frontend Build Errors¶
Docker Port Conflicts¶
The default port mapping is:
| Container | Port |
|---|---|
| farm-api | 3000 |
| farm-web | 3001 |
| farm-grafana | 3002 |
| farm-prometheus | 9090 |
| farm-tempo | 3200, 4318 |
| farm-docs | 8000 |
| farm-db | 5432 |
| farm-redis | 6379 |
If a port is already in use, stop the conflicting process or adjust the port mapping in docker-compose.yml or docker-compose.observability.yml.