update domain rules and roadmap

This commit is contained in:
toki 2026-06-15 13:35:11 +09:00
parent 99cc06767f
commit 5cecc55905
13 changed files with 286 additions and 59 deletions

View file

@ -1,21 +1,21 @@
--- ---
domain: agent domain: agent
last_rule_review_commit: 67d7b6e411b8a28d6d42cac550a29872a7ef6b7e last_rule_review_commit: 99cc06767f82a32a9106f3a483bce2b6aeed5872
last_rule_updated_at: 2026-06-01 last_rule_updated_at: 2026-06-13
--- ---
# agent # agent
## 목적 / 책임 ## 목적 / 책임
OTO Edge 서버에 CLI 기반 agent 노드를 등록하고, agent 실행에 필요한 config 파싱, Edge endpoint 해석, protobuf 등록 요청, bootstrap 스크립트를 담당한다. OTO Server에 CLI 기반 runner agent를 등록하고, agent config 파싱, 등록/heartbeat/disconnect, remote job claim, remote pipeline 실행, 실행 결과/로그/artifact 보고, bootstrap 스크립트를 담당한다.
파이프라인 실행 엔진이나 scheduler 등록 정책이 아니라 `oto agent run --config <path>` 실행 흐름과 Edge 연결 초기화가 이 도메인의 책임이다. 파이프라인 실행 엔진이나 scheduler 등록 정책이 아니라 `oto agent run --config <path>` 실행 흐름과 OTO Server runner 세션 초기화가 이 도메인의 책임이다.
## 포함 경로 ## 포함 경로
- `apps/runner/lib/cli/commands/command_agent.dart``agent run --config <path>` CLI 표면과 오류 출력 - `apps/runner/lib/cli/commands/command_agent.dart``agent run --config <path>` CLI 표면과 오류 출력
- `apps/runner/lib/oto/agent/` — agent config, runner, Edge 등록 client, generated protobuf 런타임 코드 - `apps/runner/lib/oto/agent/` — agent config, runner, OTO Server 등록/job client, remote run executor, legacy iop Edge compatibility client, generated protobuf 런타임 코드
- `apps/runner/assets/script/shell/oto_agent_bootstrap.sh` — Linux agent 다운로드, config 생성, background 실행 bootstrap - `apps/runner/assets/script/shell/oto_agent_bootstrap.sh` — Linux agent 다운로드, server config 생성, background 실행 bootstrap
## 제외 경로 ## 제외 경로
@ -23,51 +23,67 @@ OTO Edge 서버에 CLI 기반 agent 노드를 등록하고, agent 실행에 필
- `apps/runner/lib/cli/commands/command_catalog.dart` — command catalog 출력 (`cli` 도메인) - `apps/runner/lib/cli/commands/command_catalog.dart` — command catalog 출력 (`cli` 도메인)
- `apps/runner/lib/cli/commands/command_validate.dart` — pipeline YAML 검증 (`cli`/`core` 도메인) - `apps/runner/lib/cli/commands/command_validate.dart` — pipeline YAML 검증 (`cli`/`core` 도메인)
- `apps/runner/lib/cli/commands/command_scheduler.dart` — scheduler 명령 진입 (`scheduler` 도메인) - `apps/runner/lib/cli/commands/command_scheduler.dart` — scheduler 명령 진입 (`scheduler` 도메인)
- `apps/runner/lib/oto/application.dart` — pipeline build 오케스트레션 (`core` 도메인) - `apps/runner/lib/oto/application.dart` — pipeline build 오케스트레이션 (`core` 도메인)
- `apps/runner/lib/oto/core/build_result.dart` — 실행 결과/step event/artifact 결과 모델 (`core` 도메인)
- `apps/runner/lib/oto/core/output_port.dart` — runner 출력 포트 추상화 (`core` 도메인)
- `apps/runner/lib/cli/runner_output_adapter.dart` — CLI 출력 포트 adapter (`cli` 도메인)
- `apps/runner/lib/oto/pipeline/` — pipeline workflow 실행 (`pipeline` 도메인) - `apps/runner/lib/oto/pipeline/` — pipeline workflow 실행 (`pipeline` 도메인)
- `apps/runner/lib/oto/commands/` — pipeline에서 호출되는 커맨드 구현체 (`command` 도메인) - `apps/runner/lib/oto/commands/` — pipeline에서 호출되는 커맨드 구현체 (`command` 도메인)
- `apps/runner/lib/oto/commands/runner_command_capability_provider.dart` — agent 등록용 command catalog capability provider (`command` 도메인)
- `apps/runner/assets/script/`의 기타 build/package helper — CLI/배포 보조 asset (`cli` 도메인) - `apps/runner/assets/script/`의 기타 build/package helper — CLI/배포 보조 asset (`cli` 도메인)
## 주요 구성 요소 ## 주요 구성 요소
- `CommandAgent``agent` CLI subcommand 파싱, config 로딩, runner 호출, exit code 처리 - `CommandAgent``agent` CLI subcommand 파싱, config 로딩, runner 호출, exit code 처리
- `AgentConfig` / `AgentIdentityConfig` / `EdgeConnectionConfig` / `AgentRuntimeConfig` — agent bootstrap YAML 구조와 필수 필드 검증 - `AgentConfig` / `AgentIdentityConfig` / `ServerConnectionConfig` / `EdgeConnectionConfig` / `AgentRuntimeConfig` — agent bootstrap YAML 구조와 필수 필드 검증
- `AgentConfigException` — config 파일/필드/타입 오류 표현 - `AgentConfigException` — config 파일/필드/타입 오류 표현
- `AgentRunner` / `DefaultAgentRunner` — Edge 등록 workflow 실행과 결과 로그 출력 - `AgentRunner` / `DefaultAgentRunner` — OTO Server 등록 workflow, remote job loop, 결과 로그 출력
- `RegistrationException` — Edge 등록 거절 또는 연결 실패 표현 - `RegistrationException` — OTO Server 등록 거절 또는 연결 실패 표현
- `EdgeEndpoint` — Edge URL host/port 정규화와 기본 포트 결정 - `RegistrationClient` / `AgentSession` / `OtoServerJobSession` — 등록 transport와 세션 수명주기 추상화
- `EdgeRegistrationClient``proto_socket` 기반 RegisterRequest 전송 - `OtoServerRegistrationClient` — HTTP 기반 runner register, heartbeat, disconnect 요청
- `RegistrationResult` — RegisterResponse accepted/rejected 결과 변환 - `OtoServerJobClient` — job claim, execution report, log append, artifact report, cancel, status, self-update 요청
- `_OtoIopClient` — agent iop protobuf message registry를 가진 proto_socket client - `RemoteRunExecutor` / `RunRequestParser` / `RemoteRunInput` — OTO Server `RunRequest`를 workspace-confined YAML 실행 입력으로 변환하고 `Application.build()` 결과를 보고
- `apps/runner/lib/oto/agent/iop/*.pb*.dart``iop/runtime.proto` generated protobuf 코드 - `RunnerCapabilityProvider` / `RunnerCapabilitySnapshot` — 등록 시 runner capability와 command catalog 요약 제공 계약
- `apps/runner/lib/oto/agent/google/protobuf/*.pb*.dart``google/protobuf/struct.proto` generated protobuf 코드 - `RegistrationResult` — OTO Server/iop response의 accepted/rejected 결과 변환
- `EdgeEndpoint` / `EdgeRegistrationClient` / `_OtoIopClient` — legacy iop Edge compatibility 경로. 기본 runner 경로에서는 `OtoServerRegistrationClient`를 사용
- `apps/runner/lib/oto/agent/oto/*.pb*.dart``proto/oto/runner.proto` generated Dart protobuf 코드
- `apps/runner/lib/oto/agent/iop/*.pb*.dart` — legacy `iop/runtime.proto` generated protobuf 코드
- `oto_agent_bootstrap.sh` — agent config 파일 생성, 권한 설정, background 실행 bootstrap - `oto_agent_bootstrap.sh` — agent config 파일 생성, 권한 설정, background 실행 bootstrap
## 유지할 패턴 ## 유지할 패턴
- `CommandAgent`는 subcommand/argument 파싱과 출력만 담당하고, config 파싱은 `AgentConfig`, 등록 실행은 `AgentRunner`에 위임한다. - `CommandAgent`는 subcommand/argument 파싱과 출력만 담당하고, config 파싱은 `AgentConfig`, 등록 실행은 `AgentRunner`에 위임한다.
- `--config <path>``--config=<path>` 형식을 모두 유지하고, 누락/알 수 없는 인자는 실행 전에 오류 처리한다. - `--config <path>``--config=<path>` 형식을 모두 유지하고, 누락/알 수 없는 인자는 실행 전에 오류 처리한다.
- `AgentConfig`는 YAML root와 `agent`, `edge`, `runtime` section이 map인지 확인한 뒤 required string을 검증한다. - `AgentConfig`는 YAML root와 `agent`, `server`(또는 legacy `edge`), `runtime` section이 map인지 확인한 뒤 required string을 검증한다.
- agent config의 required field는 빈 문자열을 거부하고, optional `agent.alias`는 누락 시 `null`, 빈 문자열이면 빈 문자열로 보존한다. - agent config의 required field는 빈 문자열을 거부하고, optional `agent.alias`는 누락 시 `null`, 빈 문자열이면 빈 문자열로 보존한다.
- `EdgeEndpoint.parse()`는 scheme 없는 host도 허용하고, port가 없으면 https는 443, 그 외는 80을 기본값으로 둔다. - OTO Server URL은 scheme 없는 host도 허용하고, HTTP endpoint 생성 시 기본 `http://`로 해석한다.
- Edge 등록 통신은 `EdgeRegistrationClient.register()`에서 열고 `finally`에서 client를 닫는다. - OTO Server 등록 세션은 `openSession()`에서 열고 세션 소유자가 `finally`에서 `AgentSession.close()`를 호출해 heartbeat timer와 HTTP client를 정리한다.
- RegisterResponse 변환은 `RegistrationResult.fromResponse()`에 모아 accepted/rejected와 runtime config 추출을 한 곳에서 처리한다. - 기본 agent loop는 job claim 실패를 "대기할 작업 없음"으로 보고 polling을 계속하고, claim된 `RunRequest``RemoteRunExecutor.runOnce()`로 실행한다.
- remote YAML path는 `workspaceRoot` 아래로 confinement를 강제하고, inline YAML이 있으면 path보다 우선한다.
- remote variables는 YAML `property` map 위에 overlay하되, 기존 `property`가 map이 아니면 원본 YAML을 유지해 `Application.build()` 검증이 실패하게 한다.
- `property.artifacts` 선언은 `name`/`path` map list만 허용하고, artifact path도 workspace confinement를 통과해야 한다.
- RegisterResponse/JSON 변환은 `RegistrationResult`에 모아 accepted/rejected와 runner id/alias 추출을 한 곳에서 처리한다.
- generated protobuf 파일은 직접 수정하지 않고 원본 proto와 생성 절차를 확인해 재생성한다. - generated protobuf 파일은 직접 수정하지 않고 원본 proto와 생성 절차를 확인해 재생성한다.
- bootstrap 스크립트는 `--server-url`을 기본 인자로 사용하고 legacy `--edge-url`도 server URL로 받는다.
- bootstrap 스크립트는 `--release-base-url`에 https만 허용하고, 생성한 config 파일은 `chmod 600`을 유지한다. - bootstrap 스크립트는 `--release-base-url`에 https만 허용하고, 생성한 config 파일은 `chmod 600`을 유지한다.
- agent 변경 후 `dart analyze`와 agent 관련 테스트(`apps/runner/test/oto_agent_*`, 필요 시 `apps/runner/test/oto_iop_connection_smoke_test.dart`)를 확인한다. - legacy iop Edge 경로는 `edge_registration_client.dart` 안에 격리하고, 기본 production runner 경로에서 직접 import하지 않는다.
- agent 변경 후 `dart analyze`와 agent 관련 테스트(`apps/runner/test/oto_agent_*`, `apps/runner/test/oto_server_connection_smoke_test.dart`, 필요 시 `apps/runner/test/oto_iop_connection_smoke_test.dart`)를 확인한다.
## 다른 도메인과의 경계 ## 다른 도메인과의 경계
- **cli**: `apps/runner/bin/main.dart` 등록과 일반 출력/스타일은 cli 도메인이다. `CommandAgent` 내부의 agent subcommand 정책부터는 agent 도메인이다. - **cli**: `apps/runner/bin/main.dart` 등록, 일반 출력/스타일, `CliRunnerOutputPort` adapter는 cli 도메인이다. `CommandAgent` 내부의 agent subcommand 정책부터는 agent 도메인이다.
- **core/pipeline/command**: agent 등록은 pipeline build 실행과 별개다. agent 도메인에서 `Application.build()`, `Pipeline.pipelineInitialize()`, `Command.byType()`을 직접 호출하지 않는다. - **core/pipeline/command**: agent 등록은 pipeline build 실행과 별개다. remote job 실행은 `Application.build()` 진입점까지만 호출하고, `Pipeline.pipelineInitialize()``Command.byType()`을 직접 호출하지 않는다.
- **core**: remote run 실행 결과를 담는 `BuildResult`, `StepEvent`, `BuildArtifact`, `RunnerOutputPort`는 core 도메인이다. agent 도메인은 이를 서버 보고 payload로 변환해 전송한다.
- **command**: runner capability의 command catalog 계산은 command 도메인의 `CommandCatalogRunnerCapabilityProvider`가 담당한다. agent 도메인은 provider interface만 소비한다.
- **scheduler**: scheduler는 YAML 파이프라인을 cron/interval로 실행한다. agent bootstrap의 background 실행과 scheduler 등록/로그 정책을 섞지 않는다. - **scheduler**: scheduler는 YAML 파이프라인을 cron/interval로 실행한다. agent bootstrap의 background 실행과 scheduler 등록/로그 정책을 섞지 않는다.
- **framework**: `proto_socket`, `protobuf`, `fixnum` dependency 선언은 framework 도메인에서 관리하고, Edge protocol 사용 방식은 agent 도메인에서 관리한다. - **framework**: `http`, `proto_socket`, `protobuf`, `fixnum` dependency 선언`proto/oto/runner.proto` 생성 절차는 framework 도메인에서 관리하고, OTO Server/iop protocol 사용 방식은 agent 도메인에서 관리한다.
- **sample**: agent config YAML은 pipeline sample YAML이 아니다. `apps/runner/assets/yaml/sample/**`에 agent bootstrap config를 섞지 않는다. - **sample**: agent config YAML은 pipeline sample YAML이 아니다. `apps/runner/assets/yaml/sample/**`에 agent bootstrap config를 섞지 않는다.
## 금지 사항 ## 금지 사항
- agent 도메인에서 pipeline workflow나 command catalog를 직접 실행/해석하지 않는다. - agent 도메인에서 pipeline workflow나 command catalog를 직접 해석하지 않는다. remote job 실행은 `Application.build()` 진입점까지만 호출한다.
- enrollment token, generated config, Edge 응답 중 민감 정보가 로그에 노출되도록 하지 않는다. - enrollment token, generated config, server/Edge 응답 중 민감 정보가 로그에 노출되도록 하지 않는다.
- generated protobuf 파일을 수동 편집하지 않는다. - generated protobuf 파일을 수동 편집하지 않는다.
- remote run의 YAML path나 artifact path가 `workspaceRoot` 밖으로 빠져나가도록 허용하지 않는다.
- bootstrap 스크립트에서 사용자가 지정한 config/log/workspace 경로 외 임의의 프로젝트 파일을 수정하지 않는다. - bootstrap 스크립트에서 사용자가 지정한 config/log/workspace 경로 외 임의의 프로젝트 파일을 수정하지 않는다.
- agent background 실행 정책을 scheduler 등록/해제 로직에 섞지 않는다. - agent background 실행 정책을 scheduler 등록/해제 로직에 섞지 않는다.

View file

@ -1,7 +1,7 @@
--- ---
domain: cli domain: cli
last_rule_review_commit: 67d7b6e411b8a28d6d42cac550a29872a7ef6b7e last_rule_review_commit: 99cc06767f82a32a9106f3a483bce2b6aeed5872
last_rule_updated_at: 2026-06-01 last_rule_updated_at: 2026-06-13
--- ---
# cli # cli
@ -17,6 +17,7 @@ last_rule_updated_at: 2026-06-01
- `apps/runner/lib/cli/cli.dart` — CLI 루트 객체, 출력/스타일 처리 - `apps/runner/lib/cli/cli.dart` — CLI 루트 객체, 출력/스타일 처리
- `apps/runner/lib/cli/printer.dart` — OS별 콘솔 출력과 ANSI 스타일 처리 - `apps/runner/lib/cli/printer.dart` — OS별 콘솔 출력과 ANSI 스타일 처리
- `apps/runner/lib/cli/cli_style.dart` — 콘솔 색상/스타일 enum - `apps/runner/lib/cli/cli_style.dart` — 콘솔 색상/스타일 enum
- `apps/runner/lib/cli/runner_output_adapter.dart` — core `RunnerOutputPort`를 CLI 출력으로 연결하는 adapter
- `apps/runner/lib/cli/commands/command_base.dart` — CLI 커맨드 공통 베이스 - `apps/runner/lib/cli/commands/command_base.dart` — CLI 커맨드 공통 베이스
- `apps/runner/lib/cli/commands/command_manager.dart` — CLI 커맨드 라우팅 - `apps/runner/lib/cli/commands/command_manager.dart` — CLI 커맨드 라우팅
- `apps/runner/lib/cli/commands/command_const.dart` — OS별 설치 경로 상수 - `apps/runner/lib/cli/commands/command_const.dart` — OS별 설치 경로 상수
@ -35,10 +36,11 @@ last_rule_updated_at: 2026-06-01
## 제외 경로 ## 제외 경로
- `apps/runner/lib/oto/` — 비즈니스 로직·파이프라인 엔진 (cli는 진입만 담당) - `apps/runner/lib/oto/` — 비즈니스 로직·파이프라인 엔진 (cli는 진입만 담당)
- `apps/runner/lib/cli/commands/command_agent.dart` — OTO Edge agent 실행 명령 (`agent` 도메인) - `apps/runner/lib/cli/commands/command_agent.dart` — OTO Server runner agent 실행 명령 (`agent` 도메인)
- `apps/runner/lib/cli/commands/command_scheduler.dart` — scheduler 명령 파싱과 등록/실행 진입점 (`scheduler` 도메인) - `apps/runner/lib/cli/commands/command_scheduler.dart` — scheduler 명령 파싱과 등록/실행 진입점 (`scheduler` 도메인)
- `apps/runner/lib/cli/commands/scheduler/` — 스케줄러 실행/등록/OS별 백그라운드 처리 (`scheduler` 도메인) - `apps/runner/lib/cli/commands/scheduler/` — 스케줄러 실행/등록/OS별 백그라운드 처리 (`scheduler` 도메인)
- `apps/runner/lib/oto/agent/` — agent 설정/등록/Edge 통신 (`agent` 도메인) - `apps/runner/lib/oto/agent/` — agent 설정, OTO Server 등록/job 통신, legacy iop Edge compatibility (`agent` 도메인)
- `apps/runner/lib/oto/core/output_port.dart` — runner 출력 포트 추상화 (`core` 도메인)
- `apps/runner/assets/script/shell/oto_agent_bootstrap.sh` — agent 설치/실행 bootstrap (`agent` 도메인) - `apps/runner/assets/script/shell/oto_agent_bootstrap.sh` — agent 설치/실행 bootstrap (`agent` 도메인)
- `apps/runner/assets/template/` — 커맨드 실행 중 사용하는 템플릿 (`command` 도메인) - `apps/runner/assets/template/` — 커맨드 실행 중 사용하는 템플릿 (`command` 도메인)
@ -57,6 +59,7 @@ last_rule_updated_at: 2026-06-01
- `CommandTemplate` — 템플릿 출력 - `CommandTemplate` — 템플릿 출력
- `CommandManager` — CLI 커맨드 등록 관리 - `CommandManager` — CLI 커맨드 등록 관리
- `RegistPath` — OS별 PATH 등록/해제 - `RegistPath` — OS별 PATH 등록/해제
- `CliRunnerOutputPort` / `setCliOutputLogHandler()``Application.build()` 출력 포트를 CLI 출력과 log handler에 연결
- `apps/runner/bin/main.dart` — CLI 초기화 시 등록할 top-level 명령 목록을 정의 - `apps/runner/bin/main.dart` — CLI 초기화 시 등록할 top-level 명령 목록을 정의
## 유지할 패턴 ## 유지할 패턴
@ -67,6 +70,7 @@ last_rule_updated_at: 2026-06-01
- `CommandExe``BuildType` 선택과 YAML 파일 읽기까지만 담당 - `CommandExe``BuildType` 선택과 YAML 파일 읽기까지만 담당
- `catalog`/`validate`처럼 JSON 출력을 지원하는 CLI는 stdout에 구조화 결과만 쓰고 일반 실행 로그는 억제한다 - `catalog`/`validate`처럼 JSON 출력을 지원하는 CLI는 stdout에 구조화 결과만 쓰고 일반 실행 로그는 억제한다
- 콘솔 출력은 `CLI.print*`, `CLI.style`, `Printer`, 또는 `CommandBase` 출력 헬퍼를 사용 - 콘솔 출력은 `CLI.print*`, `CLI.style`, `Printer`, 또는 `CommandBase` 출력 헬퍼를 사용
- `Application.build()`에 CLI 출력을 연결할 때는 `RunnerOutputPort`를 직접 구현하지 말고 `CliRunnerOutputPort` adapter를 우선 사용한다.
- CLI 변경 후 `dart analyze`를 실행하고, CLI 진입 변경이면 최소 `dart run apps/runner/bin/main.dart` 수준의 스모크 실행 가능 여부를 확인 - CLI 변경 후 `dart analyze`를 실행하고, CLI 진입 변경이면 최소 `dart run apps/runner/bin/main.dart` 수준의 스모크 실행 가능 여부를 확인
- 배포/설치 asset 변경 시 관련 CLI 설치/패키징 경로가 실제 파일명을 참조하는지 확인 - 배포/설치 asset 변경 시 관련 CLI 설치/패키징 경로가 실제 파일명을 참조하는지 확인
@ -74,7 +78,8 @@ last_rule_updated_at: 2026-06-01
- **pipeline/command**: cli는 `Application.build()`만 호출. 파이프라인·커맨드 내부를 직접 참조하지 않는다 - **pipeline/command**: cli는 `Application.build()`만 호출. 파이프라인·커맨드 내부를 직접 참조하지 않는다
- **core**: DataComposer 호출은 Application 내부에서 이루어지며 cli는 관여하지 않는다 - **core**: DataComposer 호출은 Application 내부에서 이루어지며 cli는 관여하지 않는다
- **agent**: `agent` 명령과 `CommandAgent`는 agent 도메인이다. 일반 CLI 변경에서 Edge 등록/agent config 정책을 함께 수정하지 않는다 - **core output**: `RunnerOutputPort` 계약은 core 도메인이고, CLI 색상/출력으로 변환하는 adapter만 cli 도메인이다
- **agent**: `agent` 명령과 `CommandAgent`는 agent 도메인이다. 일반 CLI 변경에서 OTO Server 등록/agent config 정책을 함께 수정하지 않는다
- **scheduler**: `CommandScheduler`, `apps/runner/lib/cli/commands/command_scheduler.dart`, `apps/runner/lib/cli/commands/scheduler/**`는 scheduler 도메인이다. 일반 CLI 변경에서 scheduler 내부 동작을 함께 수정하지 않는다 - **scheduler**: `CommandScheduler`, `apps/runner/lib/cli/commands/command_scheduler.dart`, `apps/runner/lib/cli/commands/scheduler/**`는 scheduler 도메인이다. 일반 CLI 변경에서 scheduler 내부 동작을 함께 수정하지 않는다
- **framework**: `apps/runner/bin/main.dart`는 외부 framework Application을 소비하지만 framework 의존성 자체는 framework 도메인에서 다룬다 - **framework**: `apps/runner/bin/main.dart`는 외부 framework Application을 소비하지만 framework 의존성 자체는 framework 도메인에서 다룬다
@ -82,5 +87,6 @@ last_rule_updated_at: 2026-06-01
- cli 레이어에서 Pipeline 또는 Command를 직접 인스턴스화하지 않는다 - cli 레이어에서 Pipeline 또는 Command를 직접 인스턴스화하지 않는다
- 비즈니스 로직을 cli 커맨드 핸들러에 넣지 않는다 - 비즈니스 로직을 cli 커맨드 핸들러에 넣지 않는다
- 일반 CLI 변경에 agent 등록, Edge 연결, bootstrap 스크립트 정책을 섞지 않는다 - core `RunnerOutputPort` 계약 자체를 cli 도메인에서 변경하지 않는다
- 일반 CLI 변경에 agent 등록, OTO Server/legacy Edge 연결, bootstrap 스크립트 정책을 섞지 않는다
- 일반 CLI 변경에 scheduler 명령, 등록 파일, 로그 파일, OS 시작 프로그램 로직을 섞지 않는다 - 일반 CLI 변경에 scheduler 명령, 등록 파일, 로그 파일, OS 시작 프로그램 로직을 섞지 않는다

View file

@ -1,7 +1,7 @@
--- ---
domain: command domain: command
last_rule_review_commit: 67d7b6e411b8a28d6d42cac550a29872a7ef6b7e last_rule_review_commit: 99cc06767f82a32a9106f3a483bce2b6aeed5872
last_rule_updated_at: 2026-06-01 last_rule_updated_at: 2026-06-13
--- ---
# command # command
@ -31,6 +31,7 @@ last_rule_updated_at: 2026-06-01
- `registerAllCommands()` (`command_registry.dart`) — 카테고리별 register 함수를 호출해 CommandType → Command 매핑 구성 - `registerAllCommands()` (`command_registry.dart`) — 카테고리별 register 함수를 호출해 CommandType → Command 매핑 구성
- `CommandCatalog` / `CommandCatalogEntry` (`command_catalog.dart`) — 등록된 CommandSpec 목록과 sample 존재 여부 조회 - `CommandCatalog` / `CommandCatalogEntry` (`command_catalog.dart`) — 등록된 CommandSpec 목록과 sample 존재 여부 조회
- `CommandRuntime` / `DefaultCommandRuntime` (`command_runtime.dart`) — 커맨드 외부 프로세스 실행 추상화 - `CommandRuntime` / `DefaultCommandRuntime` (`command_runtime.dart`) — 커맨드 외부 프로세스 실행 추상화
- `CommandCatalogRunnerCapabilityProvider` (`runner_command_capability_provider.dart`) — agent 등록 시 현재 command catalog를 runner capability summary로 변환
- `DataParam` (`base_data.dart`) — 모든 커맨드 파라미터의 베이스 - `DataParam` (`base_data.dart`) — 모든 커맨드 파라미터의 베이스
- `DataBuild` / `DataScheduler` (`command_data.dart`) — YAML 최상위 build/scheduler 데이터 - `DataBuild` / `DataScheduler` (`command_data.dart`) — YAML 최상위 build/scheduler 데이터
- `DataCommand` (`command_data.dart`) — 모든 커맨드에 전달되는 통합 컨테이너 - `DataCommand` (`command_data.dart`) — 모든 커맨드에 전달되는 통합 컨테이너
@ -50,6 +51,9 @@ last_rule_updated_at: 2026-06-01
| infra / external tool | `apps/runner/lib/oto/commands/aws/`, `apps/runner/lib/oto/commands/docker/`, `apps/runner/lib/oto/commands/gradle/`, `apps/runner/lib/oto/commands/infra/`, `apps/runner/lib/oto/commands/proto/` | `apps/runner/lib/oto/data/infra_data.dart`, `apps/runner/lib/oto/data/util_data.dart` | | infra / external tool | `apps/runner/lib/oto/commands/aws/`, `apps/runner/lib/oto/commands/docker/`, `apps/runner/lib/oto/commands/gradle/`, `apps/runner/lib/oto/commands/infra/`, `apps/runner/lib/oto/commands/proto/` | `apps/runner/lib/oto/data/infra_data.dart`, `apps/runner/lib/oto/data/util_data.dart` |
| shell / process / util | `apps/runner/lib/oto/commands/shell/`, `apps/runner/lib/oto/commands/process/`, `apps/runner/lib/oto/commands/util/` | `apps/runner/lib/oto/data/util_data.dart` | | shell / process / util | `apps/runner/lib/oto/commands/shell/`, `apps/runner/lib/oto/commands/process/`, `apps/runner/lib/oto/commands/util/` | `apps/runner/lib/oto/data/util_data.dart` |
현재 등록된 command type은 `CommandType` enum과 `registerAllCommands()`를 기준으로 한다.
대표 신규/확장 type은 `BuildDart`, `BuildDartCompile`, `CreateAppData`, `PublishiOS`, `TestflightStatusCheck`, `XcodeprojAddFile`, `Notarize`, `Files`, `GitPull`, `GitCheckout`, `GitReset`, `GitStashPush`, `GitStashApply`, `StringReplacePattern`, `StringIndex`를 포함한다.
커맨드 asset: 커맨드 asset:
| asset | 사용처 | | asset | 사용처 |
@ -63,6 +67,7 @@ last_rule_updated_at: 2026-06-01
- `Command.register()`에는 `CommandSpec`을 함께 전달해 category, dataModel, samplePath를 기록 - `Command.register()`에는 `CommandSpec`을 함께 전달해 category, dataModel, samplePath를 기록
- 파라미터 모델은 `DataParam` 상속 + `@JsonSerializable` - 파라미터 모델은 `DataParam` 상속 + `@JsonSerializable`
- `CommandCatalog`와 CLI `catalog` 출력은 `CommandSpec`을 기준으로 하므로 신규 커맨드의 category/dataModel/samplePath 누락 여부를 함께 확인한다 - `CommandCatalog`와 CLI `catalog` 출력은 `CommandSpec`을 기준으로 하므로 신규 커맨드의 category/dataModel/samplePath 누락 여부를 함께 확인한다
- agent runner capability는 `CommandCatalogRunnerCapabilityProvider``registerAllCommands()``Command.catalogRows`를 통해 생성하므로, command type 추가/삭제 시 capability 노출도 함께 바뀐다
- `*.g.dart``dart run build_runner build`로 생성한다. 생성 파일 직접 수정은 생성 불가한 긴급 상황에서만 한다 - `*.g.dart``dart run build_runner build`로 생성한다. 생성 파일 직접 수정은 생성 불가한 긴급 상황에서만 한다
- `getWorkspace()`: workspace 필드 → `property['workspace']``commonData.workspace` 순으로 resolve - `getWorkspace()`: workspace 필드 → `property['workspace']``commonData.workspace` 순으로 resolve
- 커맨드 파라미터는 `getParam(command)`를 통해 태그 치환과 workspace resolve를 거친 뒤 `Data*` 모델로 파싱한다 - 커맨드 파라미터는 `getParam(command)`를 통해 태그 치환과 workspace resolve를 거친 뒤 `Data*` 모델로 파싱한다
@ -78,6 +83,7 @@ last_rule_updated_at: 2026-06-01
- **core**: 태그 치환은 core가 완료한 후 DataCommand가 커맨드에 전달됨 - **core**: 태그 치환은 core가 완료한 후 DataCommand가 커맨드에 전달됨
- **cli**: CLI `catalog`/`validate`는 command/core 정보를 읽어 출력하거나 검증하지만 커맨드 실행 로직은 command 도메인에 남긴다 - **cli**: CLI `catalog`/`validate`는 command/core 정보를 읽어 출력하거나 검증하지만 커맨드 실행 로직은 command 도메인에 남긴다
- **sample**: YAML 사용 예시는 sample 도메인이 담당한다. 커맨드 파라미터 변경 시 sample 도메인과 동기화한다 - **sample**: YAML 사용 예시는 sample 도메인이 담당한다. 커맨드 파라미터 변경 시 sample 도메인과 동기화한다
- **agent**: agent 등록 payload에 들어가는 command catalog summary는 command 도메인이 제공하고, agent 도메인은 `RunnerCapabilityProvider` interface를 소비한다
- **framework**: `dart_framework``ProcessExecutor`, path/system 유틸은 외부 런타임 의존성으로 사용한다. OTO 비즈니스 로직을 framework 의존성 쪽으로 옮기지 않는다 - **framework**: `dart_framework``ProcessExecutor`, path/system 유틸은 외부 런타임 의존성으로 사용한다. OTO 비즈니스 로직을 framework 의존성 쪽으로 옮기지 않는다
## 금지 사항 ## 금지 사항

View file

@ -1,15 +1,15 @@
--- ---
domain: core domain: core
last_rule_review_commit: 67d7b6e411b8a28d6d42cac550a29872a7ef6b7e last_rule_review_commit: 99cc06767f82a32a9106f3a483bce2b6aeed5872
last_rule_updated_at: 2026-06-01 last_rule_updated_at: 2026-06-13
--- ---
# core # core
## 목적 / 책임 ## 목적 / 책임
파이프라인 실행 전 단계에서 YAML 파싱, Jenkins 환경 변수 합성, 태그 치환, 실행 컨텍스트 생성을 담당하는 공통 인프라 레이어다. `Application` 싱글턴이 전체 빌드 흐름을 오케스트레이션한다. 파이프라인 실행 전 단계에서 YAML 파싱, Jenkins 환경 변수 합성, 태그 치환, 실행 컨텍스트 생성, 빌드 결과/step event/artifact 결과 모델을 담당하는 공통 인프라 레이어다. `Application` 싱글턴이 전체 빌드 흐름을 오케스트레이션한다.
런타임 property, command state, build data 생성처럼 pipeline/command가 공유하는 실행 컨텍스트도 이 도메인에서 시작된다. 런타임 property, command state, build data, output port처럼 pipeline/command/agent가 공유하는 실행 컨텍스트도 이 도메인에서 시작된다.
## 포함 경로 ## 포함 경로
@ -23,7 +23,7 @@ last_rule_updated_at: 2026-06-01
- `apps/runner/lib/oto/pipeline/` — 실행 흐름 (core 처리 이후) - `apps/runner/lib/oto/pipeline/` — 실행 흐름 (core 처리 이후)
- `apps/runner/lib/oto/commands/` — 커맨드 구현체 (core 결과물을 소비) - `apps/runner/lib/oto/commands/` — 커맨드 구현체 (core 결과물을 소비)
- `apps/runner/lib/oto/agent/` — OTO Edge agent 설정/등록/통신 (`agent` 도메인) - `apps/runner/lib/oto/agent/` — OTO Server runner agent 설정/등록/remote job 통신 (`agent` 도메인)
- `apps/runner/assets/script/`의 빌드/패키징 보조 스크립트 — CLI/배포 보조 asset이며 core가 직접 해석하지 않는다 - `apps/runner/assets/script/`의 빌드/패키징 보조 스크립트 — CLI/배포 보조 asset이며 core가 직접 해석하지 않는다
## 주요 구성 요소 ## 주요 구성 요소
@ -33,6 +33,9 @@ last_rule_updated_at: 2026-06-01
- `DefinedData` (`defined_data.dart`) — 내장 YAML 템플릿 (빌트인 정의) - `DefinedData` (`defined_data.dart`) — 내장 YAML 템플릿 (빌트인 정의)
- `ExecutionContext` (`execution_context.dart`) — commonData, property, command state, command map 런타임 컨테이너 - `ExecutionContext` (`execution_context.dart`) — commonData, property, command state, command map 런타임 컨테이너
- `BuildResult` (`build_result.dart`) — CLI 진입점에 전달되는 빌드 성공/실패 결과 - `BuildResult` (`build_result.dart`) — CLI 진입점에 전달되는 빌드 성공/실패 결과
- `BuildArtifact` (`build_result.dart`) — remote consumer에 보고할 artifact 선언 metadata
- `RunnerOutputPort` / `RunnerOutputStyle` / `NoopRunnerOutputPort` (`output_port.dart`) — CLI/agent가 교체할 수 있는 runner 출력 포트 계약
- `StepEvent` (`execution_context.dart`) — pipeline step started/completed/failed event 직렬화 모델
- `YamlValidationResult` (`application.dart`) — YAML 검증 CLI가 사용하는 구조화 검증 결과 - `YamlValidationResult` (`application.dart`) — YAML 검증 CLI가 사용하는 구조화 검증 결과
- `SystemRuntime` / `DefaultSystemRuntime` (`system_runtime.dart`) — OS 환경·프로세스 실행 추상화 - `SystemRuntime` / `DefaultSystemRuntime` (`system_runtime.dart`) — OS 환경·프로세스 실행 추상화
- `MattermostSender` / `MattermostData` (`utils/mattermost/`) — 공통 알림 헬퍼 - `MattermostSender` / `MattermostData` (`utils/mattermost/`) — 공통 알림 헬퍼
@ -46,6 +49,9 @@ last_rule_updated_at: 2026-06-01
- 커맨드 등록은 `registerAllCommands()` 호출 이후 command catalog validation과 pipeline validate를 수행 - 커맨드 등록은 `registerAllCommands()` 호출 이후 command catalog validation과 pipeline validate를 수행
- 실행 없는 YAML 검증은 `Application.validateYamlContent()`에서 build map, command list, command map, pipeline 초기화 순서로 확인한다 - 실행 없는 YAML 검증은 `Application.validateYamlContent()`에서 build map, command list, command map, pipeline 초기화 순서로 확인한다
- property 기본값에 `workspace`가 없으면 `Application.current`를 채우는 흐름을 유지 - property 기본값에 `workspace`가 없으면 `Application.current`를 채우는 흐름을 유지
- `Application.build()` 시작 시 `ExecutionContext.output`, step event, command map, command state를 새 실행 단위에 맞게 초기화한다
- `BuildResult``ExecutionContext.stepEvents`와 전달받은 artifact 선언을 복사해서 반환한다
- 출력은 직접 `print`를 추가하기보다 `RunnerOutputPort` 또는 기존 `Application.log()` 경로를 사용한다
- 테스트 가능한 OS/프로세스 의존 로직은 `SystemRuntime`을 통해 주입 가능한 구조를 유지 - 테스트 가능한 OS/프로세스 의존 로직은 `SystemRuntime`을 통해 주입 가능한 구조를 유지
- Jenkins env helper script 변경 시 `DataComposer`의 호출 경로와 환경 변수 파싱 결과를 함께 확인한다 - Jenkins env helper script 변경 시 `DataComposer`의 호출 경로와 환경 변수 파싱 결과를 함께 확인한다
- core 변경 후 `dart analyze`를 실행하고, 태그/파싱 변경이면 관련 단위 테스트 또는 최소 샘플 YAML 파싱 검증을 추가/확인한다 - core 변경 후 `dart analyze`를 실행하고, 태그/파싱 변경이면 관련 단위 테스트 또는 최소 샘플 YAML 파싱 검증을 추가/확인한다
@ -53,15 +59,17 @@ last_rule_updated_at: 2026-06-01
## 다른 도메인과의 경계 ## 다른 도메인과의 경계
- **pipeline**: DataComposer가 DataCommand 리스트 생성을 완료한 후 Pipeline이 실행 시작 - **pipeline**: DataComposer가 DataCommand 리스트 생성을 완료한 후 Pipeline이 실행 시작
- **pipeline events**: pipeline은 step event를 기록하지만 event 모델과 저장 위치는 core `ExecutionContext`
- **command**: 커맨드 실행 중 쓰기 태그(`<@...>`) 처리는 TagSystem에 위임 - **command**: 커맨드 실행 중 쓰기 태그(`<@...>`) 처리는 TagSystem에 위임
- **cli/scheduler**: build type, YAML content, scheduler build data는 cli/scheduler에서 넘기지만 실제 build 흐름과 `BuildResult` 생성은 Application이 담당 - **cli/scheduler**: build type, YAML content, scheduler build data는 cli/scheduler에서 넘기지만 실제 build 흐름과 `BuildResult` 생성은 Application이 담당
- **agent**: agent config 파싱과 Edge 등록은 core가 아니라 agent 도메인이다. core의 YAML 파싱/검증 흐름과 agent bootstrap config를 섞지 않는다 - **cli output**: CLI 색상/출력 adapter는 cli 도메인이고, output port interface는 core 도메인이다
- **agent**: agent config 파싱, OTO Server 등록, remote job claim/report는 core가 아니라 agent 도메인이다. core의 YAML 파싱/검증 흐름과 agent bootstrap config를 섞지 않는다
- **sample**: 태그 문법이나 YAML 구조가 변경되면 sample 도메인의 YAML 예시를 함께 점검 - **sample**: 태그 문법이나 YAML 구조가 변경되면 sample 도메인의 YAML 예시를 함께 점검
## 금지 사항 ## 금지 사항
- core에서 외부 시스템(Git, Jenkins API 등)을 직접 호출하지 않는다 - core에서 외부 시스템(Git, Jenkins API 등)을 직접 호출하지 않는다
- core에서 OTO Edge agent 등록 또는 proto socket 통신을 수행하지 않는다 - core에서 OTO Server/iop Edge agent 등록, HTTP job polling, proto socket 통신을 수행하지 않는다
- 커맨드별 파싱 로직을 DataComposer에 넣지 않는다 - 커맨드별 파싱 로직을 DataComposer에 넣지 않는다
- pipeline 흐름 제어(if/foreach/switch 등)를 core에 넣지 않는다 - pipeline 흐름 제어(if/foreach/switch 등)를 core에 넣지 않는다
- command별 실행 결과 처리 로직을 `Application`에 추가하지 않는다 - command별 실행 결과 처리 로직을 `Application`에 추가하지 않는다

View file

@ -1,7 +1,7 @@
--- ---
domain: framework domain: framework
last_rule_review_commit: 67d7b6e411b8a28d6d42cac550a29872a7ef6b7e last_rule_review_commit: 99cc06767f82a32a9106f3a483bce2b6aeed5872
last_rule_updated_at: 2026-06-01 last_rule_updated_at: 2026-06-13
--- ---
# framework # framework
@ -9,17 +9,23 @@ last_rule_updated_at: 2026-06-01
## 목적 / 책임 ## 목적 / 책임
현재 프로젝트에는 `lib/framework/` 모듈이 없다. 현재 프로젝트에는 `lib/framework/` 모듈이 없다.
이 도메인은 runner, client, console, core service의 패키지 선언(manifest), 분석기(analyzer/lint), protobuf 계약 정의 및 생성 코드 관리, 외부 의존성 경계와 빌드 도구 설정을 기록한다. 이 도메인은 runner, client, console, core service의 패키지 선언(manifest), lockfile, 분석기(analyzer/lint), protobuf 계약 정의 및 생성 코드 관리, 외부 의존성 경계와 빌드 도구 설정을 기록한다.
단, 전용 도메인 규칙(dedicated domain rule)이 아직 존재하지 않는 `apps/client/lib/**`, `packages/flutter/oto_console/lib/**`, `services/core/internal/**` 등의 구현 코드가 가진 구체적인 비즈니스 동작 규칙은 이 framework 도메인이나 기존 runner 도메인 규칙으로 무리하게 확장하여 단정하지 않고, 추후 별도 도메인 규칙 생성 또는 후속 milestone 작업을 통해 정리한다. 단, 전용 도메인 규칙(dedicated domain rule)이 아직 존재하지 않는 `apps/client/lib/**`, `packages/flutter/oto_console/lib/**`, `services/core/internal/**` 등의 구현 코드가 가진 구체적인 비즈니스 동작 규칙은 이 framework 도메인이나 기존 runner 도메인 규칙으로 무리하게 확장하여 단정하지 않고, 추후 별도 도메인 규칙 생성 또는 후속 milestone 작업을 통해 정리한다.
## 포함 경로 ## 포함 경로
- `Makefile` — runner/client/core 검증 명령, proto 생성 명령, 로컬 실행 포트 기본값
- `apps/runner/pubspec.yaml` — runner Dart dependency와 `dart_framework` Git 의존성 선언 - `apps/runner/pubspec.yaml` — runner Dart dependency와 `dart_framework` Git 의존성 선언
- `apps/runner/pubspec.lock` — runner dependency resolution snapshot
- `apps/runner/analysis_options.yaml` — runner Dart analyzer/lint 기준 - `apps/runner/analysis_options.yaml` — runner Dart analyzer/lint 기준
- `apps/client/pubspec.yaml` — Flutter client dependency 선언 - `apps/client/pubspec.yaml` — Flutter client dependency 선언
- `apps/client/pubspec.lock` — Flutter client dependency resolution snapshot
- `apps/client/analysis_options.yaml` — Flutter client analyzer/lint 기준 - `apps/client/analysis_options.yaml` — Flutter client analyzer/lint 기준
- `packages/flutter/oto_console/pubspec.yaml` — embeddable console package dependency 선언 - `packages/flutter/oto_console/pubspec.yaml` — embeddable console package dependency 선언
- `packages/flutter/oto_console/analysis_options.yaml` — console package analyzer/lint 기준
- `services/core/go.mod` — Go core service dependency 선언 - `services/core/go.mod` — Go core service dependency 선언
- `services/core/go.sum` — Go core service dependency checksum
- `services/core/oto/``proto/oto/runner.proto`에서 생성된 Go protobuf 코드
- `proto/` — runner/server protobuf 계약 정의 - `proto/` — runner/server protobuf 계약 정의
## 제외 경로 ## 제외 경로
@ -35,17 +41,22 @@ last_rule_updated_at: 2026-06-01
- `dart_framework/platform/isolate_manager.dart` — CLI 실행/스케줄러 isolate 처리에서 사용 - `dart_framework/platform/isolate_manager.dart` — CLI 실행/스케줄러 isolate 처리에서 사용
- `dart_framework/utils/*``simpleFuture`, path/system/string/os startup 유틸 사용 - `dart_framework/utils/*``simpleFuture`, path/system/string/os startup 유틸 사용
- `dart_framework/log/log.dart``Application.logWithType()`의 로그 타입에 사용 - `dart_framework/log/log.dart``Application.logWithType()`의 로그 타입에 사용
- `proto_socket`agent Edge 등록 통신에서 사용하는 workspace 상위 path dependency - `proto_socket`legacy iop Edge compatibility 경로에서 사용하는 workspace 상위 path dependency
- `protobuf` / `fixnum` — generated protobuf 코드 런타임 의존성 - `protobuf` / `fixnum` — generated protobuf 코드 런타임 의존성
- `resource_importer``apps/runner/lib/resources.resource_importer.dart` 생성 파일과 asset 임베딩 설정 - `resource_importer``apps/runner/lib/resources.resource_importer.dart` 생성 파일과 asset 임베딩 설정
- `proto/oto/runner.proto` — OTO Server runner 등록, heartbeat, bootstrap, job claim, execution/log/artifact report, cancel/status/self-update 계약
- `services/core/oto/runner.pb.go``make proto-go` 생성물
- `apps/runner/lib/oto/agent/oto/*.pb*.dart``make proto-dart` 생성물
## 유지할 패턴 ## 유지할 패턴
- 프로세스 실행은 `ProcessExecutor.start()` (스트리밍, stdout/stderr 실시간 수신) 또는 `ProcessExecutor.run()` (블로킹, 결과만 필요) 중 목적에 맞게 선택 - 프로세스 실행은 `ProcessExecutor.start()` (스트리밍, stdout/stderr 실시간 수신) 또는 `ProcessExecutor.run()` (블로킹, 결과만 필요) 중 목적에 맞게 선택
- `dart_framework` API 사용 시 기존 import 패턴을 따른다 - `dart_framework` API 사용 시 기존 import 패턴을 따른다
- 외부 의존성 ref 변경은 각 `pubspec.yaml` 또는 `go.mod`에서 수행하고, 변경 후 패키지 갱신 및 `dart analyze` 또는 빌드 확인을 한다 - 외부 의존성 ref 변경은 각 `pubspec.yaml` 또는 `go.mod`에서 수행하고, 변경 후 패키지 갱신 및 `dart analyze` 또는 빌드 확인을 한다
- tracked lockfile이 있는 package의 dependency 변경은 대응하는 `pubspec.lock` 또는 `go.sum` 갱신 여부를 확인한다
- analyzer/lint 기준 변경은 기존 코드 전체에 영향을 줄 수 있으므로 `dart analyze` 결과와 필요한 수정 범위를 함께 확인한다 - analyzer/lint 기준 변경은 기존 코드 전체에 영향을 줄 수 있으므로 `dart analyze` 결과와 필요한 수정 범위를 함께 확인한다
- generated protobuf lint 예외는 `analysis_options.yaml`의 analyzer exclude 또는 파일 생성 주석으로 관리한다 - generated protobuf lint 예외는 `analysis_options.yaml`의 analyzer exclude 또는 파일 생성 주석으로 관리한다
- protobuf 계약 변경 후 `make proto-go``make proto-dart`를 실행해 Go/Dart 생성물을 함께 갱신한다
- 로컬에 `lib/framework/`를 되살리는 대신 필요한 OTO 로직은 `apps/runner/lib/oto/` 또는 `apps/runner/lib/cli/`의 해당 도메인에 둔다 - 로컬에 `lib/framework/`를 되살리는 대신 필요한 OTO 로직은 `apps/runner/lib/oto/` 또는 `apps/runner/lib/cli/`의 해당 도메인에 둔다
## 다른 도메인과의 경계 ## 다른 도메인과의 경계
@ -53,7 +64,8 @@ last_rule_updated_at: 2026-06-01
- **core**: `apps/runner/lib/oto/application.dart`는 OTO 오케스트레이터이며 외부 framework의 Application과 별개다 - **core**: `apps/runner/lib/oto/application.dart`는 OTO 오케스트레이터이며 외부 framework의 Application과 별개다
- **cli/scheduler**: isolate, process, OS startup 유틸을 소비하지만 스케줄러 정책은 scheduler 도메인에 둔다 - **cli/scheduler**: isolate, process, OS startup 유틸을 소비하지만 스케줄러 정책은 scheduler 도메인에 둔다
- **command**: 커맨드들은 `ProcessExecutor`를 소비하지만 커맨드별 비즈니스 로직은 command 도메인에 둔다 - **command**: 커맨드들은 `ProcessExecutor`를 소비하지만 커맨드별 비즈니스 로직은 command 도메인에 둔다
- **agent**: `proto_socket`, `protobuf`, `fixnum` 의존성은 framework 도메인에서 관리하지만 Edge 등록 프로토콜과 agent 정책은 agent 도메인에 둔다 - **agent**: `http`, `proto_socket`, `protobuf`, `fixnum` 의존성은 framework 도메인에서 관리하지만 OTO Server/legacy iop protocol 사용 방식과 agent 정책은 agent 도메인에 둔다
- **services/core/internal**: Go core service business logic은 아직 dedicated domain rule이 없다. framework 도메인은 `go.mod`, `go.sum`, generated proto, build/test command 경계만 다룬다
## 금지 사항 ## 금지 사항
@ -61,3 +73,4 @@ last_rule_updated_at: 2026-06-01
- 외부 `dart_framework` 내부 코드를 이 저장소의 도메인 rule 기준으로 직접 수정한다고 가정하지 않는다 - 외부 `dart_framework` 내부 코드를 이 저장소의 도메인 rule 기준으로 직접 수정한다고 가정하지 않는다
- OTO 비즈니스 로직(파이프라인, 커맨드 등록 등)을 framework 의존성 변경으로 해결하려 하지 않는다 - OTO 비즈니스 로직(파이프라인, 커맨드 등록 등)을 framework 의존성 변경으로 해결하려 하지 않는다
- generated dependency/runtime 코드를 수동 수정으로 문제 해결하려 하지 않는다 - generated dependency/runtime 코드를 수동 수정으로 문제 해결하려 하지 않는다
- dedicated domain rule이 없는 `apps/client/lib/**`, `packages/flutter/oto_console/lib/**`, `services/core/internal/**`의 비즈니스 동작을 framework 규칙으로 단정하지 않는다

View file

@ -1,7 +1,7 @@
--- ---
domain: pipeline domain: pipeline
last_rule_review_commit: 67d7b6e411b8a28d6d42cac550a29872a7ef6b7e last_rule_review_commit: 99cc06767f82a32a9106f3a483bce2b6aeed5872
last_rule_updated_at: 2026-06-01 last_rule_updated_at: 2026-06-13
--- ---
# pipeline # pipeline
@ -35,6 +35,7 @@ YAML에서 파싱된 `DataCommand` 리스트를 순차 실행하고, 조건 분
- `PipelineContain` — 중첩 파이프라인 - `PipelineContain` — 중첩 파이프라인
- `PipelineWaitUntil` / `PipelineWaitUntilSeconds` — 조건 기반 또는 초 단위 대기 흐름 - `PipelineWaitUntil` / `PipelineWaitUntilSeconds` — 조건 기반 또는 초 단위 대기 흐름
- `DataPipeline`, `DataIf`, `DataForeach`, `DataWhile`, `DataSwitch`, `DataExeHandle` — pipeline YAML 구조 검증/파싱 모델 - `DataPipeline`, `DataIf`, `DataForeach`, `DataWhile`, `DataSwitch`, `DataExeHandle` — pipeline YAML 구조 검증/파싱 모델
- `StepEvent` 기록 — `Pipeline.execute()`가 각 workflow task의 started/completed/failed event를 core `ExecutionContext`에 기록
## 유지할 패턴 ## 유지할 패턴
@ -43,6 +44,7 @@ YAML에서 파싱된 `DataCommand` 리스트를 순차 실행하고, 조건 분
- 새 흐름 제어 유형은 `Pipeline.exeMap`에 등록하고, 필요한 데이터 모델은 `apps/runner/lib/oto/data/pipeline_data.dart`에 둔다 - 새 흐름 제어 유형은 `Pipeline.exeMap`에 등록하고, 필요한 데이터 모델은 `apps/runner/lib/oto/data/pipeline_data.dart`에 둔다
- 파이프라인 validate 단계에서 workflow task key, command ID 존재 여부, 하위 task 구조를 가능한 한 먼저 확인한다 - 파이프라인 validate 단계에서 workflow task key, command ID 존재 여부, 하위 task 구조를 가능한 한 먼저 확인한다
- 조건식은 `PipelineCondition`의 type caster와 `Command.replaceTagValue()` 흐름을 유지한다 - 조건식은 `PipelineCondition`의 type caster와 `Command.replaceTagValue()` 흐름을 유지한다
- workflow task 실행 전후 event는 core `ExecutionContext.addStepEvent()`에 기록하고, event schema 자체는 core 도메인에서 관리한다
- pipeline 변경 후 `dart analyze`를 실행하고, if/foreach/while/switch/wait-until 중 영향을 받는 샘플 YAML 파싱 또는 실행 테스트를 확인한다 - pipeline 변경 후 `dart analyze`를 실행하고, if/foreach/while/switch/wait-until 중 영향을 받는 샘플 YAML 파싱 또는 실행 테스트를 확인한다
## 다른 도메인과의 경계 ## 다른 도메인과의 경계
@ -50,6 +52,7 @@ YAML에서 파싱된 `DataCommand` 리스트를 순차 실행하고, 조건 분
- **command**: `Pipeline``Command.byType()`을 호출하는 시점이 경계. 커맨드 내부 로직은 pipeline이 모른다 - **command**: `Pipeline``Command.byType()`을 호출하는 시점이 경계. 커맨드 내부 로직은 pipeline이 모른다
- **command data**: `DataCommand`와 커맨드 파라미터 모델은 command 도메인이고, workflow 흐름 모델인 `pipeline_data.dart`만 pipeline 도메인이다 - **command data**: `DataCommand`와 커맨드 파라미터 모델은 command 도메인이고, workflow 흐름 모델인 `pipeline_data.dart`만 pipeline 도메인이다
- **core**: `DataComposer`가 YAML → `DataCommand` 변환을 마친 후 pipeline이 실행 시작 - **core**: `DataComposer`가 YAML → `DataCommand` 변환을 마친 후 pipeline이 실행 시작
- **core events**: step event 저장소와 `BuildResult` 직렬화는 core 도메인이다. pipeline은 실행 지점에서 event를 추가만 한다
- **sample**: workflow 문법 변경 시 `apps/runner/assets/yaml/sample/02_*`~`05_*`와 README 흐름 제어 예시를 함께 점검 - **sample**: workflow 문법 변경 시 `apps/runner/assets/yaml/sample/02_*`~`05_*`와 README 흐름 제어 예시를 함께 점검
## 금지 사항 ## 금지 사항
@ -58,3 +61,4 @@ YAML에서 파싱된 `DataCommand` 리스트를 순차 실행하고, 조건 분
- 커맨드별 비즈니스 로직을 pipeline에 넣지 않는다 - 커맨드별 비즈니스 로직을 pipeline에 넣지 않는다
- pipeline에서 파일 시스템, 네트워크, shell 실행을 직접 수행하지 않는다 - pipeline에서 파일 시스템, 네트워크, shell 실행을 직접 수행하지 않는다
- command param의 세부 필드를 pipeline에서 해석하지 않는다 - command param의 세부 필드를 pipeline에서 해석하지 않는다
- step event schema나 build result JSON schema를 pipeline 도메인에서 바꾸지 않는다

View file

@ -1,7 +1,7 @@
--- ---
domain: sample domain: sample
last_rule_review_commit: 67d7b6e411b8a28d6d42cac550a29872a7ef6b7e last_rule_review_commit: 99cc06767f82a32a9106f3a483bce2b6aeed5872
last_rule_updated_at: 2026-06-01 last_rule_updated_at: 2026-06-13
--- ---
# sample # sample
@ -35,17 +35,17 @@ AI가 파이프라인 YAML을 작성하거나 검토할 때 가장 먼저 읽는
| `03_pipeline_foreach.yaml` | foreach (List·Map 순회, 중첩) | | `03_pipeline_foreach.yaml` | foreach (List·Map 순회, 중첩) |
| `04_pipeline_exe_handle.yaml` | exe-handle (on-success / on-fail) | | `04_pipeline_exe_handle.yaml` | exe-handle (on-success / on-fail) |
| `05_pipeline_while_switch.yaml` | while, switch, wait-until | | `05_pipeline_while_switch.yaml` | while, switch, wait-until |
| `06_git.yaml` | Git, GitCommit, GitPush, GitRev, GitCount, GitBranch | | `06_git.yaml` | Git, GitPull, GitCheckout, GitCommit, GitPush, GitRev, GitCount, GitBranch, GitStashPush, GitStashApply, GitReset |
| `07_file.yaml` | Copy, Delete, FileRead, FileWrite, Zip, FileInfo | | `07_file.yaml` | Copy, Delete, FileRead, FileWrite, Zip, FileInfo |
| `07_file_utils.yaml` | DirectoryCreate, Rename 등 파일 보조 커맨드 | | `07_file_utils.yaml` | DirectoryCreate, Files, Rename 등 파일 보조 커맨드 |
| `08_notification.yaml` | Slack, SlackBuild, Mattermost, MattermostBuild | | `08_notification.yaml` | Slack, SlackBuild, Mattermost, MattermostBuild |
| `09_network.yaml` | WebRequest, WebFile, Upload(FTP), Download(FTP) | | `09_network.yaml` | WebRequest, WebFile, Upload(FTP), Download(FTP), GitHub, GitHubPullRequestCreate, GitHubPullRequestList, GitHubPullRequestClose |
| `10_build_ios.yaml` | BuildiOS, ArchiveiOS, ExportiOS, TestflightUpload, TestflightDistribute | | `10_build_ios.yaml` | BuildiOS, ArchiveiOS, ExportiOS, TestflightUpload, TestflightStatusCheck, TestflightDistribute, CodeSign, ProductBuild, Notarize |
| `10_build_tools.yaml` | BuildDotNet, BuildMSBuild, CodeSign, ProductBuild 등 빌드 보조 도구 | | `10_build_tools.yaml` | XcodeprojAddFile, BuildDotNet, BuildMSBuild, PublishiOS 등 빌드 보조 도구 |
| `11_build_flutter.yaml` | BuildFlutter (멀티플랫폼) | | `11_build_flutter.yaml` | BuildFlutter (멀티플랫폼) |
| `11_utils.yaml` | URLInfo, Delay | | `11_utils.yaml` | URLInfo, Delay |
| `12_scheduler.yaml` | scheduler 섹션 (cron / interval) | | `12_scheduler.yaml` | scheduler 섹션 (cron / interval) |
| `13_string_json.yaml` | StringSub, StringReplace, JsonReader, JsonReaderFile, JsonWriterFile | | `13_string_json.yaml` | StringSub, StringReplace, StringReplacePattern, StringIndex, JsonReader, JsonReaderFile, JsonWriterFile |
| `14_shell_process.yaml` | Shell, ShellFile, ProcessRun, ProcessKill, ProcessPortUse | | `14_shell_process.yaml` | Shell, ShellFile, ProcessRun, ProcessKill, ProcessPortUse |
| `15_smb_auth.yaml` | SMBAuth | | `15_smb_auth.yaml` | SMBAuth |
| `16_docker.yaml` | Docker | | `16_docker.yaml` | Docker |
@ -93,7 +93,7 @@ AI가 파이프라인 YAML을 작성하거나 검토할 때 가장 먼저 읽는
## 유지할 패턴 ## 유지할 패턴
- 파일명은 `NN_카테고리.yaml` 형식 (번호 + 언더스코어 + 카테고리) - 파일명은 `NN_카테고리.yaml` 형식 (번호 + 언더스코어 + 카테고리)
- 각 파일 상단에 `# [샘플] 제목` 주석으로 목적 명시 - 각 파일은 YAML document marker `---`로 시작하고, 바로 아래 `# [샘플] 제목` 주석으로 목적을 명시한다
- 실제 작동 가능한 파라미터 구조를 유지한다 (추측 값 사용 금지) - 실제 작동 가능한 파라미터 구조를 유지한다 (추측 값 사용 금지)
- 새 커맨드가 추가되면 관련 샘플 파일도 함께 갱신한다 - 새 커맨드가 추가되면 관련 샘플 파일도 함께 갱신한다
- 샘플은 placeholder 값을 사용하고 실제 토큰·비밀번호·API 키를 넣지 않는다 - 샘플은 placeholder 값을 사용하고 실제 토큰·비밀번호·API 키를 넣지 않는다

View file

@ -1,7 +1,7 @@
--- ---
domain: scheduler domain: scheduler
last_rule_review_commit: 67d7b6e411b8a28d6d42cac550a29872a7ef6b7e last_rule_review_commit: 99cc06767f82a32a9106f3a483bce2b6aeed5872
last_rule_updated_at: 2026-06-01 last_rule_updated_at: 2026-06-13
--- ---
# scheduler # scheduler

View file

@ -152,12 +152,18 @@ proto/ # OTO runner/server protobuf contract
| `apps/runner/assets/bin/**` | cli | `agent-ops/rules/project/domain/cli/rules.md` | | `apps/runner/assets/bin/**` | cli | `agent-ops/rules/project/domain/cli/rules.md` |
| `apps/runner/assets/script/shell/oto_agent_bootstrap.sh` | agent | `agent-ops/rules/project/domain/agent/rules.md` | | `apps/runner/assets/script/shell/oto_agent_bootstrap.sh` | agent | `agent-ops/rules/project/domain/agent/rules.md` |
| `apps/runner/assets/script/**` | cli | `agent-ops/rules/project/domain/cli/rules.md` | | `apps/runner/assets/script/**` | cli | `agent-ops/rules/project/domain/cli/rules.md` |
| `Makefile` | framework | `agent-ops/rules/project/domain/framework/rules.md` |
| `apps/runner/pubspec.yaml` | framework | `agent-ops/rules/project/domain/framework/rules.md` | | `apps/runner/pubspec.yaml` | framework | `agent-ops/rules/project/domain/framework/rules.md` |
| `apps/runner/pubspec.lock` | framework | `agent-ops/rules/project/domain/framework/rules.md` |
| `apps/runner/analysis_options.yaml` | framework | `agent-ops/rules/project/domain/framework/rules.md` | | `apps/runner/analysis_options.yaml` | framework | `agent-ops/rules/project/domain/framework/rules.md` |
| `apps/client/pubspec.yaml` | framework | `agent-ops/rules/project/domain/framework/rules.md` | | `apps/client/pubspec.yaml` | framework | `agent-ops/rules/project/domain/framework/rules.md` |
| `apps/client/pubspec.lock` | framework | `agent-ops/rules/project/domain/framework/rules.md` |
| `apps/client/analysis_options.yaml` | framework | `agent-ops/rules/project/domain/framework/rules.md` | | `apps/client/analysis_options.yaml` | framework | `agent-ops/rules/project/domain/framework/rules.md` |
| `packages/flutter/oto_console/pubspec.yaml` | framework | `agent-ops/rules/project/domain/framework/rules.md` | | `packages/flutter/oto_console/pubspec.yaml` | framework | `agent-ops/rules/project/domain/framework/rules.md` |
| `packages/flutter/oto_console/analysis_options.yaml` | framework | `agent-ops/rules/project/domain/framework/rules.md` |
| `services/core/go.mod` | framework | `agent-ops/rules/project/domain/framework/rules.md` | | `services/core/go.mod` | framework | `agent-ops/rules/project/domain/framework/rules.md` |
| `services/core/go.sum` | framework | `agent-ops/rules/project/domain/framework/rules.md` |
| `services/core/oto/**` | framework | `agent-ops/rules/project/domain/framework/rules.md` |
| `proto/**` | framework | `agent-ops/rules/project/domain/framework/rules.md` | | `proto/**` | framework | `agent-ops/rules/project/domain/framework/rules.md` |
`test/**`는 별도 도메인으로 고정하지 않는다. 테스트 변경 시 검증 대상 production 경로의 domain rule을 읽고, 여러 도메인을 검증하는 테스트면 관련 domain rule을 함께 읽는다. `test/**`는 별도 도메인으로 고정하지 않는다. 테스트 변경 시 검증 대상 production 경로의 domain rule을 읽고, 여러 도메인을 검증하는 테스트면 관련 domain rule을 함께 읽는다.

View file

@ -23,6 +23,9 @@ OTO는 YAML 기반 빌드/배포 파이프라인을 실행하는 Dart CLI에서
- [완료] 메시지 기반 빌드 에이전트 - [완료] 메시지 기반 빌드 에이전트
- 경로: `agent-roadmap/archive/phase/message-based-build-agent/PHASE.md` - 경로: `agent-roadmap/archive/phase/message-based-build-agent/PHASE.md`
- 요약: `oto agent` 또는 `oto daemon` 모드에서 OTO Server와 양방향 메시지 통신을 사용하는 build/deploy 전용 runner 경계를 정리하고 archive로 이동했다. - 요약: `oto agent` 또는 `oto daemon` 모드에서 OTO Server와 양방향 메시지 통신을 사용하는 build/deploy 전용 runner 경계를 정리하고 archive로 이동했다.
- [계획] Control Plane 제품 표면 완성
- 경로: `agent-roadmap/phase/control-plane-product-surface/PHASE.md`
- 요약: 현재 분리된 Core API, Flutter client, runner bootstrap 경계를 실제 운영 가능한 UI 스켈레톤과 OS별 설치 흐름으로 연결한다.
## 로딩 정책 ## 로딩 정책

View file

@ -0,0 +1,30 @@
# Phase: Control Plane 제품 표면 완성
## 상태
[계획]
## 목표
현재 분리된 OTO Core API 서버, Flutter client, runner bootstrap 경계를 실제 사용자가 조작할 수 있는 Control Plane 제품 표면으로 끌어올린다.
먼저 Flutter UI 스켈레톤을 만들어 Control Plane의 주요 화면과 연결 지점을 고정하고, 이어서 OTO Core bootstrap 흐름이 Linux, macOS, Windows 대상 runner 설치를 지원하도록 확장한다.
## Milestone 흐름
완료된 Milestone은 archive 경로를 가리키고, 검토중, 진행중, 계획, 스케치 또는 보류 Milestone은 이 Phase 하위 `milestones/` 경로를 가리킨다.
완료, 검토중, 진행중, 계획, 스케치 순서로 두어 아래로 갈수록 미래 작업에 가까워지게 정렬한다.
스케치 Milestone은 아직 구현 가능한 계획이 아니므로 계획 Milestone보다 아래에 둔다.
- [계획] Flutter 콘솔 스켈레톤
- 경로: `agent-roadmap/phase/control-plane-product-surface/milestones/flutter-console-skeleton.md`
- 요약: `apps/client``packages/flutter/oto_console`에 Control Plane 주요 화면, 상태 표시, 빈 상태, Core 연결 기준을 갖춘 UI 스켈레톤을 만든다.
- [계획] OS별 runner bootstrap 설치 지원
- 경로: `agent-roadmap/phase/control-plane-product-surface/milestones/cross-os-runner-bootstrap.md`
- 요약: OTO Core bootstrap command와 bootstrap asset이 Linux, macOS, Windows에서 OTO runner를 내려받고 설정/실행할 수 있도록 확장한다.
## Phase 경계
- 이 Phase는 기존 `services/core`, `apps/client`, `packages/flutter/oto_console`, `apps/runner` 경계를 유지하면서 제품 표면과 bootstrap 실행성을 보강한다.
- Jenkins 전체 기능, 장기 권한/감사 모델, durable artifact storage 운영 정책은 이 Phase의 기본 범위가 아니다.
- iop Edge 직접 연결 경로는 복원하지 않는다. OTO Core와 OTO runner의 독립 Control Plane 경로를 기준으로 한다.
- private release host, enrollment token, credential 원문은 tracked 문서에 남기지 않는다.

View file

@ -0,0 +1,68 @@
# Milestone: OS별 runner bootstrap 설치 지원
## 위치
- Roadmap: `agent-roadmap/ROADMAP.md`
- Phase: `agent-roadmap/phase/control-plane-product-surface/PHASE.md`
## 목표
OTO Core가 발급하는 bootstrap 흐름을 Linux 단일 shell script 기준에서 확장해 Linux, macOS, Windows 대상 runner 설치를 지원한다.
완료 후 대상 머신은 OTO가 미리 설치되어 있지 않아도 OS별 bootstrap command로 release asset을 내려받고, agent 설정을 만들고, `oto agent run` 실행 준비 또는 시작까지 진행할 수 있어야 한다.
## 상태
[계획]
## 승격 조건
- 없음
## 구현 잠금
- 상태: 해제
- 결정 필요: 없음
## 범위
- OTO Core bootstrap command/API와 embedded bootstrap asset 제공 경로를 OS별로 확장한다.
- Linux와 macOS는 POSIX shell 기반 설치 흐름을 우선 재사용하고, Windows는 PowerShell 기반 설치 흐름을 둔다.
- release asset 이름, OS/arch 감지, 설치 경로, config 경로, log/workspace 경로를 OS별 표준선으로 정리한다.
- bootstrap script와 server handler 테스트를 OS별 케이스로 확장한다.
## 기능
### Epic: [bootstrap-platforms] Cross-OS bootstrap contract
OS별 bootstrap command와 release asset 선택 기준을 OTO Core와 runner asset이 같은 의미로 해석하도록 만든다.
- [ ] [platform-matrix] Linux, macOS, Windows의 우선 지원 OS/arch와 release asset naming 규칙을 정리한다. 검증: 문서와 테스트 fixture가 동일한 asset 이름을 사용한다.
- [ ] [core-command] OTO Core bootstrap command 요청/응답이 대상 OS 또는 script 종류를 표현하고 올바른 bootstrap URL/command를 반환한다. 검증: `cd services/core && go test ./...`가 OS별 command 케이스를 포함해 통과한다.
- [ ] [unix-bootstrap] Linux/macOS shell bootstrap이 OS/arch를 감지해 올바른 release asset을 내려받고 config/runtime 경로를 생성한다. 검증: `cd apps/runner && dart test test/oto_agent_bootstrap_script_test.dart` 또는 대응 smoke가 통과한다.
- [ ] [windows-bootstrap] Windows PowerShell bootstrap이 release asset 다운로드, 압축 해제, config 생성, agent 실행 안내 또는 시작 흐름을 제공한다. 검증: script parsing/fixture 테스트가 Windows 경로와 quoting을 검증한다.
- [ ] [docs-smoke] README와 `agent-test/local/agent-smoke.md`가 OS별 bootstrap command, secret 기록 금지, release URL 검증 기준을 최신화한다.
## 완료 리뷰
- 상태: 없음
- 요청일: 없음
- 완료 근거: 없음
- 리뷰 필요:
- [ ] 사용자가 완료 결과를 확인했다
- [ ] archive 이동을 승인했다
- 리뷰 코멘트: 없음
## 범위 제외
- checksum/signature 검증, certificate pinning, enrollment token rotation은 기본 구현을 막지 않는 후속 보안 강화로 둔다.
- OS별 system service 설치를 완성형 daemon 관리까지 확대하지 않는다. 필요하면 user-level background 실행 또는 수동 실행 안내를 먼저 둔다.
- private release host, credential, token 원문을 tracked 문서에 기록하지 않는다.
## 작업 컨텍스트
- 관련 경로: `services/core/internal/httpserver/**`, `apps/runner/assets/script/**`, `apps/runner/test/**`, `README.md`, `agent-test/local/**`
- 표준선(선택): 우선 지원 OS는 Linux, macOS, Windows로 보고, 각 OS의 x64/arm64 지원 여부는 release asset 존재와 테스트 fixture로 명시한다.
- 표준선(선택): Linux/macOS는 shell, Windows는 PowerShell을 사용하며, 공통 설정 의미는 `agent.id`, `agent.alias`, `agent.enrollment_token`, `server.url`, `runtime.install_dir`, `runtime.workspace_root`, `runtime.log_dir`를 유지한다.
- 선행 작업: `독립 Control Plane 분리 마이그레이션`의 bootstrap command, `워크스페이스 포트/환경 표준화`의 release URL 기준, 폐기된 `Edge bootstrap 계약`의 Linux 설치 근거
- 후속 작업: release packaging 자동화, checksum/signature 검증, OS별 service manager 통합
- 확인 필요: 없음

View file

@ -0,0 +1,67 @@
# Milestone: Flutter 콘솔 스켈레톤
## 위치
- Roadmap: `agent-roadmap/ROADMAP.md`
- Phase: `agent-roadmap/phase/control-plane-product-surface/PHASE.md`
## 목표
현재 endpoint 표시와 placeholder 중심인 Flutter client를 Control Plane 작업 표면의 스켈레톤으로 확장한다.
완료 후 사용자는 OTO Core 연결 상태, runner, pipeline/job, execution, log/artifact, settings 영역의 기본 화면 구조와 빈 상태를 확인할 수 있고, 후속 API 연동을 넣을 위치가 명확해야 한다.
## 상태
[계획]
## 승격 조건
- 없음
## 구현 잠금
- 상태: 해제
- 결정 필요: 없음
## 범위
- `apps/client` host app과 `packages/flutter/oto_console` 패키지의 현재 shell/contract 경계를 유지한다.
- Overview, Runners, Pipelines/Jobs, Executions, Artifacts, Settings 화면의 스켈레톤과 상태 표현을 만든다.
- OTO Core HTTP URL 설정값을 기준으로 health/readiness 연결 상태를 표시할 수 있는 최소 adapter 또는 port를 둔다.
- 실제 API 데이터가 없거나 비어 있을 때의 empty/loading/error 상태를 제품 표면에 맞게 정리한다.
## 기능
### Epic: [ui-skeleton] Control Plane UI skeleton
OTO Console이 placeholder가 아니라 후속 기능을 얹을 수 있는 제품 화면 골격을 갖추도록 한다.
- [ ] [overview-status] Overview가 `OTO_SERVER_HTTP_URL` 기준 Core health/readiness 상태를 보여줄 수 있는 구조를 갖춘다. 검증: `make client-test` 또는 `cd apps/client && flutter test`에서 상태 표시 위젯 테스트가 통과한다.
- [ ] [section-surfaces] Runners, Pipelines/Jobs, Executions, Artifacts, Settings 섹션이 각각 독립 화면 스켈레톤과 빈 상태를 가진다. 검증: `cd packages/flutter/oto_console && flutter test`에서 navigation/section 렌더링 테스트가 통과한다.
- [ ] [api-port] Flutter UI가 Core API를 직접 호출할 구현 위치를 contract/adapter로 분리하고, 브라우저 CORS 또는 same-origin proxy 필요성을 작업 컨텍스트에 드러낸다.
- [ ] [preview-flow] 원격 preview 명령 `make client-run-web OTO_SERVER_HTTP_URL=http://toki-labs.com:18020` 기준으로 첫 화면이 Core API endpoint와 UI 스켈레톤을 안정적으로 렌더링한다. 검증: 원격 runner 또는 local smoke에서 Flutter web preview 접속 확인을 남긴다.
## 완료 리뷰
- 상태: 없음
- 요청일: 없음
- 완료 근거: 없음
- 리뷰 필요:
- [ ] 사용자가 완료 결과를 확인했다
- [ ] archive 이동을 승인했다
- 리뷰 코멘트: 없음
## 범위 제외
- runner/job/execution 전체 CRUD와 고급 운영 정책을 한 번에 완성하지 않는다.
- auth, 권한, 감사 로그, durable persistence UI를 완성하지 않는다.
- production 정적 웹 배포 파이프라인은 이 Milestone의 필수 산출물이 아니다.
## 작업 컨텍스트
- 관련 경로: `apps/client/**`, `packages/flutter/oto_console/**`, `services/core/internal/httpserver/**`, `agent-test/local/**`
- 표준선(선택): 현재 `OtoConsoleShell``OtoConsoleConfig`를 유지하고, 화면별 구현은 `oto_console` 패키지 안에 둔다.
- 표준선(선택): 현재 Core는 CORS 헤더를 제공하지 않으므로 브라우저 직접 API 호출을 붙일 때 CORS middleware 또는 same-origin proxy 정책을 함께 판단한다.
- 선행 작업: `oto_console 계약 경계 정리`, `워크스페이스 포트/환경 표준화`
- 후속 작업: 실제 runner/job/execution API 데이터 바인딩, 인증/권한, 운영 대시보드 고도화
- 확인 필요: 없음