From f309c094b78f81ba8344e2f5d1911433d9b09149 Mon Sep 17 00:00:00 2001 From: toki Date: Thu, 28 May 2026 10:45:43 +0900 Subject: [PATCH] feat: add control-plane and portal domain rules, update project rules - Add control-plane domain rule - Add portal domain rule - Update edge domain rule - Update node domain rule - Update platform-common domain rule - Update testing domain rule - Update project rules --- .../project/domain/control-plane/rules.md | 62 ++++++++++++++++++ agent-ops/rules/project/domain/edge/rules.md | 29 +++++++-- agent-ops/rules/project/domain/node/rules.md | 25 ++++++-- .../project/domain/platform-common/rules.md | 23 ++++--- .../rules/project/domain/portal/rules.md | 64 +++++++++++++++++++ .../rules/project/domain/testing/rules.md | 18 +++--- agent-ops/rules/project/rules.md | 21 +++--- 7 files changed, 201 insertions(+), 41 deletions(-) create mode 100644 agent-ops/rules/project/domain/control-plane/rules.md create mode 100644 agent-ops/rules/project/domain/portal/rules.md diff --git a/agent-ops/rules/project/domain/control-plane/rules.md b/agent-ops/rules/project/domain/control-plane/rules.md new file mode 100644 index 0000000..7975293 --- /dev/null +++ b/agent-ops/rules/project/domain/control-plane/rules.md @@ -0,0 +1,62 @@ +--- +domain: control-plane +last_rule_review_commit: 6e1c201d0b82661465238821edb136444eacb9d0 +last_rule_updated_at: 2026-05-28 +--- + +# control-plane + +## 목적 / 책임 + +여러 Edge를 관찰하고 운영 제어할 중앙 제어면 영역이다. 현재는 health/readiness HTTP, 환경별 설정 로딩, Portal-Control Plane proto-socket WebSocket hello baseline을 제공하며, Node 직접 연결이나 직접 스케줄링은 책임으로 삼지 않는다. + +## 포함 경로 + +- `apps/control-plane/cmd/control-plane/` — control-plane CLI 진입점, 설정 로딩, HTTP health/readiness 서버, wire server lifecycle +- `apps/control-plane/internal/wire/` — Control Plane wire protocol 상수와 Portal WebSocket proto-socket endpoint +- `apps/control-plane/README.md` — Control Plane 현재 상태와 계획된 운영 책임 설명 +- `apps/control-plane/Dockerfile` — Control Plane 배포용 이미지 빌드 표면 + +## 제외 경로 + +- `apps/edge/` — Edge-local Node registry, routing, input surface, stream relay의 소유자 +- `apps/node/` — 실제 adapter execution과 runtime session의 소유자 +- `apps/portal/` — Flutter 운영 클라이언트 구현 영역 +- `apps/worker/` — 비동기 작업 처리 예정 영역 +- `packages/` — 여러 앱이 공유하는 공통 패키지 +- `proto/` — 메시지 계약 원본과 생성물 +- `configs/` — 앱별 설정 예시와 공통 설정 계약 확인 영역 + +## 주요 구성 요소 + +- `rootCmd()` / `serveCmd()` — `control-plane serve` command와 기본 config path 구성 +- `controlPlaneConfig` — HTTP listen, wire listen, DB, Redis, logging 설정 구조 +- `loadConfig()` / `applyEnvOverrides()` — YAML 설정 로딩과 `IOP_*` 환경 변수 override +- `run()` — health/readiness HTTP server와 Portal wire server lifecycle 조립 +- `wire.Protocol` — Control Plane 통신 표준을 `protobuf-socket`으로 고정하는 상수 +- `wire.Endpoint` — reserved wire endpoint 설정 타입 +- `wire.PortalServer` — `/portal` WebSocket proto-socket 서버와 `PortalHelloRequest` 처리 + +## 유지할 패턴 + +- Control Plane은 Edge를 통해 시스템을 관찰/제어한다. Node를 직접 등록하거나 직접 스케줄링하는 active contract를 만들지 않는다. +- `net/http`는 health/readiness/bootstrap 같은 보조 endpoint에 우선 사용하고, IOP 고유 운영 통신은 proto-socket 기반 wire protocol로 확장한다. +- Portal-Control Plane 브라우저/앱 경계는 WebSocket/WSS proto-socket을 사용할 수 있다. Edge-Node TCP transport 기준을 이 경계에 억지로 적용하지 않는다. +- `ScheduleRequest`/`ScheduleResponse`는 legacy placeholder로만 취급하고, 새 orchestration 계약은 Edge-owned runtime state를 우회하지 않도록 다시 설계한다. +- Control Plane 설정에 실제 환경값, credential, private endpoint를 tracked 문서에 쓰지 않는다. 환경별 값은 private rule 라우팅을 따른다. +- proto 계약을 바꾸면 `proto/iop/*.proto`를 먼저 수정하고 Go 생성물을 명령으로 갱신한다. Portal/Client Dart 계약에 닿으면 `make proto-dart`도 함께 실행한다. + +## 다른 도메인과의 경계 + +- **edge**: Edge는 로컬 실행 그룹 상태와 Node registry를 소유한다. Control Plane은 Edge를 통해 상태 조회, 설정 변경, 명령 전달, 이벤트 수신을 확장한다. +- **portal**: Portal은 운영 UI와 client-side wire connection을 소유한다. Control Plane은 `/portal` wire endpoint와 서버 응답 계약을 제공한다. +- **platform-common**: protobuf 원본, 생성물, 공통 설정/관측성 helper는 platform-common 계약을 따른다. +- **testing**: Control Plane command, wire endpoint, bootstrap/enrollment 사용자 흐름을 바꾸면 testing domain rule의 검증 기준을 따른다. + +## 금지 사항 + +- Control Plane에서 Node를 직접 연결하거나 직접 스케줄링하는 경로를 제품 기본 계약으로 만들지 않는다. +- Edge-local registry, run dispatch, stream relay 구현을 Control Plane으로 복제하지 않는다. +- Portal 전용 UI state나 화면 정책을 Control Plane 서버 내부 책임으로 끌어오지 않는다. +- gRPC를 Control Plane 기본 wire protocol로 도입하지 않는다. +- 실제 DB/Redis credential이나 환경별 endpoint를 tracked docs/rules에 기록하지 않는다. diff --git a/agent-ops/rules/project/domain/edge/rules.md b/agent-ops/rules/project/domain/edge/rules.md index 006a8d0..5c8f926 100644 --- a/agent-ops/rules/project/domain/edge/rules.md +++ b/agent-ops/rules/project/domain/edge/rules.md @@ -1,18 +1,18 @@ --- domain: edge -last_rule_review_commit: 01bef3dc933e225b09d0f348aab6b0097275a4d8 -last_rule_updated_at: 2026-05-21 +last_rule_review_commit: 6e1c201d0b82661465238821edb136444eacb9d0 +last_rule_updated_at: 2026-05-28 --- # edge ## 목적 / 책임 -여러 Node를 하나의 로컬 실행 그룹으로 묶는 백엔드 실행 그룹 컨트롤러 영역이다. node 연결을 수락하고 token 기반 등록을 검증한 뒤 adapter/runtime 설정을 내려주며, ops console, OpenAI-compatible HTTP, A2A JSON-RPC 입력을 내부 `adapter + target` 실행 요청으로 수렴시킨다. +여러 Node를 하나의 로컬 실행 그룹으로 묶는 백엔드 실행 그룹 컨트롤러 영역이다. node 연결을 수락하고 token 기반 등록을 검증한 뒤 adapter/runtime 설정을 내려주며, `iop-edge` command 중심의 local/field 운영 UX, ops console, OpenAI-compatible HTTP, A2A JSON-RPC 입력을 내부 `adapter + target` 실행 요청으로 수렴시킨다. ## 포함 경로 -- `apps/edge/cmd/edge/` — edge CLI 진입점과 serve 커맨드 +- `apps/edge/cmd/edge/` — edge CLI 진입점과 serve/console/config/env/setup/node/nodes/smoke 커맨드 - `apps/edge/internal/bootstrap/` — fx 의존성 주입과 서버 시작/종료 lifecycle - `apps/edge/internal/events/` — run/node event in-process fanout bus - `apps/edge/internal/input/` — OpenAI-compatible/A2A 입력 서버 lifecycle 관리 @@ -26,7 +26,8 @@ last_rule_updated_at: 2026-05-21 ## 제외 경로 - `apps/node/` — 실제 모델 실행과 adapter 관리 -- `apps/control-plane/` — 여러 Edge 연결 관리와 운영 제어 API 제공 예정 영역 +- `apps/control-plane/` — 여러 Edge 연결 관리와 운영 제어 API 제공 영역 +- `apps/portal/` — Flutter 운영 클라이언트 영역 - `apps/worker/` — 비동기 작업 처리 예정 영역 - `packages/` — 공통 설정/관측성/인증 패키지 - `proto/` — 메시지 계약 원본과 생성물 @@ -39,13 +40,20 @@ last_rule_updated_at: 2026-05-21 - `node.NodeStore` — 사전 등록된 `NodeRecord`를 token/ID로 조회; 설정 파일에서 seed - `node.NodeRecord` — 사전 등록된 node 정의 (ID, alias, token, adapter/runtime config) - `node.BuildConfigPayload()` — `NodeRecord`의 adapter 설정을 proto `NodeConfigPayload`로 변환하는 mapper +- `rootCmd()` / `resolveConfigPath()` — bundle-local `edge.yaml`, binary-adjacent config, repo-dev fallback을 처리하는 CLI entrypoint +- `config init` / `config check` / `config print` — bundle-local Edge 설정 생성·검증·출력 command +- `env` — config discovery, advertise host, log path, node bootstrap URL, OpenAI/A2A URL을 서버 기동 없이 출력하는 진단 command +- `node register` — `edge.yaml`의 `nodes[]`를 보존형 YAML patch로 추가/갱신하고 one-line bootstrap command를 출력하는 command +- `nodes list` — 설정된 node record를 offline/configured 상태로 조회하는 command +- `smoke openai` — `/healthz`, `/v1/models`, `/v1/chat/completions`를 확인하는 OpenAI-compatible 진단 command - `bootstrap.Module` — fx lifecycle에 `bootstrap.Runtime` start/stop을 연결 - `bootstrap.Runtime` — logger, registry, node store, event bus, service, transport server, input manager를 묶는 실행 조립체 - `events.Bus` — `RunEvent`와 `EdgeNodeEvent` subscriber fanout 및 bounded replay - `service.Service` — node 선택, run dispatch, cancel/terminate-session, node command 요청을 표면 중립 DTO로 제공 - `service.RunHandle` — foreground run event stream과 dispatch metadata를 함께 들고 있는 handle +- `service.NodeCommandView` / `UsageStatusView` — console/HTTP/RPC surface가 공유할 수 있는 node command 결과 DTO - `input.Manager` — OpenAI-compatible 서버와 A2A 서버 lifecycle 소유자 -- `openai.Server` — `/v1/models`, `/v1/chat/completions`, SSE stream을 `service.SubmitRun()`으로 연결하는 HTTP 표면 +- `openai.Server` — `/v1/models`, `/v1/chat/completions`, SSE stream, strict output policy, Ollama API passthrough를 `service`로 연결하는 HTTP 표면 - `a2a.Server` / `a2a.TaskStore` — A2A `message/send`, `tasks/get`, `tasks/cancel`과 task 상태 보관 - `opsconsole.Run` — edge-local console loop와 slash command 처리 - `opsconsole.EventRouter` — run/node event를 edge console 출력으로 라우팅 @@ -54,6 +62,9 @@ last_rule_updated_at: 2026-05-21 - edge는 사전 등록된 node 정의를 검증하고 연결 상태를 registry에 반영하는 역할을 먼저 안정화한다. - edge는 단순 gateway가 아니라 Node registry, adapter/profile configuration, routing, stream relay의 소유자다. +- 공식 local/field 운영 UX는 `iop-edge` command 표면에 모은다. repo helper script나 README 절차를 공식 사용자 경로로 승격하지 않는다. +- `config init`은 bundle-local `edge.yaml` template을 만들고, `env`는 서버를 기동하지 않고 effective environment를 설명해야 한다. +- `node register`는 사용자에게 `curl -fsSL | bash -s ` 한 줄을 출력하는 경로를 유지한다. 사용자가 기본 경로에서 `node.yaml`을 직접 만들거나 `iop-node serve --config ...`를 직접 실행하게 하지 않는다. - 외부 OpenAI-compatible HTTP API는 입력 표면일 뿐이며, 내부 실행 모델 전체를 대표하지 않는다. - node가 연결 직후 RegisterRequest를 보내고 edge가 RegisterResponse로 중앙 설정을 응답하는 흐름을 유지한다. - Registry는 동시성 안전성을 유지하고 외부로 내부 map을 노출하지 않는다. @@ -62,6 +73,8 @@ last_rule_updated_at: 2026-05-21 - 내부 실행 요청은 `adapter + target`으로 표현한다. 외부 API 호환 경계의 `model` 표현을 edge 내부 책임 전체로 확장하지 않는다. - ops console과 HTTP 입력 표면은 `apps/edge/internal/service`를 호출하는 얇은 어댑터로 유지한다. node 선택, run dispatch, command request 생성은 service 계층에서 공유한다. - OpenAI-compatible 경계의 `model`과 A2A 경계의 `Task`/JSON-RPC 표현은 입력 표면 안에서만 유지하고, edge 내부 실행은 `service.SubmitRun()`의 `adapter + target` 요청으로 변환한다. +- OpenAI-compatible `/v1/models`는 `openai.models`를 우선하고, 없으면 `openai.target`을 advertised model로 사용한다. 내부 target override와 외부 model echo 정책을 혼동하지 않는다. +- OpenAI/Ollama passthrough성 옵션은 입력 표면에서 명시적으로 변환하고, node adapter의 Ollama 실행 계약을 우회하지 않는다. - run/node event fanout은 `events.Bus`를 통해 수행하고, transport handler에서 console/HTTP 표면으로 직접 출력하거나 응답하지 않는다. - 입력 서버 lifecycle은 `input.Manager`가 소유하며, bootstrap runtime이 transport server와 함께 시작/종료한다. - `apps/edge/cmd/edge/**`, `apps/edge/internal/bootstrap/**`, `apps/edge/internal/transport/**`, `apps/edge/internal/service/**`, `apps/edge/internal/events/**`, `apps/edge/internal/input/**`, `apps/edge/internal/openai/**`, `apps/edge/internal/opsconsole/**`, `apps/edge/internal/node/**`, console/HTTP 입출력, run/node event relay를 바꾼 뒤에는 `testing` domain rule의 작업 후 검증 기준을 따른다. @@ -71,7 +84,8 @@ last_rule_updated_at: 2026-05-21 - **node**: edge는 node 내부 adapter를 직접 실행하지 않는다. edge는 사전 등록 정보와 연결 registry를 기반으로 요청을 보낼 대상과 실행 설정을 관리하고, TCP/protobuf로 `RunRequest`/`CancelRequest`/`NodeCommandRequest`를 보낸다. - **platform-common**: edge 설정, metrics, protobuf 타입은 platform-common 계약을 따른다. - **external input surfaces**: OpenAI-compatible HTTP와 A2A JSON-RPC는 edge inbound adapter이며, 내부 transport/protobuf 경계를 대체하지 않는다. -- **control-plane 후보**: control-plane은 Edge를 통해 시스템을 제어한다. Node 직접 연결/직접 스케줄링을 control-plane 책임으로 굳히지 않는다. +- **control-plane**: control-plane은 Edge를 통해 시스템을 제어한다. Node 직접 연결/직접 스케줄링을 control-plane 책임으로 굳히지 않는다. +- **portal**: portal은 Control Plane을 통해 운영 UI를 제공한다. Edge HTTP/OpenAI/A2A 입력 표면을 Portal UI state 소유권으로 확장하지 않는다. ## 금지 사항 @@ -79,5 +93,6 @@ last_rule_updated_at: 2026-05-21 - OpenAI-compatible HTTP API를 추가할 때 내부 TCP/protobuf 경계를 우회하지 않는다. - A2A/OpenAI/console 입력 표면에서 registry client에 직접 `RunRequest`를 조립·전송하지 않는다. 공유 로직은 `service.Service`에 둔다. - Control Plane 구현 전이라도 Node를 Control Plane에 직접 연결하는 경로를 edge 도메인에 추가하지 않는다. +- `node register`와 bootstrap UX에 named environment parameter 조합을 기본 사용자 경로로 노출하지 않는다. - gRPC 또는 WebSocket을 기본 내부 transport로 바꾸지 않는다. - `proto/gen/iop/*.pb.go` 생성 파일을 직접 수정하지 않는다. diff --git a/agent-ops/rules/project/domain/node/rules.md b/agent-ops/rules/project/domain/node/rules.md index 3651de6..87b3701 100644 --- a/agent-ops/rules/project/domain/node/rules.md +++ b/agent-ops/rules/project/domain/node/rules.md @@ -1,7 +1,7 @@ --- domain: node -last_rule_review_commit: 01bef3dc933e225b09d0f348aab6b0097275a4d8 -last_rule_updated_at: 2026-05-21 +last_rule_review_commit: 6e1c201d0b82661465238821edb136444eacb9d0 +last_rule_updated_at: 2026-05-28 --- # node @@ -25,8 +25,8 @@ Edge에 연결되어 실제 adapter execution을 수행하는 IOP 노드 에이 ## 제외 경로 - `apps/edge/` — Node를 관리하는 실행 그룹 컨트롤러 영역 -- `apps/control-plane/` — 여러 Edge 연결 관리와 운영 제어 API 제공 예정 영역 -- `apps/web/` — Web Portal 앱 영역 +- `apps/control-plane/` — 여러 Edge 연결 관리와 운영 제어 API 제공 영역 +- `apps/portal/` — Flutter 운영 클라이언트 영역 - `apps/worker/` — 비동기 작업 처리 예정 영역 - `packages/` — 여러 앱이 공유하는 공통 패키지 - `proto/` — 앱 간 메시지 계약 @@ -44,9 +44,13 @@ Edge에 연결되어 실제 adapter execution을 수행하는 IOP 노드 에이 - `adapters.Registry` — 어댑터 등록/조회 및 `LifecycleAdapter` start/stop lifecycle 관리 (실패 시 역순 롤백) - `adapters.LifecycleAdapter` — start/stop lifecycle이 필요한 어댑터의 optional 인터페이스 - `adapters.BuildFromPayload()` — edge에서 받은 `NodeConfigPayload`로 `Registry`를 초기화하는 factory -- `adapters/cli.CLI` — one-shot, persistent TUI, codex-exec, opencode-sse profile을 실행하는 CLI adapter +- `adapters/cli.CLI` — one-shot, persistent TUI, persistent-lazy, codex-exec, antigravity-print, opencode-sse profile을 실행하는 CLI adapter +- `adapters/cli.executeAntigravityPrint()` — Antigravity print mode conversation id를 IOP logical session별로 보관하고 resume_args로 후속 요청을 재개 +- `adapters/cli.executeOpencodeSSE()` — opencode serve HTTP/SSE session을 실행하거나 `--attach`로 외부 server에 연결해 delta를 relay +- `adapters/cli.executePersistent()` — terminal/persistent profile의 completion marker, idle timeout, output filter를 처리 - `adapters/cli/status` — claude/codex/antigravity CLI 상태 파서 (사용량 한도, reset 시각 등) - `adapters/cli.lineEmitter` — stdout 한 줄을 파싱해 `RuntimeEvent`를 반환하는 내부 인터페이스; `emitters.go`에서 format별로 등록 +- `adapters/ollama.Ollama` — Ollama `/api/chat` streaming, `/api/tags` capabilities, `/api/*` command passthrough를 처리하는 adapter - `store.Store` — 실행 상태와 결과 저장 ## 유지할 패턴 @@ -58,9 +62,14 @@ Edge에 연결되어 실제 adapter execution을 수행하는 IOP 노드 에이 - 실행 취소는 run ID 기준으로 `runManager`에 등록하고 실행 종료 시 반드시 `deregister`로 해제한다. - `CancelAction_CANCEL_RUN`은 현재 run 취소, `CancelAction_TERMINATE_SESSION`은 logical session 종료로 구분한다. - `NodeCommandRequest`는 실행 요청과 분리해 `USAGE_STATUS`, `CAPABILITIES`, `SESSION_LIST`, `TRANSPORT_STATUS` 같은 조회/제어성 명령으로 처리한다. +- `OLLAMA_API` command는 Ollama adapter 내부의 제한된 `/api/*` passthrough로 처리하고, Edge/OpenAI surface가 node HTTP client를 우회해 직접 Ollama에 붙는 구조로 확장하지 않는다. - `adapters.Registry`의 start/stop은 bootstrap lifecycle에서만 호출하고 개별 adapter에서 직접 호출하지 않는다. - cli adapter의 출력 format별 파싱 로직은 `lineEmitter` 구현체로 분리하고 `node.Node`에 분기문으로 박지 않는다. -- CLI profile mode별 세부 실행(`persistent-lazy`, `codex-exec`, `opencode-sse`)은 `adapters/cli` 내부에 두고, `runtime.Adapter` 계약 밖으로 새 transport를 노출하지 않는다. +- CLI profile mode별 세부 실행(`persistent-lazy`, `codex-exec`, `antigravity-print`, `opencode-sse`)은 `adapters/cli` 내부에 두고, `runtime.Adapter` 계약 밖으로 새 transport를 노출하지 않는다. +- CLI logical session은 `(target, session_id)`로 식별한다. Antigravity conversation id, Codex external id, opencode session/server 상태를 전역 target 단위로 공유하지 않는다. +- `response_idle_timeout_ms`, `startup_idle_timeout_ms`, `completion_marker`, `resume_args`, `mode` 같은 CLI profile 설정은 edge config/proto payload를 통해 주입하고 node 코드에 target별 상수를 늘리지 않는다. +- Ollama adapter는 내부 target을 model 이름으로 사용하고, `context_size`는 `options.num_ctx` default로만 주입한다. 요청 input에 명시된 `options.num_ctx`가 있으면 이를 덮어쓰지 않는다. +- `RuntimeEvent`는 start/delta/reasoning_delta/complete/error/cancelled 타입을 유지하고, adapter별 streaming 표현을 node 외부로 새 이벤트 체계로 노출하지 않는다. - node 내부 변경은 가능한 대상 패키지 테스트를 먼저 추가하거나 갱신한다. - `apps/node/cmd/node/**`, `apps/node/internal/bootstrap/**`, `apps/node/internal/transport/**`, `apps/node/internal/node/**`, `apps/node/internal/router/**`, `apps/node/internal/adapters/**`, `apps/node/internal/store/**`의 실행 요청/응답/stream/cancel/status/session 경로를 바꾼 뒤에는 `testing` domain rule의 작업 후 검증 기준을 따른다. @@ -68,7 +77,8 @@ Edge에 연결되어 실제 adapter execution을 수행하는 IOP 노드 에이 - **edge**: edge는 node 연결 등록, adapter/runtime 설정 전달, 라우팅 진입, stream relay를 담당한다. node는 edge가 보낸 실행/취소/명령 요청을 처리하고 이벤트와 명령 응답을 돌려준다. - **platform-common**: node는 `packages/config`, `packages/events`, `packages/observability`, `proto/gen/iop` 등을 사용하지만 공통 타입/설정/event helper 자체의 소유자는 platform-common이다. -- **control-plane 후보**: control-plane은 Node가 아니라 Edge를 통해 시스템을 제어한다. node는 control-plane 직접 연결/직접 스케줄링을 전제로 하지 않는다. +- **control-plane**: control-plane은 Node가 아니라 Edge를 통해 시스템을 제어한다. node는 control-plane 직접 연결/직접 스케줄링을 전제로 하지 않는다. +- **portal**: portal은 node에 직접 연결하지 않는다. node 상태와 실행 결과는 Edge/Control Plane 표면을 통해 노출한다. ## 금지 사항 @@ -77,3 +87,4 @@ Edge에 연결되어 실제 adapter execution을 수행하는 IOP 노드 에이 - 새 어댑터 구현을 `node.Node`에 직접 분기문으로 박아 넣지 않는다. - edge-local console, OpenAI-compatible HTTP, A2A 같은 입력 표면 책임을 node로 끌어오지 않는다. - placeholder 상태인 control-plane/worker 책임을 node에 임시로 흡수하지 않는다. +- CLI provider별 session/conversation 상태를 `runtime` 공통 인터페이스로 성급히 승격하지 않는다. provider 세부 상태는 `adapters/cli` 내부에 둔다. diff --git a/agent-ops/rules/project/domain/platform-common/rules.md b/agent-ops/rules/project/domain/platform-common/rules.md index e5fa2ef..e22c7f6 100644 --- a/agent-ops/rules/project/domain/platform-common/rules.md +++ b/agent-ops/rules/project/domain/platform-common/rules.md @@ -1,7 +1,7 @@ --- domain: platform-common -last_rule_review_commit: 01bef3dc933e225b09d0f348aab6b0097275a4d8 -last_rule_updated_at: 2026-05-21 +last_rule_review_commit: 6e1c201d0b82661465238821edb136444eacb9d0 +last_rule_updated_at: 2026-05-28 --- # platform-common @@ -29,18 +29,20 @@ last_rule_updated_at: 2026-05-21 - `apps/node/` — node 실행 파이프라인과 adapter 관리 - `apps/edge/` — 실행 그룹 컨트롤러와 node registry -- `apps/control-plane/` — control-plane 앱 구현 예정 영역 -- `apps/web/` — Next.js Web Portal 앱 영역 +- `apps/control-plane/` — 중앙 제어면 앱 구현 영역 +- `apps/portal/` — Flutter 운영 클라이언트 구현 영역 - `apps/worker/` — worker 앱 구현 예정 영역 ## 주요 구성 요소 - `config.NodeConfig` / `config.EdgeConfig` — node/edge 앱 설정 계약 +- `config.EdgeServerConf` / `config.EdgeBootstrapConf` — Edge listen/advertise host와 artifact bootstrap URL 설정 계약 - `config.EdgeOpenAIConf` / `config.EdgeA2AConf` / `config.EdgeConsoleConf` — edge 입력 표면과 console 기본 설정 계약 -- `config.CLIProfileConf` / `config.CompletionMarkerConf` — CLI adapter profile과 completion marker 설정 계약 +- `config.CLIProfileConf` / `config.CompletionMarkerConf` — CLI adapter profile, mode, resume args, completion marker 설정 계약 +- `config.OllamaConf` — Ollama base URL과 context size 설정 계약 - `auth.LoadServerTLS` / `auth.LoadClientTLS` — mTLS TLS config 생성 - `events.NewEdgeNodeEvent()` — node/edge lifecycle event envelope 생성 -- `hostsetup.Run()` / `hostsetup.EdgeSpec()` / `hostsetup.NodeSpec()` — systemd unit, 설정 파일, 데이터 디렉터리 준비 +- `hostsetup.Run()` / `hostsetup.EdgeSpec()` / `hostsetup.NodeSpec()` / `hostsetup.EdgeBundleConfigTemplate()` — systemd unit, 설정 파일, bundle-local edge config, 데이터 디렉터리 준비 - `observability.NewLogger` / `observability.ServeMetrics` — 공통 로깅/메트릭 - `policy.Engine` — 정책 적용/검증 계약 - `jobs.Job` — 비동기 작업 상태 placeholder; 내부 실행 대상은 `target`으로 표현 @@ -51,18 +53,20 @@ last_rule_updated_at: 2026-05-21 - 공통 패키지는 특정 앱의 내부 패키지를 import하지 않는다. - 설정 struct 필드 변경 시 YAML tag, mapstructure tag, default, `configs/*.yaml` 예시를 함께 확인한다. - host setup 기본 템플릿을 바꿀 때는 `packages/hostsetup`의 `EdgeSpec`/`NodeSpec`, 기본 경로, systemd unit, 관련 CLI `setup` 옵션과 함께 확인한다. -- protobuf 계약 변경은 `proto/iop/*.proto`에서 시작하고 `make proto`로 생성물을 갱신한다. +- protobuf 계약 변경은 `proto/iop/*.proto`에서 시작하고 `make proto`로 Go 생성물을 갱신한다. Portal/Client Dart 계약에 닿으면 `make proto-dart`도 함께 실행한다. - 생성 파일(`proto/gen/iop/*.pb.go`)은 사람이 직접 편집하지 않는다. +- Dart 생성 파일(`apps/portal/lib/gen/**`)도 사람이 직접 편집하지 않는다. - 공통 패키지는 작고 명확한 계약을 유지하고 앱별 정책을 과도하게 끌어올리지 않는다. - 공통 event helper는 envelope 생성과 상수 정의까지만 담당하고, edge 내부 fanout/replay/store 정책은 edge 도메인에 둔다. -- `RunRequest`, `ExecutionSpec`, `NodeCommandRequest`, job/history 계열 계약을 변경할 때 내부 실행 용어는 `target`을 우선하고, `model`은 외부 호환 경계인지 확인한다. +- `RunRequest`, `ExecutionSpec`, `NodeCommandRequest`, `CLIProfileConfig`, job/history 계열 계약을 변경할 때 내부 실행 용어는 `target`을 우선하고, `model`은 외부 호환 경계인지 확인한다. +- `PortalHelloRequest`/`PortalHelloResponse`는 Portal-Control Plane hello baseline 계약이다. Edge/Node scheduling 계약으로 확장하지 않는다. - `packages/config/**`, `packages/events/**`, `packages/hostsetup/**`, `configs/**`, `proto/iop/**`처럼 edge-node 실행 설정, setup, lifecycle event, 메시지 계약에 영향을 주는 작업을 한 뒤에는 `testing` domain rule의 작업 후 검증 기준을 따른다. ## 다른 도메인과의 경계 - **node**: node가 필요로 하는 설정/타입/계약을 제공하지만 실행 파이프라인의 소유자는 node이다. - **edge**: edge가 필요로 하는 설정/관측성/protobuf 계약을 제공하지만 실행 그룹 제어와 node registry 동작의 소유자는 edge이다. -- **control-plane/web/worker 후보**: 앱별 구현이 진행될 때 필요한 공통 타입만 이 영역으로 승격하고 앱 내부 책임은 각 도메인에 둔다. +- **control-plane/portal/worker**: 앱별 구현에 필요한 공통 타입만 이 영역으로 승격하고 앱 내부 책임은 각 도메인에 둔다. ## 금지 사항 @@ -71,4 +75,5 @@ last_rule_updated_at: 2026-05-21 - edge fanout bus, web UI state, control-plane session 관리처럼 특정 앱의 운영 상태를 공통 패키지로 끌어올리지 않는다. - 내부 실행 계약을 확장하면서 `model` 중심 명명을 되살리지 않는다. 외부 API 호환이 필요한 경우 경계와 변환 위치를 명시한다. - protobuf 생성물을 직접 수정하지 않는다. +- Dart protobuf 생성물을 직접 수정하지 않는다. - 설정 파일만 바꾸고 `packages/config`의 로딩/default와 불일치하게 두지 않는다. diff --git a/agent-ops/rules/project/domain/portal/rules.md b/agent-ops/rules/project/domain/portal/rules.md new file mode 100644 index 0000000..51619ef --- /dev/null +++ b/agent-ops/rules/project/domain/portal/rules.md @@ -0,0 +1,64 @@ +--- +domain: portal +last_rule_review_commit: 6e1c201d0b82661465238821edb136444eacb9d0 +last_rule_updated_at: 2026-05-28 +--- + +# portal + +## 목적 / 책임 + +IOP 운영 클라이언트의 Flutter-first UI 영역이다. 현재는 Control Plane HTTP/Wire endpoint 설정을 build-time define으로 주입받고, proto-socket WebSocket으로 Portal hello handshake를 수행하는 scaffold를 제공한다. + +## 포함 경로 + +- `apps/portal/lib/` — Flutter 앱 코드, Portal 설정, Control Plane wire client +- `apps/portal/test/` — Flutter widget/config/wire client 테스트 +- `apps/portal/lib/gen/` — `proto/iop/*.proto`에서 생성된 Dart protobuf 코드 +- `apps/portal/web/` — Flutter Web 정적 entrypoint와 manifest +- `apps/portal/android/`, `apps/portal/ios/`, `apps/portal/linux/`, `apps/portal/macos/`, `apps/portal/windows/` — Flutter platform host scaffold +- `apps/portal/pubspec.yaml` / `apps/portal/pubspec.lock` — Flutter/Dart dependency 계약 +- `apps/portal/Dockerfile` / `apps/portal/nginx.conf` — Flutter Web build와 nginx 정적 서빙 표면 +- `apps/portal/README.md` — Portal 개발, 검증, build-time 설정 설명 + +## 제외 경로 + +- `apps/control-plane/` — Portal wire server와 중앙 제어면 API 구현 영역 +- `apps/edge/` — Edge-local 실행 그룹 컨트롤러 +- `apps/node/` — adapter execution runtime +- `apps/web/` — 제거된 legacy Next.js scaffold 경로 +- `proto/iop/` — protobuf 원본 계약은 platform-common 도메인 소유 +- `bin/web.sh` / `Makefile` — Portal 실행·검증 entrypoint는 testing 도메인 소유 + +## 주요 구성 요소 + +- `IopPortalApp` — Flutter Material app root +- `PortalHomePage` — Control Plane endpoint 표시와 wire connection 상태 UI +- `PortalConfig` — `IOP_CONTROL_PLANE_HTTP_URL`, `IOP_CONTROL_PLANE_WIRE_URL` build-time define 로딩 +- `PortalWireClient` — Control Plane `/portal` WebSocket proto-socket client와 hello request helper +- `portalParserMap` — Portal wire protobuf type parser map +- `apps/portal/lib/gen/proto/iop/*.pb.dart` — IOP protobuf의 Dart 생성물 +- `apps/portal/Dockerfile` / `nginx.conf` — Flutter Web 산출물 정적 서빙 구성 + +## 유지할 패턴 + +- Portal은 Flutter-first client로 유지한다. legacy Next.js `apps/web`를 되살리거나 확장하지 않는다. +- Control Plane 연결 설정은 `--dart-define` 또는 host/bootstrap 주입 경계로 관리한다. 환경별 endpoint를 코드에 고정하지 않는다. +- Portal-Control Plane 고유 통신은 proto-socket WebSocket/WSS를 사용하고, 브라우저/앱 UI에서 Edge-Node TCP transport에 직접 붙지 않는다. +- `apps/portal/lib/gen/**` Dart protobuf 생성물은 직접 수정하지 않는다. 원본 `proto/iop/*.proto` 변경 후 `make proto-dart`로 갱신한다. +- `proto_socket` Dart dependency는 현재 local path dependency이므로, 경로/패키징 변경 시 Portal build와 dev server entrypoint를 함께 확인한다. +- `Client Integration Clone Adoption` 결정 전에는 `apps/portal` 경로를 기준으로 작업한다. `apps/client` 전환이 결정되면 domain rule과 도메인 매핑을 함께 갱신한다. + +## 다른 도메인과의 경계 + +- **control-plane**: Control Plane은 `/portal` wire endpoint와 서버 응답 계약을 제공한다. Portal은 client connection lifecycle과 UI state를 소유한다. +- **platform-common**: protobuf 원본과 Go 생성물은 platform-common 소유다. Portal은 Dart 생성물을 소비하되 원본 계약을 독자적으로 바꾸지 않는다. +- **testing**: `bin/web.sh`, `make portal-test`, `make portal-build-web` 같은 실행/검증 entrypoint는 testing 도메인의 기준을 따른다. +- **edge/node**: Portal은 Edge와 Node runtime에 직접 붙지 않고 Control Plane을 통해 운영면을 확장한다. + +## 금지 사항 + +- Flutter Portal 작업에서 legacy `apps/web` Next.js 구조를 복원하거나 새 제품 경로로 확장하지 않는다. +- UI에서 Node나 Edge 내부 transport/protobuf session에 직접 연결하는 운영 경로를 만들지 않는다. +- `apps/portal/lib/gen/**` 생성 파일을 직접 편집하지 않는다. +- 실제 Control Plane endpoint, auth token, signing key 같은 환경별 값을 tracked source에 하드코딩하지 않는다. diff --git a/agent-ops/rules/project/domain/testing/rules.md b/agent-ops/rules/project/domain/testing/rules.md index de61181..2a76d94 100644 --- a/agent-ops/rules/project/domain/testing/rules.md +++ b/agent-ops/rules/project/domain/testing/rules.md @@ -1,7 +1,7 @@ --- domain: testing -last_rule_review_commit: 3b9f37076a396370f1c7043d7fa92e6f0a006031 -last_rule_updated_at: 2026-05-27 +last_rule_review_commit: 6e1c201d0b82661465238821edb136444eacb9d0 +last_rule_updated_at: 2026-05-28 --- # testing @@ -12,10 +12,10 @@ last_rule_updated_at: 2026-05-27 ## 포함 경로 -- `Makefile` — 공식 test target과 보조 smoke target을 선언하는 위치이다. +- `Makefile` — 공식 test target, proto generation, Portal 검증 target, 보조 smoke target을 선언하는 위치이다. - `bin/edge.sh` — repo 내부 edge console/server 개발 진단 helper이다. - `bin/node.sh` — repo 내부 node 연결 개발 진단 helper이다. field 사용자 기본 경로로 안내하지 않는다. -- `bin/web.sh` — 사용자가 Web Portal dev server를 실행하는 shell entrypoint이다. +- `bin/web.sh` — 사용자가 Flutter Portal web dev server를 실행하는 shell entrypoint이다. - `bin/build/field-binaries.sh` — field 배포용 edge/node 바이너리 build entrypoint이다. - `scripts/e2e-smoke.sh` — mock/real profile 기반 보조 edge-node smoke 검증이다. - `scripts/e2e-openai-ollama.sh` — OpenAI-compatible Ollama 입력 표면 보조 smoke 검증이다. @@ -24,7 +24,7 @@ last_rule_updated_at: 2026-05-27 - `apps/node/` — node 실행 구현의 소유자는 node 도메인이다. testing 도메인은 작업 후 검증 기준만 정의한다. - `apps/edge/` — edge 실행 구현의 소유자는 edge 도메인이다. testing 도메인은 작업 후 검증 기준만 정의한다. -- `apps/web/` — Web Portal 구현의 소유자는 별도 후보 도메인이다. testing 도메인은 entrypoint와 검증 기준만 정의한다. +- `apps/portal/` — Flutter Portal 구현의 소유자는 portal 도메인이다. testing 도메인은 entrypoint와 검증 기준만 정의한다. - `packages/` 및 `proto/` — 공통 계약의 소유자는 platform-common 도메인이다. testing 도메인은 해당 변경 후 필요한 검증 기준만 정의한다. ## 주요 구성 요소 @@ -34,7 +34,7 @@ last_rule_updated_at: 2026-05-27 - edge-node 개발 진단 흐름 검증 — `bin/edge.sh`와 `bin/node.sh`를 각각 실행하고, edge console에서 메시지 2회와 command 명령을 직접 보내 결과가 edge 화면에 도착하는지 확인하는 저수준 검증이다. field 사용자 기본 UX는 Edge가 제시한 bootstrap 명령이다. - 보조 E2E smoke — 임시 설정과 mock adapter로 최소 생존을 빠르게 확인하는 보조 검증이다. 이 결과만으로 완료 처리하지 않는다. - OpenAI-compatible Ollama smoke — `scripts/e2e-openai-ollama.sh`로 OpenAI HTTP 입력 표면이 edge service와 node adapter 경로로 수렴하는지 확인하는 보조 검증이다. -- Web Portal verify — `apps/web` 변경 시 `npm run verify --prefix apps/web` 기준으로 TypeScript check와 production build를 확인한다. +- Portal verify — `apps/portal` 변경 시 `make portal-test` 또는 `cd apps/portal && flutter test`로 Flutter 테스트를 확인하고, Web 산출물 변경 시 `make portal-build-web`을 확인한다. - full-cycle 실제 구동 — 비효율적이어도 관련 사용자 명령과 실행 cycle을 한 번씩 실제 entrypoint로 통과시키는 검증이다. - 실제 외부 CLI 검증 — `claude`, `antigravity`, `codex`, `opencode`처럼 외부 CLI 설치와 계정/환경이 필요한 기준 profile을 실제 호출하는 검증이다. - one-line bootstrap/install UX — Node, OTO, specialized agent, Control Plane enrollment처럼 사용자가 대상 host에서 복사해 실행하는 연결/설치 명령의 사용자 경험 기준이다. @@ -56,8 +56,8 @@ last_rule_updated_at: 2026-05-27 - field Node bootstrap의 사용자 명령은 `curl -fsSL <완성된-bootstrap-url> | bash -s ` 형태를 기준으로 한다. 다른 bootstrap/enrollment 작업에서도 같은 수준의 단일 token UX를 우선 적용하고, 예외가 필요하면 사용자에게 먼저 확인한다. - repo 내부 edge-node 진단의 상세 수행 절차와 기능별 체크리스트는 `agent-ops/skills/project/e2e-smoke/SKILL.md`를 따른다. - `make test-e2e`, `scripts/e2e-smoke.sh`, `scripts/e2e-openai-ollama.sh`는 보조 smoke 명령이다. 실행할 수 있으면 보조 확인으로 기록하되, full-cycle 실제 구동이나 field bootstrap 검증을 대체하지 않는다. -- `bin/build/field-binaries.sh` 변경 시 최소 현재 host target build를 실행하고 산출물 위치와 checksum 생성을 확인한다. -- `bin/web.sh` 또는 `apps/web/**` 변경 시 `npm run verify --prefix apps/web`를 실행하고, dev server entrypoint 변경이면 `./bin/web.sh` 기동 가능 여부도 확인한다. +- `bin/build/field-binaries.sh` 변경 시 최소 현재 host target build를 실행하고 산출물 위치, checksum 생성, node bootstrap script가 positional token UX를 유지하는지 확인한다. +- `bin/web.sh` 또는 `apps/portal/**` 변경 시 `make portal-test`를 실행하고, Web build/entrypoint 변경이면 `make portal-build-web`과 `./bin/web.sh` 기동 가능 여부도 확인한다. - 풀테스트에서는 실제 외부 CLI profile 검증을 필수로 수행한다. 환경, 계정, provider, 원격 endpoint 문제로 호출할 수 없거나 실패한 profile은 누락하지 말고 profile별 실패 또는 blocker로 보고한다. - 작업 최종 보고에는 실행한 테스트 명령, repo 내부 edge-node 진단 수행 여부, 보조 E2E smoke 수행 여부, full-cycle 실제 구동 수행 여부를 명시한다. 수행하지 못한 필수 검증은 이유와 남은 위험을 함께 적는다. @@ -111,7 +111,7 @@ terminated session default node=test-node - **node**: node는 adapter 실행과 edge 연결 구현을 소유한다. testing은 node 변경 후 어떤 검증을 거칠지 정한다. - **edge**: edge는 registry, service, transport, console, HTTP/A2A input surface 구현을 소유한다. testing은 edge 변경 후 사용자 실행 흐름을 어떻게 확인할지 정한다. - **platform-common**: platform-common은 config/proto 계약을 소유한다. testing은 해당 계약 변경이 edge-node 실행 흐름에 닿을 때 필요한 검증을 정한다. -- **web 후보**: Web Portal 구현 자체는 testing 도메인이 소유하지 않는다. testing은 web entrypoint와 verify 명령 기준만 다룬다. +- **portal**: Flutter Portal 구현 자체는 testing 도메인이 소유하지 않는다. testing은 web entrypoint와 verify 명령 기준만 다룬다. ## 금지 사항 diff --git a/agent-ops/rules/project/rules.md b/agent-ops/rules/project/rules.md index 2447fd6..0f43e3b 100644 --- a/agent-ops/rules/project/rules.md +++ b/agent-ops/rules/project/rules.md @@ -7,18 +7,19 @@ ## 프로젝트 개요 -- IOP(Inference Operations Platform)는 Control Plane - Edge - Node 계층 구조를 기반으로 모델 서빙과 CLI Agent/Automation 실행을 함께 다루는 실행 오케스트레이션 모노레포이다. 핵심 서비스는 Go이고 Portal UI의 장기 기준은 Flutter-first로 둔다. +- IOP(Inference Operations Platform)는 Control Plane - Edge - Node 계층 구조를 기반으로 모델 서빙과 CLI Agent/Automation 실행을 함께 다루는 실행 오케스트레이션 모노레포이다. 핵심 서비스는 Go이고 운영 클라이언트는 Flutter-first로 둔다. - 내부 실행 개념은 model 중심이 아니라 `adapter + target` 중심으로 정리한다. 외부 OpenAI-compatible 경계나 외부 CLI 인자에서는 호환성을 위해 `model` 표현이 남을 수 있다. -- 현재 1차 구현 중심은 `apps/node`와 `apps/edge`의 Edge-Node 실행 스켈레톤이며, CLI adapter, node 등록/레지스트리/transport, edge input surface가 우선 검증되고 있다. -- `apps/control-plane`은 health/readiness HTTP와 wire endpoint 예약을 가진 scaffold이고, `apps/web`은 삭제 예정인 legacy Next.js Portal scaffold이다. Portal 본격 구현은 `Flutter-first Portal 마이그레이션` 마일스톤과 별도 domain rule 생성/갱신을 먼저 따른다. +- 현재 구현 중심은 `apps/node`와 `apps/edge`의 Edge-Node 실행 경로, `iop-edge` command 중심의 local/field 운영 UX, OpenAI-compatible/A2A 입력 표면, CLI adapter logical session/runtime이다. +- `apps/control-plane`은 health/readiness HTTP와 Portal-Control Plane proto-socket WebSocket hello baseline을 가진 중앙 제어면 scaffold이다. 여러 Edge 관찰/제어 본 구현은 control-plane domain rule을 따른다. +- `apps/portal`은 Flutter-first 운영 클라이언트 scaffold이다. 기존 legacy Next.js `apps/web`은 제거되었으며, client module naming 전환 여부는 `Client Integration Clone Adoption` 마일스톤 결정 후 반영한다. - `apps/worker`는 CLI placeholder 수준이므로 본격 구현 전 별도 domain rule을 만들거나 갱신한다. ## 주요 구조 - `apps/node/` — Edge에 연결되는 실행자. 런타임 라우팅, adapter execution, CLI/model runtime 실행, 현재 단계의 로컬 실행 이력 저장을 담당한다. - `apps/edge/` — 여러 Node를 묶는 백엔드 실행 그룹 컨트롤러. token 기반 등록, node registry, node 설정 전달, routing, stream relay, ops console, OpenAI-compatible/A2A 입력 표면을 담당한다. -- `apps/control-plane/` — 향후 여러 Edge를 연결하고 상태 조회/설정 변경/명령 전달/이벤트 수신/운영 제어 API 제공을 담당할 Go 기반 중앙 관리 서버 scaffold이다. -- `apps/web/` — 삭제 예정인 legacy Next.js Web Portal scaffold이다. 장기 제품 UI는 Flutter 앱과 Flutter Web 산출물 기준으로 전환한다. +- `apps/control-plane/` — 여러 Edge를 연결하고 상태 조회/설정 변경/명령 전달/이벤트 수신/운영 제어 API 제공을 담당할 Go 기반 중앙 관리 서버 scaffold이다. +- `apps/portal/` — Flutter-first 운영 클라이언트 앱이다. Flutter Web 산출물과 native target을 같은 Dart 코드베이스에서 관리한다. - `apps/worker/` — 비동기 작업 처리 예정 영역이다. 현재 placeholder이다. - `packages/` — 설정, 인증, 이벤트 helper, host setup, 정책, 메타데이터, 작업, 관측성, 버전 등 공통 패키지이다. - `proto/iop/` — IOP 메시지 계약 원본이다. @@ -32,7 +33,7 @@ ## 기술 스택 - 언어/모듈: Go `1.24`, module `iop` -- Portal UI: Flutter-first 앱과 Flutter Web 산출물 기준으로 전환 예정. 현재 `apps/web`의 Next.js/React/TypeScript scaffold는 제품 경로에서 삭제한다. +- 운영 클라이언트 UI: Flutter `apps/portal`과 Flutter Web 산출물 기준. legacy Next.js/React/TypeScript `apps/web` 경로는 제거되었다. - CLI: `github.com/spf13/cobra` - 설정: `github.com/spf13/viper`, YAML - DI: `go.uber.org/fx` @@ -54,7 +55,8 @@ - 바이너리 배포 UX는 repo checkout 위치에 묶이지 않아야 한다. `iop-edge`/`iop-node`는 아무 작업 디렉터리에서 실행 가능해야 하며, 로컬/dev bundle에서는 Edge 설정을 바이너리와 같은 디렉터리의 `edge.yaml` 같은 구조화된 config에 모으는 방향을 우선한다. Node 쪽은 별도 사용자 config 파일이 아니라 Edge가 제공하는 bootstrap으로 연결한다. - Edge-Node 내부 통신은 TCP 기반 protobuf 메시지 흐름을 우선한다. Portal-Control Plane처럼 브라우저/앱 표면이 필요한 경계는 proto-socket WebSocket/WSS를 사용할 수 있다. gRPC 도입, Edge-Node 기본 transport의 WebSocket 전환, actor/FSM/plugin framework 도입은 금지한다. - protobuf 계약 변경 시 `proto/iop/*.proto`를 먼저 수정하고 `make proto`로 `proto/gen/iop/*.pb.go`를 갱신한다. 생성 파일은 직접 수정하지 않는다. -- 앱 설정 구조 변경 시 `packages/config`의 struct/default와 `configs/*.yaml` 예시를 함께 확인한다. +- Portal/Client Dart protobuf 계약 변경 시 `proto/iop/*.proto`를 먼저 수정하고 `make proto-dart`로 `apps/portal/lib/gen/**` 생성물을 갱신한다. Dart 생성 파일도 직접 수정하지 않는다. +- Edge/Node 앱 설정 구조 변경 시 `packages/config`의 struct/default와 `configs/*.yaml` 예시를 함께 확인한다. Control Plane 로컬 설정 구조 변경 시 `apps/control-plane`의 config loader와 `configs/control-plane.yaml` 예시를 함께 확인한다. - 테스트는 변경 범위에 맞춰 `go test ./...` 또는 대상 패키지 테스트를 실행한다. - 사용자 실행 파이프라인에 닿는 작업을 한 경우, 작업 완료 후 `agent-ops/rules/project/domain/testing/rules.md`의 검증 기준을 따른다. - field/bootstrap 작업은 `testing` domain rule을 따르고, 실제 환경값이 필요하면 private rule 라우팅을 따른다. @@ -73,6 +75,8 @@ |----------|--------|----------| | `apps/node/**` | node | `agent-ops/rules/project/domain/node/rules.md` | | `apps/edge/**` | edge | `agent-ops/rules/project/domain/edge/rules.md` | +| `apps/control-plane/**` | control-plane | `agent-ops/rules/project/domain/control-plane/rules.md` | +| `apps/portal/**` | portal | `agent-ops/rules/project/domain/portal/rules.md` | | `packages/**` | platform-common | `agent-ops/rules/project/domain/platform-common/rules.md` | | `proto/**` | platform-common | `agent-ops/rules/project/domain/platform-common/rules.md` | | `configs/**` | platform-common | `agent-ops/rules/project/domain/platform-common/rules.md` | @@ -82,8 +86,7 @@ ## 도메인 후보 -- `control-plane`: `apps/control-plane/**`가 scaffold를 넘어 여러 Edge 연결 관리, Edge 상태 조회, Edge 설정 변경, Edge 명령 전달, 이벤트 수신, 운영 제어 API 제공을 구현하기 시작할 때 생성한다. -- `portal`: Flutter-first Portal 또는 legacy `apps/web/**` 제거/대체가 본격 구현될 때 생성한다. 기존 Next.js `apps/web/**`는 확장하지 않고 삭제 또는 Flutter Web 산출물 서빙 경로로 대체한다. +- `client`: `Client Integration Clone Adoption`에서 `apps/portal`을 `apps/client`로 전환하기로 결정되면 portal domain rule과 경로 매핑을 client 기준으로 갱신한다. - `worker`: `apps/worker/**`가 placeholder를 넘어 작업 큐 소비/재시도/결과 저장을 구현하기 시작할 때 생성한다. ## 스킬 라우팅