## Summary - Isolate dev, E2E, and integration test environments so multiple git worktrees can run all three simultaneously without port conflicts - Each worktree gets a deterministic slot (0-99) with unique port ranges: dev (30100-31199), E2E (20320-21399), CI integration (14320-40098) - Dev portal dashboard (http://localhost:9900) auto-discovers all running stacks, streams logs, and provides a History tab for past run logs ## Port Isolation | Environment | Port Range | Project Name | |---|---|---| | Dev stack | 30100-31199 | `hdx-dev-<slot>` | | E2E tests | 20320-21399 | `e2e-<slot>` | | CI integration | 14320-40098 | `int-<slot>` | All three can run simultaneously from the same worktree with zero port conflicts. ## Dev Portal Features **Live tab:** - Auto-discovers dev, E2E, and integration Docker containers + local services (API, App) - Groups all environments for the same worktree into a single card - SSE log streaming with ANSI color rendering, capped at 5000 lines - Auto-starts in background from `make dev`, `make dev-e2e`, `make dev-int` **History tab:** - Logs archived to `~/.config/hyperdx/dev-slots/<slot>/history/` on exit (instead of deleted) - Each archived run includes `meta.json` with worktree/branch metadata - Grouped by worktree with collapsible cards, search by worktree/branch - View any past log file in the same log panel, delete individual runs or clear all - Custom dark-themed confirm modal (no native browser dialogs) ## What Changed - **`scripts/dev-env.sh`** — Slot-based port assignments, portal auto-start, log archival on exit - **`scripts/test-e2e.sh`** — E2E port range (20320-21399), log capture via `tee`, portal auto-start, log archival - **`scripts/ensure-dev-portal.sh`** — Shared singleton portal launcher (works sourced or executed) - **`scripts/dev-portal/server.js`** — Discovery for dev/E2E/CI containers, history API (list/read/delete), local service port probing - **`scripts/dev-portal/index.html`** — Live/History tabs, worktree-grouped cards, search, collapse/expand, custom confirm modal, ANSI color log rendering - **`docker-compose.dev.yml`** — Parameterized ports/volumes/project name with `hdx.dev.*` labels - **`packages/app/tests/e2e/docker-compose.yml`** — Updated to new E2E port defaults - **`Makefile`** — `dev-int`/`dev-e2e` targets with log capture + portal auto-start; `dev-portal-stop`; `dev-clean` stops everything + wipes slot data - **`.env` files** — Ports use `${VAR:-default}` syntax across dev, E2E, and CI environments - **`agent_docs/development.md`** — Full documentation for isolation, port tables, E2E/CI port ranges ## How to Use ```bash # Start dev stack (auto-starts portal) make dev # Run E2E tests (auto-starts portal, separate ports) make dev-e2e FILE=navigation # Run integration tests (auto-starts portal, separate ports) make dev-int FILE=alerts # All three can run simultaneously from the same worktree # Portal at http://localhost:9900 shows everything # Stop portal make dev-portal-stop # Clean up everything (all stacks + portal + history) make dev-clean ``` ## Dev Portal <img width="1692" height="944" alt="image" src="https://github.com/user-attachments/assets/6ed388a3-43bc-4552-aa8d-688077b79fb7" /> <img width="1689" height="935" alt="image" src="https://github.com/user-attachments/assets/8677a138-0a40-4746-93ed-3b355c8bd45e" /> ## Test Plan - [x] Run `make dev` — verify services start with slot-assigned ports - [x] Run `make dev` in a second worktree — verify different ports, no conflicts - [x] Run `make dev-e2e` and `make dev-int` simultaneously — no port conflicts - [x] Open http://localhost:9900 — verify all stacks grouped by worktree - [x] Click a service to view logs — verify ANSI colors render correctly - [x] Stop a stack — verify logs archived to History tab with correct worktree - [x] History tab — search, collapse/expand, view archived logs, delete - [x] `make dev-clean` — stops everything, wipes slot data and history
8.8 KiB
Development Workflows
Setup Commands
# Install dependencies and setup hooks
yarn setup
# Start full development stack (auto-assigns unique ports per worktree)
yarn dev # or equivalently: make dev
Key Development Scripts
yarn dev/make dev: Start full dev stack with worktree-isolated ports. A dev portal at http://localhost:9900 auto-starts showing all running stacks.yarn dev:down/make dev-down: Stop the dev stack for the current worktreemake dev-portal: Start the dev portal manually (auto-started byyarn dev)yarn lint: Run linting across all packagesyarn dev:unit: Run unit tests in watch mode (per package)
Environment Configuration
.env.development: Development environment variables- Docker Compose manages ClickHouse, MongoDB, OTel Collector
- Hot reload enabled for all services in development
Worktree Isolation (Multi-Agent / Multi-Developer)
When multiple git worktrees need to run the dev stack simultaneously (e.g.
multiple agents or developers working in parallel), use make dev instead of
yarn dev. This automatically assigns unique ports per worktree.
How It Works
- A deterministic slot (0-99) is computed from the worktree directory name (via
cksum) - Each service gets a unique port:
base + slot(see table below) - Docker Compose runs with a unique project name (
hdx-dev-<slot>) - Volume paths include the slot to prevent data corruption between worktrees
Dev Port Mapping (base + slot)
Ports are allocated in the 30100-31199 range to avoid conflicts with CI integration tests (14320-40098) and E2E tests (20320-21399).
| Service | Base Port | Range | Env Variable |
|---|---|---|---|
| API server | 30100 | 30100 - 30199 | HYPERDX_API_PORT |
| App (Next.js) | 30200 | 30200 - 30299 | HYPERDX_APP_PORT |
| OpAMP | 30300 | 30300 - 30399 | HYPERDX_OPAMP_PORT |
| MongoDB | 30400 | 30400 - 30499 | HDX_DEV_MONGO_PORT |
| ClickHouse HTTP | 30500 | 30500 - 30599 | HDX_DEV_CH_HTTP_PORT |
| ClickHouse Native | 30600 | 30600 - 30699 | HDX_DEV_CH_NATIVE_PORT |
| OTel health | 30700 | 30700 - 30799 | HDX_DEV_OTEL_HEALTH_PORT |
| OTel gRPC | 30800 | 30800 - 30899 | HDX_DEV_OTEL_GRPC_PORT |
| OTel HTTP | 30900 | 30900 - 30999 | HDX_DEV_OTEL_HTTP_PORT |
| OTel metrics | 31000 | 31000 - 31099 | HDX_DEV_OTEL_METRICS_PORT |
| OTel JSON HTTP | 31100 | 31100 - 31199 | HDX_DEV_OTEL_JSON_HTTP_PORT |
Dev Portal
The dev portal is a centralized web dashboard that discovers all running worktree stacks by inspecting Docker container labels and slot files.
# Start the portal (runs on fixed port 9900)
make dev-portal
# Open in browser
open http://localhost:9900
The portal auto-refreshes every 3 seconds and shows each worktree's:
- Branch name and slot number
- All services with status (running/stopped) and clickable port links
- Separate cards for each active worktree
Overriding the Slot
# Use a specific slot instead of the auto-computed one
HDX_DEV_SLOT=5 make dev
Testing Strategy
Testing Tools
- Unit Tests: Jest with TypeScript support
- Integration Tests: Jest with database fixtures
- Frontend Testing: React Testing Library + Jest
- E2E Testing: Playwright (frontend) and Custom smoke tests with BATS (ingestion)
Testing Patterns
- TDD Approach: Write tests before implementation for new features
- Test organization: Tests co-located with source files in
__tests__/directories - Mocking: MSW for API mocking in frontend tests
- Database testing: Isolated test databases with fixtures
CI / Integration Testing
For integration testing:
# Build dependencies (run once before first test run)
make dev-int-build
# Run API integration tests (spins up Docker services, runs tests, tears down)
make dev-int FILE=<TEST_FILE_NAME>
# Run common-utils integration tests
make dev-int-common-utils FILE=<TEST_FILE_NAME>
Multi-agent / worktree support:
The make dev-int command automatically assigns unique Docker ports per
worktree directory, so multiple agents can run integration tests in parallel
without port conflicts.
- A deterministic slot (0-99) is computed from the worktree directory name
- Each slot gets its own Docker Compose project name and port range
- Override the slot manually:
make dev-int HDX_CI_SLOT=5 FILE=alerts - The slot and assigned ports are printed when
dev-intstarts
Port mapping (base + slot):
| Service | Default port (slot 0) | Variable |
|---|---|---|
| ClickHouse HTTP | 18123 | HDX_CI_CH_PORT |
| MongoDB | 39999 | HDX_CI_MONGO_PORT |
| API test server | 19000 | HDX_CI_API_PORT |
| OpAMP | 14320 | HDX_CI_OPAMP_PORT |
CI Testing Notes:
- Uses separate Docker Compose configuration (
docker-compose.ci.yml) - Isolated test environment with unique
-p int-<slot>project name - Includes all necessary services (ClickHouse, MongoDB, OTel Collector)
- Tests run against real database instances for accurate integration testing
E2E Testing
E2E tests use the same slot-based isolation pattern as integration tests, with their own dedicated port range (20320-21399) so they can run simultaneously with both the dev stack and CI integration tests.
E2E port mapping (base + slot):
| Service | Base Port | Range | Env Variable |
|---|---|---|---|
| OpAMP | 20320 | 20320 - 20419 | HDX_E2E_OPAMP_PORT |
| ClickHouse HTTP | 20500 | 20500 - 20599 | HDX_E2E_CH_PORT |
| ClickHouse Native | 20600 | 20600 - 20699 | HDX_E2E_CH_NATIVE_PORT |
| API server | 21000 | 21000 - 21099 | HDX_E2E_API_PORT |
| MongoDB | 21100 | 21100 - 21199 | HDX_E2E_MONGO_PORT |
| App (local) | 21200 | 21200 - 21299 | HDX_E2E_APP_LOCAL_PORT |
| App (fullstack) | 21300 | 21300 - 21399 | HDX_E2E_APP_PORT |
# Run all E2E tests
make e2e
# Run a specific test file (dev mode: hot reload, containers kept running)
make dev-e2e FILE=navigation
# Run a specific test by grep pattern
make dev-e2e FILE=navigation GREP="help menu"
# Grep across all files
make dev-e2e GREP="should navigate"
# Open HTML report after tests finish (screenshots, traces, step-by-step)
make dev-e2e FILE=navigation REPORT=1
# Or call the script directly for more control
./scripts/test-e2e.sh --ui --last-failed
# Override the slot manually
HDX_E2E_SLOT=5 ./scripts/test-e2e.sh
- A deterministic slot (0-99) is computed from the worktree directory name
- Each slot gets its own Docker Compose project name (
e2e-<slot>) and port range - The slot and assigned ports are printed when E2E tests start
Port range safety: E2E has its own dedicated port range (20320-21399) that does not overlap with CI integration tests (14320-40098) or the dev stack (30100-31199), so all three can run simultaneously from the same worktree.
Common Development Tasks
Adding New Features
- API First: Define API endpoints and data models
- Database Models: Create/update Mongoose schemas and ClickHouse queries
- Frontend Integration: Build UI components and integrate with API
- Testing: Add unit and integration tests
- Documentation: Update relevant docs
Debugging
- Check browser and server console output for errors, warnings, or relevant logs
- Add targeted logging to trace execution and variable states
- For persistent issues, check
fixes/directory for documented solutions - Document complex fixes in
fixes/directory with descriptive filenames
Code Quality
Pre-commit Hooks
The project uses Husky + lint-staged to automatically run:
- Prettier for formatting
- ESLint for linting
- API doc generation (for external API changes)
These run automatically on git commit for staged files.
Manual Linting (if needed)
If you need to manually lint:
# Per-package linting with auto-fix
cd packages/app && yarn run lint:fix
cd packages/api && yarn run lint:fix
cd packages/common-utils && yarn lint:fix
# Check all packages
yarn run lint
File Locations Quick Reference
- Config:
packages/api/src/config.ts,packages/app/next.config.mjs,docker-compose.dev.yml - Models:
packages/api/src/models/ - API Routes:
packages/api/src/routers/ - Controllers:
packages/api/src/controllers/ - Pages:
packages/app/pages/ - Components:
packages/app/src/ - Shared Utils:
packages/common-utils/src/