Skip to main content

Dev Environment Setup

This guide takes you from a fresh machine to a fully running Platform-Kernel infrastructure stack so you can write, test, and iterate on modules with production-identical services.

note

Stack parity. The local Docker Compose stack uses the same image versions as staging and production (versions are pinned in docker/versions.env). There are no "dev-mode only" shortcuts in infrastructure — what you test locally is what runs in prod.


Prerequisites

Install the following tools before proceeding. Exact versions matter.

ToolRequired VersionInstall
Go1.26.1go.dev/dl
Node.js24 LTS (Krypton)nodejs.org or fnm install 24
pnpm10.33.0npm install -g [email protected]
Docker Desktop4.69.0 (Engine 29.4.0)docker.com
Git2.40+System package manager
bufv1.68.2brew install bufbuild/buf/buf (optional — only for proto changes)

Verify your environment:

go version # go version go1.26.1 linux/amd64
node --version # v24.x.x
pnpm --version # 10.33.0
docker version # Engine: 29.4.0
danger

Apple Silicon (M-series) note. Two services in the stack require platform: linux/amd64 (ClickHouse and ClamAV). Docker Desktop on macOS uses Rosetta 2 emulation for these automatically. Ensure "Use Rosetta for x86/amd64 emulation on Apple Silicon" is enabled in Docker Desktop → Settings → General.


Repository Layout

The entire kernel monorepo lives under .dev/kernel/ — a Go workspace combined with a pnpm workspace:

.dev/kernel/
├── services/ # 15 Go microservices
│ ├── gateway/ # API Gateway (port 8051)
│ ├── iam/ # Identity & Access Management (port 8050)
│ ├── data-layer/ # Data CRUD + Analytics (port 8052)
│ ├── event-bus/ # Kafka + RabbitMQ bus (port 8053)
│ ├── notify/ # Notification Service (port 8054)
│ ├── billing/ # Billing & Subscriptions (port 8055)
│ ├── files/ # File Storage / S3 (port 8057)
│ ├── money/ # Money Service (port 8058)
│ ├── audit/ # Audit Log / ClickHouse (port 8059)
│ ├── integration-hub/ # External integrations (port 8056)
│ ├── module-registry/ # Module Registry (port 50060)
│ ├── domain-resolver/ # Custom Domain Mapping
│ ├── kernel-cli/ # Admin CLI
│ ├── vault/ # HashiCorp Vault client library
│ └── shared/ # Crypto, mTLS, Feature Flags helpers

├── packages/ # 22 TypeScript packages (SDK + tooling)
│ ├── sdk-auth/ # @platform/sdk-auth
│ ├── sdk-data/ # @platform/sdk-data
│ ├── sdk-events/ # @platform/sdk-events
│ ├── sdk-notify/ # @platform/sdk-notify
│ ├── sdk-files/ # @platform/sdk-files
│ ├── sdk-money/ # @platform/sdk-money
│ ├── sdk-audit/ # @platform/sdk-audit
│ ├── sdk-flags/ # @platform/sdk-flags
│ ├── sdk-core/ # @platform/sdk-core (shared types + HTTP client)
│ ├── sdk-ui/ # @platform/sdk-ui (Design System)
│ ├── sdk-testing/ # @platform/sdk-testing (mocks + fixtures)
│ ├── sdk-codegen/ # @platform/sdk-codegen (OpenAPI → TS)
│ ├── create-module/ # npx @platform/create-module CLI
│ ├── ui-shell/ # Admin UI Shell (Vite 8 + React 19 + MF 2.0)
│ ├── build-config/ # Shared Vite / ESLint / tsconfig
│ ├── dev-server/ # Local hot-reload development server
│ └── ...

├── proto/platform/ # gRPC Protobuf contracts (7 packages)
├── docker/ # Docker Compose configs + versions.env
├── sandbox/ # Sandbox environment
├── migrations/ # Shared DB migrations
├── go.work # Go workspace (links all services)
├── pnpm-workspace.yaml
└── .env.example # Environment variable template

Step 1 — Clone and Configure Environment

# Clone (replace with your actual remote)
git clone [email protected]:your-org/platform-kernel.git
cd platform-kernel/.dev/kernel

# Copy environment template
cp .env.example .env

The .env file contains all required variables. Defaults work out of the box for local development. For reference, here are the most important groups:

# PostgreSQL
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_DB=platform_kernel
POSTGRES_USER=kernel
POSTGRES_PASSWORD=CHANGEME_postgres_password

# Valkey (Redis-compatible cache)
VALKEY_HOST=localhost
VALKEY_PORT=6379
VALKEY_PASSWORD=CHANGEME_valkey_password

# Kafka (KRaft mode — no ZooKeeper)
KAFKA_BROKER=localhost:9092
KAFKA_BROKERS=localhost:9092
KAFKA_CLIENT_ID=platform-kernel

# RabbitMQ
RABBITMQ_HOST=localhost
RABBITMQ_PORT=5672
RABBITMQ_USER=kernel
RABBITMQ_PASSWORD=CHANGEME_rabbitmq_password
RABBITMQ_VHOST=/platform

# ClickHouse (OLAP — audit + analytics)
CLICKHOUSE_HOST=localhost
CLICKHOUSE_HTTP_PORT=8123
CLICKHOUSE_NATIVE_PORT=9000
CLICKHOUSE_DB=platform_audit
CLICKHOUSE_USER=kernel
CLICKHOUSE_PASSWORD=CHANGEME_clickhouse_password

# JWT (ES256 — filled by HashiCorp Vault in staging/prod)
JWT_SECRET=CHANGEME_jwt_secret_min_32_chars
JWT_ACCESS_TTL=900 # 15 minutes
JWT_REFRESH_TTL=604800 # 7 days

# Gateway
GATEWAY_PORT=8080
GATEWAY_RATE_LIMIT_PER_TENANT=1000
GATEWAY_RATE_LIMIT_PER_IP=20
GATEWAY_RATE_LIMIT_AUTH_PER_MIN=5

# Database connection pool (all Go services)
DB_MAX_OPEN_CONNS=25
DB_MAX_IDLE_CONNS=5
danger

Never commit .env to Git. It is listed in .gitignore. Use a secrets manager (HashiCorp Vault, 1Password Secrets Automation) for team secret sharing.


Step 2 — Start the Infrastructure Stack

The full stack is defined in docker/docker-compose.yml with image versions pinned in docker/versions.env:

ImageVersion (April 2026)
PostgreSQL17-alpine
Valkey8.1-alpine
Apache Kafka (KRaft)3.9.0
RabbitMQ4.1-management-alpine
ClickHouse25.3-alpine
SeaweedFS (S3)3.84
HashiCorp Vault1.19
GoFeatureFlagv1.42.0
ClamAV1.4
Envoyv1.33-latest

Launch everything with a single command from .dev/kernel/:

docker compose --env-file docker/versions.env up -d

Wait for all services to become healthy (takes ~2–3 minutes on first boot due to ClamAV signature download and ClickHouse WAL initialization):

docker compose ps

Expected output — all STATUS should be healthy:

NAME STATUS
platform-postgres healthy
platform-valkey healthy
platform-kafka healthy
platform-rabbitmq healthy
platform-clickhouse healthy
platform-seaweedfs healthy
platform-vault healthy
platform-feature-flags running # healthcheck disabled — distroless image
platform-clamav healthy # takes ~120s on first boot

Step 3 — Service Port Map

Once running, the following local ports are exposed. All API calls go through the Gateway (localhost:8051) — direct service ports are for observability and debugging only.

ServiceHTTP PortgRPC PortNotes
Gateway805150051Primary API entry point
IAM805050050Identity & Access Management
Data Layer805250052CRUD + analytics
Event Bus805350053Kafka + RabbitMQ bridge
Notify805450054Notifications
Billing805550055Subscriptions + limits
Integration Hub805650056External integrations
Files805750057S3 object storage
Money805850058Wallets + transactions
Audit805950059Immutable audit log
SeaweedFS S38333S3-compatible object store
HashiCorp Vault8200Secret management
RabbitMQ Admin15672Management UI
ClickHouse HTTP8123HTTP query interface
GoFeatureFlag1031Feature flag evaluation API
Envoy Admin9901Proxy admin interface

Verify the Gateway is healthy:

curl -s http://localhost:8051/health | jq .status
# "ok"

Step 4 — Install TypeScript Dependencies

From .dev/kernel/:

pnpm install

pnpm uses the workspace defined in pnpm-workspace.yaml — a single install bootstraps all 22 packages simultaneously.


Step 5 — Build SDK Packages

The SDK packages must be built before your module can import them:

pnpm --filter "./packages/**" run build

For hot-reload development of sdk-* packages while writing a module:

pnpm --filter "@platform/sdk-data" run dev

Step 6 — Shared Tooling

packages/build-config

The @platform/build-config package is the Single Source of Truth for all build tooling shared across modules:

  • Shared Vite configuration (Module Federation 2.0 presets)
  • EnterpriseSingletons — the shared block for federation.config.js. Do not hardcode requiredVersion in your module. Update packages/build-config/src/mf-singletons.ts instead.
  • Shared ESLint config (eslint.config.mjs)
  • Shared tsconfig.base.json

packages/dev-server

The @platform/dev-server package provides a local hot-reload proxy that sits in front of your module and the UI Shell:

# From your module directory
pnpm dev

The dev server proxies all /api/v1/* requests to localhost:8051 (Gateway) and serves your module's Module Federation remote entry at http://localhost:3001/remoteEntry.js.


Linting & Code Quality

The monorepo enforces strict quality gates:

# Go services — golangci-lint (config in .golangci.yml)
golangci-lint run ./...

# TypeScript — ESLint (config in eslint.config.mjs)
pnpm lint

# TypeScript type-checking
pnpm typecheck

# Go tests with coverage
go test ./... -coverprofile=coverage.out
go tool cover -func=coverage.out
tip

The CI pipeline runs all three in sequence. Green local linting = green CI (there are no CI-only rules). The target coverage floor for every Go package is 80%.


Environment Validation Checklist

Before starting module development, verify all services are reachable:

# Gateway is up
curl -sf http://localhost:8051/health

# Kafka is accepting connections
docker exec platform-kafka /opt/kafka/bin/kafka-broker-api-versions.sh \
--bootstrap-server localhost:9092

# PostgreSQL is accepting queries
docker exec platform-postgres psql -U kernel -d platform_kernel -c "SELECT version();"

# Vault is initialized (dev mode — in-memory, no unsealing required)
curl -sf http://localhost:8200/v1/sys/health | jq .initialized
# true

# Feature flags evaluation
curl -sf http://localhost:1031/health | jq .initialized
# true

All five checks passing means your environment is ready for Sandbox and module development.