test(workbench): 워크벤치 검증과 로드맵 상태를 동기화한다

현재 마일스톤의 project-config 진행 상태와 workbench-shell 검증 근거를 로드맵에 반영한다.
This commit is contained in:
toki 2026-06-07 04:18:22 +09:00
parent 0d6916fd48
commit a5449ab91c
4 changed files with 64 additions and 14 deletions

View file

@ -14,7 +14,7 @@
완료, 검토중, 진행중, 계획, 스케치 순서로 두어 아래로 갈수록 미래 작업에 가까워지게 정렬한다. 완료, 검토중, 진행중, 계획, 스케치 순서로 두어 아래로 갈수록 미래 작업에 가까워지게 정렬한다.
스케치 Milestone은 아직 구현 가능한 계획이 아니므로 계획 Milestone보다 아래에 둔다. 스케치 Milestone은 아직 구현 가능한 계획이 아니므로 계획 Milestone보다 아래에 둔다.
- [계획] Milestone Work Item Creation Sync - [진행중] Milestone Work Item Creation Sync
- 경로: `agent-roadmap/phase/agent-ops-mcp-control-plane/milestones/milestone-work-item-creation-sync.md` - 경로: `agent-roadmap/phase/agent-ops-mcp-control-plane/milestones/milestone-work-item-creation-sync.md`
- 요약: Plane-origin 방식으로 Milestone을 생성하고 Plane Todo 티켓까지 동기화한 뒤 멈추는 계획 후보다. Workspace agent 실행은 IOP CLI 1차 통로를 선행으로 두며, Agent chat/IDE-origin 생성 projection은 이번 범위에서 제외한다. - 요약: Plane-origin 방식으로 Milestone을 생성하고 Plane Todo 티켓까지 동기화한 뒤 멈추는 계획 후보다. Workspace agent 실행은 IOP CLI 1차 통로를 선행으로 두며, Agent chat/IDE-origin 생성 projection은 이번 범위에서 제외한다.

View file

@ -11,7 +11,7 @@ Plane-origin 경로로 Milestone을 생성하고, `develop` branch의 agent-road
## 상태 ## 상태
[계획] [진행중]
## 구현 잠금 ## 구현 잠금
@ -47,14 +47,14 @@ Plane-origin 경로로 Milestone을 생성하고, `develop` branch의 agent-road
Plane project 단위로 Milestone sync에 필요한 기본 설정을 저장하고 이후 UI/UX가 소비할 project settings 경계를 만든다. Plane project 단위로 Milestone sync에 필요한 기본 설정을 저장하고 이후 UI/UX가 소비할 project settings 경계를 만든다.
- [ ] [project-model] Plane project 단위 sync 설정 모델을 정의한다. 검증: 설정 모델이 provider project target, git remote URL, source-of-truth branch, workspace id/path를 필수 필드로 갖는다. - [x] [project-model] Plane project 단위 sync 설정 모델을 정의한다. 검증: 설정 모델이 provider project target, git remote URL, source-of-truth branch, workspace id/path를 필수 필드로 갖는다.
- [ ] [project-store] Project sync 설정을 Core DB에 저장하는 persistence 경계를 정한다. 검증: Plane project별로 하나의 active sync 설정을 찾을 수 있고, Milestone 생성 동기화가 이 설정 없이는 진행되지 않는 기준이 문서화되어 있다. - [x] [project-store] Project sync 설정을 Core DB에 저장하는 persistence 경계를 정한다. 검증: Plane project별로 하나의 active sync 설정을 찾을 수 있고, Milestone 생성 동기화가 이 설정 없이는 진행되지 않는 기준이 문서화되어 있다.
- [ ] [project-bind] Plane-origin 생성 동기화가 project sync 설정을 통해 Plane project, git repository, 작업 workspace를 해석하도록 한다. 검증: 같은 Plane project 안의 티켓은 같은 git/workspace 설정을 사용하며, 다른 Plane project와 섞이지 않는다. - [x] [project-bind] Plane-origin 생성 동기화가 project sync 설정을 통해 Plane project, git repository, 작업 workspace를 해석하도록 한다. 검증: 같은 Plane project 안의 티켓은 같은 git/workspace 설정을 사용하며, 다른 Plane project와 섞이지 않는다.
- [ ] [workspace-layout] NomadCode host 기준 workspace 경로 규칙을 정의한다. 검증: `workspace_base_path=/home/user/workspace`, `repo_dir_name=nomadcode`이면 project workspace root는 `/home/user/workspace/nomadcode`이고 실제 작업 slot path는 `/home/user/workspace/nomadcode/000`처럼 계산된다. - [x] [workspace-layout] NomadCode host 기준 workspace 경로 규칙을 정의한다. 검증: `workspace_base_path=/home/user/workspace`, `repo_dir_name=nomadcode`이면 project workspace root는 `/home/user/workspace/nomadcode`이고 실제 작업 slot path는 `/home/user/workspace/nomadcode/000`처럼 계산된다.
- [ ] [workspace-slot] 병렬 운용을 위한 workspace slot index 모델을 정의한다. 검증: 기본 작업공간은 `000`이고, 병렬 요청이 들어오면 `001`, `002`처럼 3자리 zero-padded index를 증가시키며 각 slot이 독립 작업공간으로 예약된다. - [x] [workspace-slot] 병렬 운용을 위한 workspace slot index 모델을 정의한다. 검증: 기본 작업공간은 `000`이고, 병렬 요청이 들어오면 `001`, `002`처럼 3자리 zero-padded index를 증가시키며 각 slot이 독립 작업공간으로 예약된다.
- [ ] [workspace-slot-state] Workspace slot의 사용중 상태 모델을 정의한다. 검증: 각 slot은 `available`, `in_use`, `dirty`, `error` 같은 상태 후보를 갖고, 새 작업은 `available` slot만 선택하며, 동시에 들어온 요청이 같은 slot을 잡지 않도록 DB에서 원자적으로 `in_use`로 전환하는 기준이 있다. - [x] [workspace-slot-state] Workspace slot의 사용중 상태 모델을 정의한다. 검증: 각 slot은 `available`, `in_use`, `dirty`, `error` 같은 상태 후보를 갖고, 새 작업은 `available` slot만 선택하며, 동시에 들어온 요청이 같은 slot을 잡지 않도록 DB에서 원자적으로 `in_use`로 전환하는 기준이 있다.
- [ ] [workspace-checkout] Git repository checkout 정책을 project sync 설정과 연결한다. 검증: git remote는 project sync 설정에서 읽고, 안정성을 우선해 각 slot은 같은 remote의 독립 checkout을 기본으로 확보하며, 일반 단일 운용에서는 `000`만 사용한다. - [x] [workspace-checkout] Git repository checkout 정책을 project sync 설정과 연결한다. 검증: git remote는 project sync 설정에서 읽고, 안정성을 우선해 각 slot은 같은 remote의 독립 checkout을 기본으로 확보하며, 일반 단일 운용에서는 `000`만 사용한다.
- [ ] [settings-ui] Project sync 설정을 이후 프로젝트 설정 UI/UX에서 관리해야 하는 후보로 남긴다. 검증: 이번 마일스톤에서는 UI 구현을 하지 않고, 후속 Project settings 화면이 provider project target, git remote, workspace를 표시/수정해야 한다는 요구가 남아 있다. - [x] [settings-ui] Project sync 설정을 이후 프로젝트 설정 UI/UX에서 관리해야 하는 후보로 남긴다. 검증: 이번 마일스톤에서는 UI 구현을 하지 않고, 후속 Project settings 화면이 provider project target, git remote, workspace를 표시/수정해야 한다는 요구가 남아 있다.
### Epic: [agent-bridge] Workspace agent IOP CLI bridge ### Epic: [agent-bridge] Workspace agent IOP CLI bridge
@ -120,6 +120,7 @@ Plane-origin 생성 경로를 `develop` agent-roadmap 기준의 `Todo` 검토
- Slot 사용 상태: slot은 Core DB에서 `available` 또는 `in_use` 같은 사용 상태를 추적한다. 여기서 사용 상태는 해당 slot이 현재 작업에 배정되어 다른 병렬 작업이 잡으면 안 되는지를 나타낸다. - Slot 사용 상태: slot은 Core DB에서 `available` 또는 `in_use` 같은 사용 상태를 추적한다. 여기서 사용 상태는 해당 slot이 현재 작업에 배정되어 다른 병렬 작업이 잡으면 안 되는지를 나타낸다.
- Checkout 기준: 안정성을 우선해 각 slot은 같은 git remote를 기준으로 독립 checkout을 갖는 작업공간으로 둔다. 초기 slot 생성 때 clone 비용이 들지만 이후 branch 이동과 일반 작업은 해당 slot 안에서 처리하므로 운영 비용을 낮춘다. - Checkout 기준: 안정성을 우선해 각 slot은 같은 git remote를 기준으로 독립 checkout을 갖는 작업공간으로 둔다. 초기 slot 생성 때 clone 비용이 들지만 이후 branch 이동과 일반 작업은 해당 slot 안에서 처리하므로 운영 비용을 낮춘다.
- 후속 UI/UX: project settings 화면에서 Plane project target, git remote, workspace 설정을 확인하고 수정하는 UX가 필요하다. - 후속 UI/UX: project settings 화면에서 Plane project target, git remote, workspace 설정을 확인하고 수정하는 UX가 필요하다.
- 완료 근거(2026-06-07): `[project-config]``services/core/internal/projectsync/`, `services/core/migrations/00004_create_project_sync_settings.sql`, `services/core/migrations/00005_create_workspace_slots.sql`, `services/core/queries/project_sync_settings.sql`, `services/core/queries/workspace_slots.sql`, `packages/contracts/notes/flutter-core-api-candidates.md`의 모델/저장/slot/UI 후보 경계와 테스트로 확인했다. 검증: `cd services/core && go test ./...` PASS.
- 중지 지점: Plane-origin 생성이 Plane `Todo` 상위 티켓과 `develop` agent-roadmap Milestone identity로 연결된 상태다. - 중지 지점: Plane-origin 생성이 Plane `Todo` 상위 티켓과 `develop` agent-roadmap Milestone identity로 연결된 상태다.
- 루프 확인: Plane `Backlog + AGENT assignee` -> IOP CLI로 workspace agent authoring run 실행 -> agent가 Milestone 파일 작성/갱신 후 `develop` push -> sync layer가 push 완료 또는 roadmap scan을 감지 -> Plane 원문 댓글 보존/본문 치환/제목 변경/`Todo` 이동 -> 사용자가 확인 후 `In Progress`로 이동하는 지점까지다. `In Progress` 이후 실행은 후속 잠금 범위다. - 루프 확인: Plane `Backlog + AGENT assignee` -> IOP CLI로 workspace agent authoring run 실행 -> agent가 Milestone 파일 작성/갱신 후 `develop` push -> sync layer가 push 완료 또는 roadmap scan을 감지 -> Plane 원문 댓글 보존/본문 치환/제목 변경/`Todo` 이동 -> 사용자가 확인 후 `In Progress`로 이동하는 지점까지다. `In Progress` 이후 실행은 후속 잠금 범위다.
- 후속 잠금: `Todo -> In Progress` 이후 실행 lifecycle은 사용자가 명시적으로 잠금을 해제할 때까지 진행하지 않는다. - 후속 잠금: `Todo -> In Progress` 이후 실행 lifecycle은 사용자가 명시적으로 잠금을 해제할 때까지 진행하지 않는다.

View file

@ -33,10 +33,10 @@ NomadCode Flutter 앱의 상단 titlebar와 우측 icon rail 기반 workbench sh
NomadCode는 여러 도메인 관리 화면을 우측 icon rail과 중앙 content host로 전환하는 제품 shell을 소유한다. NomadCode는 여러 도메인 관리 화면을 우측 icon rail과 중앙 content host로 전환하는 제품 shell을 소유한다.
- [ ] [titlebar] NomadCode shell은 상단 titlebar 영역을 제공하고, 앱/워크스페이스/현재 컨텍스트 상태를 이 영역에서 표현한다. - [x] [titlebar] NomadCode shell은 상단 titlebar 영역을 제공하고, 앱/워크스페이스/현재 컨텍스트 상태를 이 영역에서 표현한다.
- [ ] [right-rail] NomadCode shell은 VS Code activity bar처럼 아이콘만 있는 우측 rail을 제공한다. - [x] [right-rail] NomadCode shell은 VS Code activity bar처럼 아이콘만 있는 우측 rail을 제공한다.
- [ ] [center-content] 우측 rail item 선택에 따라 중앙 content가 Agent, Workflow, Web Context, Settings, provider slot 등으로 전환된다. - [x] [center-content] 우측 rail item 선택에 따라 중앙 content가 Agent, Workflow, Web Context, Settings, provider slot 등으로 전환된다.
- [ ] [layout-shape] 상단 titlebar와 우측 rail이 ㄱ자 구조를 만들고, 중앙 content는 host 도메인 화면을 침범 없이 표시한다. 검증: narrow/wide layout에서 titlebar, rail, center content가 겹치지 않는다. - [x] [layout-shape] 상단 titlebar와 우측 rail이 ㄱ자 구조를 만들고, 중앙 content는 host 도메인 화면을 침범 없이 표시한다. 검증: narrow/wide layout에서 titlebar, rail, center content가 겹치지 않는다.
### Epic: [provider-slots] Provider slot registry ### Epic: [provider-slots] Provider slot registry
@ -89,6 +89,7 @@ IOP와 OTO 관리는 webview나 별도 앱이 아니라 각 repository의 embedd
- 표준선(선택): NomadCode shell은 상단 titlebar + 우측 icon rail + center content 구조를 소유한다. - 표준선(선택): NomadCode shell은 상단 titlebar + 우측 icon rail + center content 구조를 소유한다.
- 표준선(선택): 외부 제품 UI는 provider adapter/composition layer에서만 import하고, default build는 외부 제품 package 없이 빌드 가능해야 한다. - 표준선(선택): 외부 제품 UI는 provider adapter/composition layer에서만 import하고, default build는 외부 제품 package 없이 빌드 가능해야 한다.
- 표준선(선택): Agent shell은 공통 package, NomadCode/IOP/OTO는 각각 capability pack으로 조립한다. - 표준선(선택): Agent shell은 공통 package, NomadCode/IOP/OTO는 각각 capability pack으로 조립한다.
- 완료 근거(2026-06-07): `[workbench-shell]``apps/client/lib/src/app/nomadcode_workbench_shell.dart``apps/client/test/widget_test.dart`의 right rail, Agent dock, IOP/Workflow section 전환, narrow/wide layout rect 검증으로 확인했다. 검증: `cd apps/client && flutter test` PASS.
- 선행 작업: Client Integration Standardization, Project Workspace Management UX - 선행 작업: Client Integration Standardization, Project Workspace Management UX
- 선행 확인 대상: `../iop/packages/flutter/iop_console/`, `../oto/packages/flutter/oto_console/` - 선행 확인 대상: `../iop/packages/flutter/iop_console/`, `../oto/packages/flutter/oto_console/`
- 후속 작업: 실제 desktop/mobile project workspace 화면 구현, workflow/provider 관리 탭별 세부 content 구현 - 후속 작업: 실제 desktop/mobile project workspace 화면 구현, workflow/provider 관리 탭별 세부 content 구현

View file

@ -133,6 +133,54 @@ void main() {
expect(find.textContaining('Optional IOP console package'), findsOneWidget); expect(find.textContaining('Optional IOP console package'), findsOneWidget);
}); });
testWidgets('Workbench separates titlebar, right rail, and content', (
WidgetTester tester,
) async {
addTearDown(() {
tester.view.resetPhysicalSize();
tester.view.resetDevicePixelRatio();
});
for (final size in const [Size(390, 800), Size(1280, 900)]) {
tester.view.physicalSize = size;
tester.view.devicePixelRatio = 1;
await tester.pumpWidget(const NomadCodeClientApp());
await tester.pump();
final titleRect = tester.getRect(find.text('NomadCode Console'));
final workflowRailRect = tester.getRect(find.byTooltip('Workflow'));
expect(titleRect.bottom, lessThanOrEqualTo(workflowRailRect.top));
await tester.tap(find.byTooltip('Workflow'));
await tester.pump();
final workflowContentRect = tester.getRect(
find.text('Workflow management surface will mount here.'),
);
expect(workflowContentRect.top, greaterThan(titleRect.bottom));
expect(
workflowContentRect.right,
lessThanOrEqualTo(workflowRailRect.left),
);
await tester.tap(find.byTooltip('Agent'));
await tester.pump();
final agentRailRect = tester.getRect(find.byTooltip('Agent'));
final agentContentRect = tester.getRect(
find.text('Ask the workspace agent'),
);
expect(agentContentRect.top, greaterThan(titleRect.bottom));
expect(agentContentRect.right, lessThanOrEqualTo(agentRailRect.left));
await tester.pumpWidget(const SizedBox.shrink());
await tester.pump();
}
});
testWidgets('WorkspaceHomePage triggers launcher callback on button tap', ( testWidgets('WorkspaceHomePage triggers launcher callback on button tap', (
WidgetTester tester, WidgetTester tester,
) async { ) async {