myxce/.kiro/steering/tech.md
Rongsong Shen f5fbc6bcac
feat(eliminate-frontend-makefile): task 3.3 - update live documentation (11 files)
Removes every live current-fact reference to src/frontend/Makefile
targets or Makefile-specific fixed paths across 11 docs (steering,
frontend/CLAUDE.md, root CLAUDE.md, deployment docs, and two skill
docs), replacing with the Meson-based equivalents established by
tasks 1-3.2: /xce-build apiserver, meson test --suite apiserver,
direct tests/regression/run.sh invocation.

Round-1 review rejected the first pass: xce-deploy-ha/SKILL.md had
over-corrected by deleting all mention of deploy-ha.sh's still-real
/tmp/apiserver legacy fallback (that script's discovery logic is
unchanged, unlike run-resource-verify.sh's, which genuinely lost its
fallback in task 3.1 -- xce-test-resources/SKILL.md's identical-
looking edit was correct for that reason). Fixed by restoring an
accurate, Makefile-free description of the real fallback at all four
touched sites. Re-reviewed and approved.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XYdtrEWWZfKRRGED7raEYg
2026-09-03 14:22:54 +00:00

101 lines
6 KiB
Markdown

# Technology Stack
## Architecture
```
xcecli (Go/Cobra) ──REST──► apiserver (Go/Gin) ──CGO──► C daemon layer
controller / scheduler / worker / autoscaler
↑↑↑ all linked against libxce (src/lib/)
```
Request path inside apiserver: `Gin Router → Middleware (WhitelistURL → WhitelistIP → RateLimit → JWT → CORS) → RBAC Check → Controller → Services → In-Memory Store`
All controller state is in-memory. No persistent database in the API tier; job/queue/host state is pushed live into the in-memory stores from the C controller backend over CGO (see Key Technical Decision #2), not loaded from a file. C daemons communicate via TCP using a custom messaging layer: iomgr (epoll-based I/O loop), vtaskmgr (thread pool for packet dispatch), and xce_request/xce_reply for non-blocking send/receive. WAL + checkpoint provide persistence at the controller level.
## Core Technologies
- **Go 1.23.4** — apiserver (REST API) and xcecli (CLI). Two independent Go modules, no `go.work`.
- **C (gnu17)** — controller, worker, scheduler, autoscaler, libxce. No C++.
- **Gin v1.10.0** — HTTP router, middleware, binding
- **Cobra v1.9.1** — CLI framework for xcecli
- **Zap v1.27.0** — structured logging throughout (both Go modules)
- **Viper v1.19.0 / v1.20.1** — YAML config management
- **Cap'n Proto** — wire serialization for WAL and daemon-to-daemon replication
- **iomgr / vtaskmgr / delaymgr** — libxce async I/O framework: single-threaded epoll loop (iomgr), thread-pool packet dispatch (vtaskmgr), timer thread for periodic/blocking tasks (delaymgr)
## Build Systems
| System | Scope |
|--------|-------|
| **Meson ≥ 1.5** | C daemons + Go modules via `tools/go_build` wrapper — sole build/test path for apiserver/xcecli |
| **Nix flakes** | Hermetic dev environment, AppImage packaging |
```bash
# Full build (C + Go, debug + ASAN)
/xce-build
# Go development loop (apiserver + xcecli)
/xce-build apiserver # builds both binaries + runs unit tests
meson test -C <build_dir> --suite apiserver # CGO-backed backend tests
XCE=<build_dir>/frontend/xcecli/xcecli URL=http://localhost:8080 \
src/frontend/tests/regression/run.sh # regression suite
# Nix package builds (from src/)
nix build .#xcecore # C daemons + apiserver
nix build .#xcecore_debug # debug + ASAN
nix build .#xcecli # CLI only
```
## Development Standards
### Controller Pattern (Go)
```go
// Struct: {Resource}Controller (typically an empty struct{})
type JobController struct{}
// Handler: {Action}{Resource}
func (j JobController) CreateJob(ctx *gin.Context) {
// Validate input
var req models.JobSubmitRequest
if err := utils.BindJSONStrict(ctx, &req); err != nil { ReturnError(ctx, code, err.Error(), nil); return }
parsedIndices, err := preCheckJobRequest(&req)
if err != nil { ReturnError(ctx, code, err.Error(), nil); return }
// Business logic — package-level services function, not a controller field
err = services.SubmitJob(&newJob, arraySize)
if err != nil { ReturnError(ctx, code, err.Error(), nil); return }
ReturnSuccess(ctx, code, "submitted", result)
}
```
Early return on every error. Log with zap fields before returning.
### Testing Requirements
- **TDD mandatory**: Write failing test first, then implementation.
- **Go unit tests**: Table-driven, no external dependencies, `t.TempDir()` for fixtures.
- **C tests**: Add test case in `testsuite/` before modifying implementation.
- `/xce-build apiserver`'s unit-test step must pass without a live server.
- `tests/regression/run.sh` requires `XCE` + `URL` env vars.
### Code Formatting
- Go: `gofmt` / `goimports` (post-edit hooks configured)
- C: `clang-format` using project config at `xce/.clang-format`
### Auth and RBAC
- Auth backend set in `config/auth.yaml` (`provider: config_file | pam | ldap | oauth2`). Only `config_file` and `pam` (Linux + CGO) are functional; `ldap` and `oauth2` are documented as future/stub providers whose `Authenticate()` always returns a "not yet implemented" error.
- Permissions are a plain action string (e.g. `"job:view"`, `"queue:submit"`) paired with a separate structured `domain` list (e.g. `{type: self}`, `{type: all}`) in `rbac.yaml` — not a combined `"action:scope"` string. `controllers.RequirePermission()` checks the action string only; domain/scope is evaluated separately.
- RBAC loaded from `config/rbac.yaml`, enforced by `controllers.RequirePermission()` middleware.
## Key Technical Decisions
1. **No Go workspace** — `apiserver` and `xcecli` are independent modules; changes to shared types require updating both.
2. **In-memory API state** — no database in Go tier; `store.InitStores()` allocates empty per-resource stores at startup, and job/queue/host/etc. state is then pushed in live from the C controller backend over CGO (`backend.RegisterToBackend()` + `backend.StartNotificationListener()` in `cmd/main.go`). Only RBAC (`config/rbac.yaml`) and auth (`config/auth.yaml`) are actually loaded from YAML at startup.
3. **CGO bridge** — `backend/` package wraps C library calls; unit tests run `CGO_ENABLED=0`, backend tests need `CGO_ENABLED=1` inside nix dev shell.
4. **Swagger-first API docs** — `swaggo/swag` annotations on handlers; docs served at runtime by Gin.
5. **Structured logging** — every log entry carries context via `zap.String()`, `zap.Error()`. Never use `fmt.Println` for operational output.
6. **Single-writer HA with full Raft log replication** — controller is always one active primary; standby election and log replication use a Raft protocol (term-based voting, freshness gates, `AppendEntries` request/reply, per-peer `next_index[]`/`match_index[]` progress vectors, `(term,index)` log matching/truncation, commit-index advance) implemented in the `src/lib/raft/` shared module (`raft.c`/`raft.h`) and validated by the `raft-log-replication`, `raft-commit-safety`, `raft-ha-core-safety`, and `ha-term-safety` specs.