Skip to content

Commit 0082cce

Browse files
jthakkar04claude
andauthored
chore: fix relay build and improve dev setup (#927)
Signed-off-by: Jagat Thakkar <32109558+jthakkar04@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 9c1ad0c commit 0082cce

5 files changed

Lines changed: 208 additions & 27 deletions

File tree

.gitignore

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,18 @@ dist/
6464
.idea/
6565

6666
state/
67-
.claude/
67+
68+
# Go build artifacts
69+
*.exe
70+
*.dll
71+
*.so
72+
*.dylib
73+
*.test
74+
*.out
75+
coverage.html
76+
vendor/
77+
apps/relay/bin/
78+
79+
# Air (hot-reload) logs
80+
build-errors.log
81+
.claude/

CLAUDE.md

Lines changed: 150 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,158 @@
1-
# Ctrlplane Development Guide
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## What Is Ctrlplane?
6+
7+
Ctrlplane is the **orchestration layer between CI/CD pipelines and infrastructure** — it decides when releases are ready, where they should deploy, and what gates they must pass (environment promotion, verification, approvals, rollbacks).
8+
9+
```text
10+
Your CI/CD → Ctrlplane (orchestrates) → Your Infrastructure
11+
```
212

313
## Common Commands
414

5-
- `pnpm build` - Build all packages
6-
- `pnpm lint` - Run ESLint
7-
- `pnpm lint:fix` - Run ESLint with auto-fix
8-
- `pnpm format` - Check formatting
9-
- `pnpm format:fix` - Fix formatting
10-
- `pnpm typecheck` - Type check all packages
11-
- `pnpm test` - Run all tests
12-
- `pnpm -F <package-name> test` - Run tests for a specific package
13-
- `pnpm -F <package-name> test -- -t "test name"` - Run a specific test
15+
### Setup (first time)
16+
```bash
17+
docker compose -f docker-compose.dev.yaml up -d # Start local services
18+
pnpm i && pnpm build # Install deps and build
19+
pnpm -F @ctrlplane/db migrate # Apply database migrations
20+
pnpm dev # Start all dev servers
21+
# Reset (wipe all Docker volumes first):
22+
docker compose -f docker-compose.dev.yaml down -v
23+
docker compose -f docker-compose.dev.yaml up -d
24+
pnpm -F @ctrlplane/db migrate
25+
pnpm dev
26+
```
1427

15-
## Code Style
28+
### Day-to-day
29+
- `pnpm test` — Run all TypeScript tests
30+
- `pnpm lint` — Lint all TypeScript code
31+
- `pnpm format:fix` — Format all TypeScript code
32+
- `pnpm build` — Build all packages
33+
- `pnpm typecheck` — TypeScript type check across all packages
34+
- `pnpm -F <package-name> test` — Run tests for a specific package
35+
- `pnpm -F <package-name> test -- -t "test name"` — Run a specific test
36+
37+
### Database
38+
- `pnpm -F @ctrlplane/db migrate` — Run migrations
39+
- `pnpm -F @ctrlplane/db push` — Apply schema changes (dev, no migration file)
40+
- `pnpm -F @ctrlplane/db studio` — Open Drizzle Studio UI
1641

17-
- Use TypeScript with explicit types (prefer interfaces for public APIs)
18-
- Import styles: Use named imports, group imports by source (std lib > external > internal)
19-
- Consistent type imports: `import type { Type } from "module"`
20-
- Formatting: Prettier is used with `@ctrlplane/prettier-config`
21-
- Prefer async/await over raw promises
22-
- Adhere to file/directory naming conventions in each package
23-
- Handle errors explicitly (use try/catch and typed error responses)
24-
- Document public APIs and complex logic
25-
- For tests, use vitest with mocks and typed test fixtures
42+
### E2E Tests (Playwright)
43+
```bash
44+
cd e2e
45+
pnpm exec playwright test # Run all e2e tests
46+
pnpm exec playwright test tests/api/resources.spec.ts # Run a specific file
47+
pnpm test:api # Run all API tests
48+
pnpm test:debug # Run in debug mode
49+
```
50+
E2E tests use YAML fixture files (`.spec.yaml` alongside `.spec.ts`) to declare test entities. `importEntitiesFromYaml` loads them; `cleanupImportedEntities` tears them down. Use `addRandomPrefix: true` when parallel runs may conflict.
51+
52+
### workspace-engine (Go)
53+
```bash
54+
cd apps/workspace-engine
55+
go run ./... # Run without building
56+
go build -o ./bin/workspace-engine . # Build binary
57+
go test ./... # Run tests
58+
golangci-lint run # Lint
59+
go fmt ./... # Format
60+
```
2661

2762
## Monorepo Structure
2863

29-
- Packages are organized in apps/, packages/, integrations/ directories
30-
- Turborepo manages the build pipeline and dependencies
31-
- Shared configs are in the tooling/ directory
64+
```text
65+
apps/
66+
api/ # Node.js/Express REST API — core business logic
67+
web/ # React 19 + React Router frontend
68+
workspace-engine/ # Go reconciliation engine (multiple controllers)
69+
relay/ # Go WebSocket relay for agent communication
70+
packages/
71+
db/ # Drizzle ORM schema + migrations (PostgreSQL)
72+
trpc/ # tRPC server setup
73+
auth/ # better-auth integration
74+
workspace-engine-sdk/ # Published TypeScript SDK for external integrations
75+
integrations/ # External service adapters
76+
e2e/ # Playwright end-to-end tests (API + UI)
77+
tooling/ # Shared ESLint, Prettier, TypeScript configs
78+
```
79+
80+
**Build system**: Turborepo + pnpm workspaces. Package names use `@ctrlplane/` scope.
81+
82+
## Architecture
83+
84+
### Service Communication
85+
86+
- **Web → API**: tRPC (type-safe RPC via `/api/trpc`)
87+
- **API → workspace-engine**: PostgreSQL work queue (`reconcile_work_scope` table)
88+
- **Relay → Job Agents**: WebSocket bidirectional streaming
89+
- **External webhooks** (GitHub, ArgoCD, Terraform Cloud) hit `apps/api`
90+
91+
### Reconciliation / Work Queue
92+
93+
The workspace-engine implements a PostgreSQL-backed work queue. Multiple controllers poll `reconcile_work_scope` for leased work items:
94+
95+
| Controller | Responsibility |
96+
|---|---|
97+
| `deploymentplan` | Compute which resources match a deployment selector |
98+
| `desiredrelease` | Determine target release per resource |
99+
| `policyeval` | Evaluate policy rules against release targets |
100+
| `jobdispatch` | Route jobs to the correct job agent |
101+
| `jobeligibility` | Check whether a job can run |
102+
| `jobverificationmetric` | Poll verification metrics (Datadog, Prometheus, HTTP) |
103+
| `environmentresourceselectoreval` | Evaluate env-level resource selectors |
104+
| `relationshipeval` | Evaluate resource relationship rules |
105+
106+
Controllers use lease-based locking to prevent duplicate processing and support `Result.RequeueAfter` for scheduled retries. The engine is horizontally scalable — use `SERVICES` env var to activate specific controllers per instance.
107+
108+
### Release & Deployment Flow
109+
110+
```text
111+
CI registers version
112+
→ Release Target Planning (resource × environment fan-out)
113+
→ Policy Evaluation (approvals, environment ordering, deploy windows)
114+
→ Job Dispatch (GitHub Actions / ArgoCD / Terraform Cloud / custom agent)
115+
→ Verification (metrics checks → promote or rollback)
116+
```
117+
118+
### Policy Engine
119+
120+
Policies are **CEL-based declarative rules** with a `selector` field (CEL expression) matching resources/environments. Rule types:
121+
122+
- `policyRuleAnyApproval` — require N approvals
123+
- `policyRuleEnvironmentProgression` — enforce environment ordering (staging → prod)
124+
- `policyRuleDeploymentWindow` — restrict deploy times (rrule-based schedules)
125+
- `policyRuleGradualRollout` — sequential fan-out with intervals
126+
- `policyRuleVerification` — check metrics before advancing
127+
- `policyRuleRetry` / `policyRuleRollback` — failure handling
128+
129+
All policies for a release target must pass (AND between types, OR within a type).
130+
131+
### Database Schema (packages/db)
132+
133+
Drizzle ORM manages the PostgreSQL schema. Key tables:
134+
135+
- `workspace` — multi-tenant isolation; all tables include `workspaceId`
136+
- `deployment` / `deploymentVersion` — service definitions and builds
137+
- `environment` — staging, prod, etc.
138+
- `resource` / `resourceProvider` — infrastructure inventory
139+
- `release` / `releaseJob` — deployment instances and execution units
140+
- `job` / `jobAgent` — execution units and executor configs
141+
- `policy` / `policyRule*` — CEL-based deployment gates
142+
- `reconcile_work_scope` — work queue (kind, scopeType, scopeId, priority, notBefore)
143+
144+
### Job Agents
145+
146+
Job agents are execution adapters stored in the `jobAgent` table. Supported agents: GitHub Actions, ArgoCD, Kubernetes Jobs, Terraform Cloud, Argo Workflows. The `jobdispatch` controller routes jobs to agents; each translates a job spec to agent-native format and correlates results via `externalId`.
147+
148+
## Code Style
149+
150+
- TypeScript with explicit types; prefer `interface` for public APIs
151+
- Named imports; group by source (std lib → external → internal)
152+
- `import type { Type }` for type-only imports
153+
- Prettier via `@ctrlplane/prettier-config`
154+
- `async/await` over raw promises
155+
- React: functional components only; type as `const Foo: React.FC<Props> = () => {}`
156+
- Tests use vitest with typed fixtures
157+
- Use the builder pattern for complex object construction
158+
- For Go (workspace-engine): see `apps/workspace-engine/CLAUDE.md` for its own guidelines

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
Your CI builds code. Your clusters run it. Ctrlplane decides _when_ releases are ready, _where_ they should deploy, and _what gates_ they must pass—handling environment promotion, verification, approvals, and rollbacks automatically.
2929

30-
```
30+
```text
3131
Your CI/CD ──► Ctrlplane ──► Your Infrastructure
3232
(builds) (orchestrates) (deploys)
3333
```
@@ -80,7 +80,7 @@ For self-hosted options, see our [installation guide](https://docs.ctrlplane.dev
8080
## 📚 Documentation
8181

8282
- [Quickstart](https://docs.ctrlplane.dev/quickstart) — Deploy your first service in 15 minutes
83-
- [Core Concepts](https://docs.ctrlplane.dev/concepts/introduction) — Systems, deployments, environments, resources
83+
- [Core Concepts](https://docs.ctrlplane.dev/concepts/overview) — Systems, deployments, environments, resources
8484
- [Policies](https://docs.ctrlplane.dev/policies/overview) — Approvals, verification, gradual rollouts
8585
- [Integrations](https://docs.ctrlplane.dev/integrations/cicd) — GitHub Actions, ArgoCD, Kubernetes
8686

apps/relay/.air.toml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
root = "."
2+
testdata_dir = "testdata"
3+
tmp_dir = "tmp"
4+
5+
[build]
6+
args_bin = []
7+
bin = "./tmp/main"
8+
cmd = "go build -o ./tmp/main . && chmod +x ./tmp/main"
9+
delay = 1000
10+
exclude_dir = ["assets", "tmp", "vendor", "testdata"]
11+
exclude_file = []
12+
exclude_regex = ["_test.go"]
13+
exclude_unchanged = false
14+
follow_symlink = false
15+
full_bin = "sh -c 'set -a; [ -f ../../.env ] && . ../../.env; set +a; exec ./tmp/main'"
16+
include_dir = []
17+
include_ext = ["go", "tpl", "tmpl", "html"]
18+
include_file = []
19+
kill_delay = "60s"
20+
log = "build-errors.log"
21+
poll = false
22+
poll_interval = 0
23+
rerun = false
24+
rerun_delay = 500
25+
send_interrupt = true
26+
stop_on_root = false
27+
28+
[color]
29+
app = ""
30+
build = "yellow"
31+
main = "magenta"
32+
runner = "green"
33+
watcher = "cyan"
34+
35+
[log]
36+
main_only = false
37+
time = false
38+
39+
[misc]
40+
clean_on_exit = false

apps/relay/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package relay
1+
package main
22

33
import (
44
"context"

0 commit comments

Comments
 (0)