# 开发与构建执行环境

本文档是以下事项的权威出处：

- NC01、D601 与 Master server 的构建执行面边界；
- 持久化 `unidesk-dev` 环境；
- 公开开发前端端口；
- `deploy apply --env dev`；
- Rust backend-core 构建边界。

发布线和开发 lane 治理由 `docs/reference/release-governance.md` 与
[GitHub issue #6](https://github.com/pikasTech/unidesk/issues/6) 负责。
同一规则需要出现在其他入口时，详细规则保留在本文档，其他文档只留简短交叉引用。

## 目标

开发环境用于在不干扰生产环境的前提下体验下一版本 UniDesk：

- 生产环境继续使用 `http://74.48.78.17:18081/` 的正常公开前端。
- 开发环境通过独立的 Master server 端口 `http://74.48.78.17:18083/` 暴露。
- 开发后端和前端工作负载：
  - 运行在 D601 原生 k3s 的 `unidesk-dev` namespace；
  - 不运行在 Master server Compose stack。
- 开发 backend-core 和前端 rollout：
  - 使用 `origin/master:deploy.json#environments.dev` 中已推送的 Git commit；
  - 不使用脏 worktree。
- Rust backend-core 检查和构建：
  - 仍通过 `ci publish-backend-core` 使用其拥有的 D601 CI；
  - 开发 CD 只消费已发布镜像，不编译 Rust。
- Master server 唯一的构建例外是经过审查并显式限制并发的 backend-core 主服务上线操作。

## 通用构建执行面

- Master server 只负责轻量源码编辑、Git 操作、状态观察和受控调度。
- 通用 Docker 镜像、仓库级检查、浏览器验证及 Rust/Go/前端重型构建默认使用 NC01。
- D601 不再是通用构建首选，只在以下事实明确成立时使用：
  - owning CI 或 Tekton 流水线固定运行在 D601；
  - 目标产物必须进入 D601 node-local registry 或原生 k3s；
  - 任务需要 D601 自有硬件、workspace 或运行面；
  - 用户明确指定 D601。
- D601 离线不得阻塞与 D601 无关的通用镜像构建；此类任务直接切到 NC01。
- NC01 上的临时构建目录和容器只用于验证，不成为源码或部署真相。
- 构建产物必须回到项目声明的镜像标签、registry、Git 或可审计交付路径。

## D601 UniDesk 工作区

`D601:UniDesk` 的固定开发 workspace 是 D601 节点上的 `/home/ubuntu/workspace/unidesk-dev`，固定使用 `master` 分支和 `origin git@github.com:pikasTech/unidesk.git`。所有需要在 D601 上改 UniDesk 代码、做轻量语法/命令形态验证、验证 `trans`/`tran`/Code Queue runner、收敛分布式敏捷实验补丁的工作，都应先进入这个目录。

每次开始 D601 UniDesk 分布式开发、切换任务、恢复中断或上下文压缩后，先通过 UniDesk SSH 维护桥执行：

```bash
trans D601:/home/ubuntu/workspace/unidesk-dev git status --short --branch
trans D601:/home/ubuntu/workspace/unidesk-dev git remote -v
```

若路径、分支或 remote 不符合预期，先修正 fixed workspace，再继续。`/home/ubuntu/cq-deploy`、Code Queue pod 内 `/root/unidesk`/`/app`、D601 上的 `/root/unidesk` 和 `/tmp/unidesk-*` 只作为部署副本、运行副本或临时实验面；运行面热修可以直接作用在 pod/容器，但必须随后把持久化修复提交到 Git remote，并在 fixed workspace 中复验。

固定 workspace 只作为 source truth 预检、fetch、受控 worktree 创建和最终同步入口。实际开发、文档修改、测试补丁和 PR 准备应在固定 repo 下的独立 worktree 中完成，例如 `/home/ubuntu/workspace/unidesk-dev/.worktree/<task>`；该 worktree 必须通过 `bun scripts/cli.ts dev-env worktree add .worktree/<task> --branch <branch> --from origin/master` 从最新 `origin/master` 创建，让 `.worktreecopy` 中声明的本地配置白名单自动复制到新 worktree。使用任务专属分支或 detached worktree 隔离当前改动，结束前用 `git status` 确认只包含本任务文件。不要把 `/home/ubuntu/workspace/unidesk-dev` 根目录当作并行任务 scratch 区，也不要复用其他任务遗留 worktree。

- Master server 不作为 UniDesk 重型验证机：
  - 默认执行面是 NC01、CI runner 或目标运行面；
  - 重型验证包括仓库级 check 和 Playwright/browser smoke；
  - 重型构建包括镜像构建和 Rust/Go 编译；
  - Code Queue runner 实测也遵循同一执行面边界；
  - 只有 owning pipeline 或目标运行面固定属于 D601 时才使用 D601；
  - 唯一例外是用户或 issue 明确要求的 backend-core 主服务上线；
  - 该例外使用 `CARGO_BUILD_JOBS=1`、`--jobs 1` 或 CLI 内置等价方式限制并发；
  - 结果必须用异步 job/status/health 证据回写 issue。

`scripts/cli.ts`、`scripts/trans`、`scripts/tran`、`scripts/src/ssh.ts` 和相邻的 `trans`/`tran`/SSH helper 是主 server 上人工与 Codex 高频使用的控制入口；这类客户端工具链改进可以直接在 master server `/root/unidesk` 轻量修改、提交并推送到 `origin/master`。该例外只覆盖 CLI/trans/tran 客户端源码、帮助、语法/命令形态验证和对应 reference 文档，不覆盖 `src/components/provider-gateway` 行为变更、镜像构建、仓库级 check、浏览器 smoke 或其他重型验证。除非用户明确要求，CLI 改动不做单元测试、合同测试或新增测试脚本。涉及 provider-gateway 代码时仍必须遵循 provider-gateway 版本和远程升级规则。

当 `trans`/`tran`/SSH 透传的文件传输、stdin、chunk、编码、timeout 或 route/operation 解析出现高频摩擦时，先优化 CLI 客户端的分块、校验、重试、可观测输出和帮助文档，并用目标 provider/pod/Windows route 的最小闭环证明；只有证据显示 client 侧无法规避 provider-gateway 边界时，才进入 provider-gateway 变更流程。

## Public Dev Frontend Port

The main server owns one extra public entrypoint for dev UI:

```text
browser -> main-server:18083 -> dev-frontend-proxy -> prod backend-core microservice proxy -> k3sctl-adapter -> D601 k3s Service frontend-dev -> frontend-dev -> backend-core-dev
```

`dev-frontend-proxy` is an nginx sidecar in the main-server Compose project. It proxies requests to `backend-core:8080/api/microservices/k3sctl-adapter/proxy/api/services/frontend-dev/proxy...`, so D601 does not expose a new public port and the dev UI still crosses the existing UniDesk/k3sctl-adapter control boundary. The proxy is intentionally thin: it does not build frontend assets, does not talk to D601 directly, and does not contain DevOps logic.

`frontend-dev` and `backend-core-dev` are registered with `k3sctl-adapter` through the managed-service catalog `src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-core.k3s.json`. The public dev port must use that cataloged Kubernetes API service-proxy path; it must not add a direct D601 public port, NodePort, or backend-core catalog entry for arbitrary k3s services.

The dev public port is configured in `config.json` as `network.devFrontend.port=18083`, surfaced by `server status` as `urls.devFrontend`, and managed by `server rebuild dev-frontend-proxy`. The proxy health depends on `frontend-dev`; it can be unhealthy until the D601 dev frontend has been deployed.

The unrestricted public network entries are therefore production frontend, dev frontend, and provider ingress. backend-core REST, PostgreSQL, user-service backend ports, k3s Services, NodePorts and D601 host ports remain private or explicitly restricted.

Dev and production frontend authentication must use the same `config.json.auth` username, password, session secret and session TTL. The public dev and production entrypoints share the same IP/host with different ports, so the `unidesk_session` cookie is host-scoped rather than port-scoped. `deploy apply --env dev --service frontend` must sync `unidesk-dev-runtime-secrets` and `unidesk-dev-runtime-config` from the main-server config before rolling out `frontend-dev`; dev manifests may contain placeholders but must not establish a separate dev login identity.

## Desired State

`deploy.json` remains the only version intent file. Dev entries live under `environments.dev` and are read from `origin/master:deploy.json`, never from a dirty local file, when using `--env dev` or `ci run-dev-e2e`.

The target release-governance model is to split stable maintenance validation from high-risk master integration, for example with explicit lanes such as `dev-v1` and `dev-master`. That split is not active until `deploy.json`, deploy commands, CI, frontend labels and diagnostics support it explicitly. Until then, the documented `environments.dev` behavior remains the active contract and must not be emulated through local manifest edits or hidden branch conventions.

During a `release/v1` stabilization window, this same implemented `environments.dev` lane is temporarily reserved for v1 validation. Use pushed commits and explicit `deploy.json` pins to validate v1 fixes; do not add a parallel `dev-v1`/`dev-master` schema in the middle of the stabilization window unless that split is the blocker for v1. The detailed phase rule lives in `docs/reference/release-governance.md`.

The persistent dev rollout currently supports:

- `backend-core`, `frontend`, `mdtodo`, `claudeqq` and `code-queue` as D601 registry artifact consumers in `unidesk-dev`. Decision Center moved to the NC01 YAML-first k8s lane and is no longer a current D601 persistent dev workload.
- `baidu-netdisk` as the main-server direct user-service artifact validation sample.

`deploy apply --env dev --service baidu-netdisk` consumes the D601 registry artifact and validates the main-server Compose service; it is not a persistent D601 k3s dev workload. `deploy apply --env dev --service code-queue` is intentionally dev-only and may mutate only `unidesk-dev` Code Queue scheduler/read/write/provider-egress-proxy objects. `deploy apply --env prod --service code-queue` must remain unsupported. The `environments.dev.ci` declaration and short launcher runner are owned by `docs/reference/dev-ci-runner.md`.

## Rust Backend-Core Boundary

backend-core is implemented as a Rust service. The default dev and CI path compiles backend-core on D601 CI and consumes commit-pinned artifacts. The master server may inspect files, run concrete-file lightweight syntax checks, dispatch jobs and proxy traffic, but it must not run repository-level checks, Compose checks or Rust compilation for ordinary backend-core iteration.

Narrow production-online exception: when a user or issue explicitly asks to put the current backend-core fix online on the main-server Compose runtime, master server may run backend-core-only Rust compilation with constrained parallelism (`CARGO_BUILD_JOBS=1`, `--jobs 1`, or the CLI's equivalent setting) and must use async job/status/health evidence. This exception does not allow repository-wide checks, Rust tests, Go builds, frontend builds, or other service builds on the master server.

Allowed on the master server:

- `git diff --check` and `bun --check <specific-file>`
- `bun scripts/cli.ts check --help`
- `bun scripts/cli.ts deploy plan --env dev --service backend-core`
- `bun scripts/cli.ts deploy apply --env dev --service backend-core`
- `bun scripts/cli.ts ci run --revision <commit>`
- `bun scripts/cli.ts ci run-dev-e2e --wait-ms <ms>`
- for reviewed backend-core main-server online only: backend-core-specific `cargo check`/build with `CARGO_BUILD_JOBS=1`, or `bun scripts/cli.ts server rebuild backend-core` followed by `job status` polling and health verification

Not allowed on the master server for this path:

- repository-wide `cargo check`, `cargo build`, `cargo test`, `rustfmt`, or any Rust command outside the backend-core main-server online exception.
- `bun scripts/cli.ts check --rust` without the D601 CI guard.
- `bun scripts/cli.ts server rebuild backend-core` as a way to iterate Rust backend-core or replace D601 CI artifact flow.
- Ad-hoc `docker build` of `src/components/backend-core/Dockerfile` on the master server outside the controlled CLI rebuild exception.

`check --rust` remains a D601 CI/dev-execution command: `UNIDESK_D601_RUST_CHECK=1 bun scripts/cli.ts check --full --rust`. It deliberately fails outside that guard with an explicit explanation instead of silently compiling on the wrong host; the main-server online exception is handled by the backend-core-specific build/rebuild path, not by weakening `check --rust`.

## Dev Deploy Path

`deploy apply --env dev --service backend-core|frontend|mdtodo|claudeqq|code-queue` is the controlled persistent dev rollout path for D601 dev workloads. The controller runs on the master server, but dev CD is a pull-only artifact consumer. All listed services consume CI-published commit-pinned artifacts from the D601 registry. Decision Center uses the NC01 k8s lane and GitHub storage checks instead of this D601 dev path.

1. Fetch `origin/master:deploy.json#environments.dev` and resolve the requested service commit to a full SHA.
2. Dispatch to D601 through the existing provider-gateway/Host SSH maintenance capability.
3. Require the existing registry image `127.0.0.1:5000/unidesk/<service-id>:<commit>` produced by `ci publish-backend-core` for backend-core or `ci publish-user-service --service <service-id>` for user services.
4. Verify the registry manifest and image labels for service id, source commit and Dockerfile. The dry-run plan exposes the registry image, planned digest source, target, source commit and `build.willCompile=false`.
5. Import the registry artifact into native k3s containerd at `/run/k3s/containerd/containerd.sock`.
6. Apply only the selected `unidesk-dev` Service/Deployment objects from the dev manifest.
7. For `frontend`, sync auth/session settings from main-server `config.json.auth` into the dev runtime Secret/ConfigMap before rollout.
8. Stamp the Deployment with `UNIDESK_DEPLOY_*` env and `unidesk.ai/deploy-*` annotations.
9. Verify health through the Kubernetes API service proxy and require the live commit to match the requested commit.

The dev path is not a fallback system. If artifact lookup, label verification, native k3s, containerd import, kubectl apply or live health verification fails, the job fails with logs. It must not fall back to `cargo build`, `docker build`, building on the master server, building source on the dev target, using a dirty worktree, direct D601 public ports, NodePort, hostPort, provider-gateway business HTTP, or another deployment command. k3s-managed health verification must use the Kubernetes API service proxy.

## DevOps Hygiene

The persistent dev environment follows the shared Git-backed deployment hygiene rules in `docs/reference/devops-hygiene.md`. In particular, D601 runtime edits, dirty-worktree builds, copied scripts/images/source, direct D601 ports, NodePorts and manual smoke checks without live commit agreement must not become deployment truth.

## Standard Workflow

Use this sequence for backend-core Rust and frontend dev work:

1. Preflight the fixed workspace, then create the task-scoped worktree with `bun scripts/cli.ts dev-env worktree add .worktree/<task> --branch <branch> --from origin/master`; keep unrelated parallel changes separated with `git status`/`git diff`.
2. Master server 只执行 diff 审查和具体文件的轻量语法检查。
   - 轻量语法检查示例是 `bun --check <specific-file>`。
   - 仓库级检查和类型检查默认在 NC01、CI 或目标运行面执行。
   - Compose 检查、前端检查和 Rust 检查遵循同一执行面边界。
   - 仅 D601 owning pipeline 使用 D601。
3. Commit the code from the task worktree and merge/push it to `origin/master` through the chosen lightweight PR or direct integration path; `deploy apply --env dev` cannot deploy unpushed local changes.
4. Update `deploy.json` `environments.dev.services` so `backend-core` and `frontend` point at the pushed commit, then commit and push that manifest update.
5. Preflight backend-core publication: `bun scripts/cli.ts ci publish-backend-core --commit <full-sha> --dry-run`. The result must have no `blockedScopes`, `wouldBuildOnD601=true`, D601 `unidesk-ci` Tekton runner metadata, D601 registry target `127.0.0.1:5000/unidesk/backend-core`, required labels for service id/source repo/source commit/Dockerfile, and `recommendedAction` pointing to the real publish command.
6. Publish the artifact first: `bun scripts/cli.ts ci publish-backend-core --commit <full-sha> --wait-ms 1200000` for backend-core, or `bun scripts/cli.ts ci publish-user-service --service <frontend|decision-center|mdtodo|claudeqq|code-queue> --commit <full-sha> --wait-ms 1200000` for user services.
7. Verify the publish output contains non-empty `artifactSummary.digest` and `artifactSummary.digestRef`, and that the pushed image labels match `backend-core`, the source repo, source commit and Dockerfile. This verification can use the publish output and the D601 registry manifest HEAD; it must not rebuild.
8. Run `bun scripts/cli.ts deploy apply --env dev --service backend-core --dry-run` and confirm `artifactConsumer.noRuntimeSourceBuild=true`, `build.willCompile=false`, the registry image is `127.0.0.1:5000/unidesk/backend-core:<commit>`, and the target is `unidesk-dev/backend-core-dev`.
9. Run `bun scripts/cli.ts deploy apply --env dev --service backend-core` and observe the returned job with `bun scripts/cli.ts job status <jobId> --tail-bytes 30000`.
10. Run `bun scripts/cli.ts deploy apply --env dev --service <frontend|decision-center|mdtodo|claudeqq|code-queue>` and observe the job the same way; this must consume the registry artifact and verify live deploy metadata through the service health path.
11. If the dev service catalog changes, deploy the pushed `k3sctl-adapter` commit through the controlled local manifest exception, then verify `/api/control-plane` lists `k3s/dev/unidesk-dev-core.k3s.json`.
12. Rebuild or verify `dev-frontend-proxy` on the main server with `bun scripts/cli.ts server rebuild dev-frontend-proxy` when the proxy config or port changes.
13. Manually test `http://74.48.78.17:18083/` and the dev health endpoints.
14. Run D601 CI for the commit and the dev smoke runner: `bun scripts/cli.ts ci run --revision <commit> --wait-ms <ms>` and `bun scripts/cli.ts ci run-dev-e2e --wait-ms <ms>`. When Code Queue behavior changes, update the `code-queue` entry in `environments.dev.services` to the pushed commit before running dev artifact validation or the temporary dev smoke.

## Validation Commands

Useful read-only or bounded validation commands:

```bash
bun scripts/cli.ts server status
bun scripts/cli.ts deploy plan --env dev
bun scripts/cli.ts deploy plan --env dev --service backend-core
bun scripts/cli.ts dev-env validate --manifest src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-core.k8s.yaml
bun scripts/cli.ts dev-env validate --manifest src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-mdtodo.k8s.yaml
bun scripts/cli.ts dev-env validate --manifest src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-claudeqq.k8s.yaml
bun scripts/cli.ts dev-env validate --manifest src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-code-queue.k8s.yaml
bun scripts/cli.ts ci run-dev-e2e --wait-ms 600000
bun scripts/cli.ts microservice proxy k3sctl-adapter /api/services/backend-core-dev/proxy/health --raw --full
bun scripts/cli.ts microservice proxy k3sctl-adapter /api/services/frontend-dev/proxy/health --raw --full
curl -fsS http://127.0.0.1:18083/health
```

When validating on D601 directly, always use the native kubeconfig explicitly: `KUBECONFIG=/etc/rancher/k3s/k3s.yaml`. The default `kubectl` context may point at Docker Desktop and is not valid for UniDesk native k3s verification.
