nomadcode/agent-ops/roadmap/milestones/plane-task-pipeline-design.md

126 lines
10 KiB
Markdown

# Work Item Provider Pipeline Design
## 목표
Plane Communication Foundation 다음 단계로 Plane/Jira 등 work item provider와 core task pipeline 사이의 최소 제품 흐름을 확정한다. 자동 실행 구현에 들어가기 전에 provider-neutral 생성, enqueue, 상태 투영, 중복 방지, 결과 발행 경계를 정리해 Workflow Core가 참조할 상태 변화와 실패 케이스를 명확히 한다.
## 단계
Work Item Provider Pipeline Design
## 상태
계획
## 범위
- Plane/Jira 같은 work item provider에서 core task를 생성하고 연결하는 entrypoint 후보 정리
- 수동 endpoint, webhook, polling 등 trigger 방식의 다음 구현 경로 결정
- core task enqueue 조건과 중복 생성 방지 기준 정리
- provider별 직접 접속부와 core 내부 pipeline 계약을 분리하는 adapter interface 정리
- provider board state와 agent 내부 실행 상태의 분리 계약 정리
- Plane/Jira에서 공통으로 읽히는 label/comment 기반 상태 투영 방식 정리
- task 완료/실패 결과를 provider comment/status로 발행하는 최소 정책 정리
- provider별 workspace/project/work item/state metadata 사용 방식 확정
- Workflow Core에 넘길 상태 변화, 실패 케이스, notification 요구사항 정리
## 필수 기능
- [x] Plane work item -> core task 생성/연결 흐름을 현재 구현 기준으로 문서화한다.
- [x] 초기 entrypoint는 기존 `POST /api/integrations/plane/tasks`를 기준선으로 삼는다.
- [x] 생성 단계는 Plane work item 조회와 core task 저장까지만 담당한다.
- [x] 생성된 task는 `pending` 상태로 남기고 enqueue는 별도 단계에서 처리한다.
- [x] Plane 연결 정보는 provider-neutral external ref와 Plane metadata에 함께 저장한다.
- [ ] 자동 enqueue 여부와 사용자/운영 트리거 경계를 결정한다.
- [ ] work item provider adapter interface를 설계한다.
- [ ] core pipeline이 사용할 provider-neutral DTO를 정의한다.
- [ ] work item 조회, comment 작성, status/state 변경, label projection 경계를 interface로 분리한다.
- [ ] Plane adapter와 Jira adapter가 같은 interface를 구현할 수 있는지 검증한다.
- [ ] provider별 상태/라벨/comment 매핑은 adapter 설정으로 분리한다.
- [ ] 현재 Plane 고정 진입부를 provider-neutral 구조로 리팩토링한다.
- [ ] `POST /api/integrations/plane/tasks`의 Plane 전용 흐름을 generic pipeline service 아래로 옮긴다.
- [ ] HTTP handler가 Plane 타입과 직접 결합하지 않도록 요청 DTO와 변환 책임을 분리한다.
- [ ] `buildPlaneCreateTaskInput`의 core task 생성 로직을 provider-neutral mapper로 분리한다.
- [ ] 기존 Plane endpoint는 compatibility entrypoint로 유지하거나 generic endpoint로 대체할지 결정한다.
- [ ] provider-neutral 상태와 projection 계약을 확정한다.
- [x] board state는 `backlog`, `todo`, `in_progress`, `testing`, `complete`, `cancel`로 둔다.
- [x] `in_progress` 내부 agent 상태는 core task metadata를 canonical source로 둔다.
- [x] Plane/Jira provider projection은 label-first로 둔다.
- [x] provider 본문(description)은 agent 실행 상태 저장소로 쓰지 않는다.
- [ ] core task metadata schema와 provider label mapping을 구현 대상으로 확정한다.
- [ ] 완료/실패 결과의 provider comment/status update 정책을 정한다.
- [x] agent 단계 완료 기록은 prefix와 이모지가 있는 comment로 남기는 방향을 샘플 검증한다.
- [ ] comment prefix 세트와 작성 타이밍을 확정한다.
- [ ] 중복 생성 방지와 재시도 시 식별 기준을 정한다.
- [ ] Workflow Core에서 처리할 lifecycle, retry, timeout, notification 요구사항을 정리한다.
## 완료 기준
- [ ] Plane/Jira work item에서 core task로 이어지는 provider-neutral pipeline entrypoint와 계약이 문서화되어 있다.
- [ ] core workflow/pipeline 계층이 Plane package 타입에 직접 의존하지 않는다.
- [ ] Plane 직접 접속부는 adapter 구현에 격리되고, Jira adapter 추가 지점이 명확하다.
- [ ] enqueue 조건, idempotency 기준, 실패 표시 방식이 결정되어 있다.
- [ ] provider board state, core canonical state, label/comment projection 계약이 문서화되어 있다.
- [ ] completed/failed/cancelled 결과를 provider에 반영하는 최소 정책이 결정되어 있다.
- [ ] Workflow Core가 pipeline 계약 질문 없이 상태 전이 구현을 시작할 수 있다.
## 범위 제외
- Plane webhook 구현
- Jira adapter 실제 구현
- Plane 전체 양방향 동기화
- Plane custom property 또는 work item type Pro 기능 의존
- task lifecycle, retry, timeout의 실제 구현
- 외부 협업 도구로 notification 발송
- Mattermost 메시지 발송 구현
- 복잡한 workflow DSL
- Plane token 생성/보관/교체 운영 절차
## 작업 컨텍스트
- 관련 경로: `services/core/internal/adapters/plane/`, `services/core/internal/http/`, `services/core/internal/storage/`, `services/core/internal/scheduler/`, `services/core/internal/workflow/`, `services/core/README.md`
- 파일명 메모: 기존 Plane 중심 파일명 `plane-task-pipeline-design.md`는 대규모 rename을 피하기 위해 유지하되, 마일스톤 이름과 내용은 Work Item Provider Pipeline Design으로 일반화한다.
- 선행 작업: Plane Communication Foundation
- 후속 작업: Workflow Core
- 현재 코드 결합 상태:
- HTTP router는 `POST /api/integrations/plane/tasks`로 Plane 전용 entrypoint를 가진다.
- handler는 `PlaneWorkItemClient`, `plane.WorkItemRef`, `plane.WorkItem`에 직접 의존한다.
- `buildPlaneCreateTaskInput`이 Plane 조회 결과를 core task payload/external ref로 직접 변환한다.
- DB schema는 `external_provider`, `external_id`, `external_url`, `external_metadata`로 provider-neutral 토대가 있으므로 유지한다.
- 리팩토링 목표는 Plane/Jira 직접 접속부를 adapter로 격리하고, 그 아래 pipeline/service 계층은 provider-neutral DTO와 interface만 보게 하는 것이다.
- 초기 생성/연결 흐름:
- 운영자 또는 상위 자동화가 `POST /api/integrations/plane/tasks`를 호출한다.
- 요청 필수값은 `workspace_slug`, `project_id`, `work_item_id`이고, `state_id`, `external_url`, `comment`는 선택값으로 받는다.
- core는 Plane adapter로 work item detail을 조회해 title과 description 후보를 얻는다.
- task title은 Plane work item name을 우선하고, 비어 있으면 `work_item_id`를 사용한다.
- task payload의 `message`는 요청 `comment`, Plane stripped description, plain description, HTML description, title 순서로 선택한다.
- task source는 `plane`, external provider는 `plane`, external id는 `work_item_id`로 저장한다.
- `workspace_slug`, `project_id`, `work_item_id`, `state_id`, `external_url``payload.plane``external_metadata`에 저장한다.
- 생성 직후 task 상태는 `pending`이며, 이 entrypoint는 enqueue, Plane 상태 변경, 결과 comment 발행을 수행하지 않는다.
- 상태 설계 결정:
- provider board state는 `backlog`, `todo`, `in_progress`, `testing`, `complete`, `cancel`의 소유권/검증 단계로 유지한다.
- `in_progress`를 planning, implementing, review 같은 board state로 쪼개지 않고, agent 내부 실행 상태는 core task metadata에 canonical 값으로 저장한다.
- agent 내부 실행 상태 후보는 `agent_run_state`, `agent_phase`, `wait_type`, `status_reason`, `last_heartbeat_at`, `plan_ref`, `attempt`다.
- agent가 작업 중 사용자 판단을 기다릴 때는 board state를 `in_progress`로 유지하고 `agent_run_state=waiting_for_user``wait_type`으로 멈춤 이유를 표현한다.
- `testing`은 agent가 plan, 구현, 자체 테스트, 자체 리뷰 루프를 끝낸 뒤 사용자가 직접 테스트하는 단계다.
- provider projection은 라벨을 우선 사용한다. 예: `agent:waiting-user`, `phase:planning`, `agent:blocked`, `agent:failed`.
- provider 본문(description)은 작업 요구사항과 맥락의 원본으로 보고, agent 실행 상태를 매번 갱신하는 저장소로 쓰지 않는다.
- Plane custom property는 현재 NomadCode dev project에서 `is_issue_type_enabled=False`라 기본 경로로 전제하지 않는다.
- Plane 샘플 work item `NOMAD-13``In Progress` state와 `agent:waiting-user`, `phase:planning` 라벨로 board state와 agent 내부 실행 상태 분리 방식을 보여준다.
- provider abstraction 결정:
- Plane은 첫 구현 provider일 뿐이며 core pipeline의 도메인 모델이 되어서는 안 된다.
- Jira도 같은 workflow state, label/comment projection, idempotency 계약을 공유할 수 있어야 한다.
- provider별 API 인증, URL, workspace/project/issue 식별자, status id, label id는 adapter 설정과 metadata로만 다룬다.
- core의 canonical 상태와 agent 실행 metadata는 provider에서 읽어온 값이 아니라 NomadCode task 상태의 진실로 둔다.
- comment 기록 규칙 후보:
- `🧭 PLAN | <요약>`: plan 작성 또는 계획 검토 단계 완료 기록
- `🛠️ WORK | <요약>`: 구현 또는 문서 반영 단계 완료 기록
- `🔎 REVIEW | <요약>`: 코드리뷰/self-review 단계 완료 기록
- `✅ VERIFY | <요약>`: 테스트/검증 완료 기록
- 각 comment 본문은 1~2줄 요약을 기본으로 하며, 자세한 실행 로그나 상태 metadata는 core에 남긴다.
- 현재 지점 / 착수 상태:
- 현재 상태는 `계획`이며, 구현 착수 전 설계 정리 지점이다.
- 정리된 내용은 provider-neutral 방향성, Plane/Jira adapter 추상화 필요성, label/comment 기반 상태 투영 샘플이다.
- 아직 확정되지 않은 다음 결정은 provider adapter interface, trigger 경계, core metadata schema, provider label mapping이다.
- 다음에 이 마일스톤을 착수하면 Plane 고정 진입부 리팩토링 전에 위 결정 항목을 먼저 닫는다.
- 확인 필요: trigger 방식은 현재 구현 상태와 운영 기대치를 보고 수동 endpoint 유지, webhook, polling 중 하나를 선택한다.