<!-- task=m-external-integration/02_jira_adapter plan=0 tag=JIRA -->

# Jira Adapter Plan

## 이 파일을 읽는 구현 에이전트에게

`CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채우는 것이 구현의 마지막 단계다. 구현 후 검증 명령을 실행하고 실제 stdout/stderr를 붙여 넣은 뒤 active 파일을 그대로 둔 채 리뷰 준비를 보고한다. 사용자 결정, 사용자 소유 외부 환경, scope 충돌 없이는 안전하게 진행할 수 없는 경우에는 review stub의 `사용자 리뷰 요청` 섹션에 근거를 남기고 멈춘다.

## 배경

External Integration 마일스톤은 Plane/Jira style work item provider를 adapter 경계에 격리해야 한다. 현재 `workitem` 계약은 Plane이 구현하고 있지만 Jira adapter package가 없다. 이 작업은 Jira lookup/comment/status transition의 최소 HTTP adapter와 deterministic tests를 추가한다.

## 사용자 리뷰 요청 흐름

구현 중 user-only blocker는 active `CODE_REVIEW-local-G07.md`의 `사용자 리뷰 요청`에 기록한다. code-review가 실제 `USER_REVIEW.md`, archive, `complete.log`를 소유한다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/external-integration/milestones/external-integration.md`
- Task ids:
  - `jira-adapter`: Jira issue 조회, comment, status transition adapter 구현
- Completion mode: check-on-pass

## 분석 결과

### 읽은 파일

- `agent-roadmap/current.md`
- `agent-roadmap/phase/external-integration/PHASE.md`
- `agent-roadmap/phase/external-integration/milestones/external-integration.md`
- `agent-test/local/rules.md`
- `agent-test/local/core-smoke.md`
- `agent-ops/rules/project/domain/core/rules.md`
- `services/core/internal/workitem/provider.go`
- `services/core/internal/workitem/provider_test.go`
- `services/core/internal/adapters/plane/client.go`
- `services/core/internal/adapters/plane/client_test.go`
- `services/core/internal/http/handlers.go`
- `services/core/internal/http/handlers_test.go`
- `services/core/internal/http/router.go`
- `services/core/internal/config/config.go`
- `services/core/internal/config/config_test.go`
- `services/core/cmd/server/main.go`
- `services/core/go.mod`
- `services/core/README.md`
- `README.md`

### 테스트 환경 규칙

- test_env: `local`
- `agent-test/local/rules.md` 있음, 읽음.
- matched profile: `agent-test/local/core-smoke.md` 읽음.
- 적용 명령: `cd services/core && go test ./...`, `cd services/core && go vet ./...`.
- Jira live credential/profile은 없다. 이번 plan은 httptest 기반 adapter verification으로 닫고 live Jira smoke는 범위 밖이다.

### 테스트 커버리지 공백

- Jira package가 없어 모든 Jira behavior test가 신규 필요.
- config/server wiring도 없으므로 `JIRA_BASE_URL`, `JIRA_EMAIL`, `JIRA_API_TOKEN` 또는 token 형태를 추가한다면 config tests가 필요.
- HTTP endpoint는 이번 adapter task의 필수 범위가 아니다. provider-neutral handler 확장은 adapter-boundary 또는 별도 follow-up에서 다룬다.

### 심볼 참조

- renamed/removed symbols: none.
- new symbols expected: `internal/adapters/jira.Client`, `jira.Config`, `jira.IssueRef`, `FetchWorkItem`, `AppendComment`, `ProjectStatus`.

### 분할 판단

- split decision policy evaluated.
- `02_jira_adapter` is independent from Plane and Mattermost because it lives under a new provider package and can be tested with httptest.
- It has no predecessor dependency. Do not wait for `01_plane_adapter`.
- `04+01,02,03_adapter_boundary` will audit provider boundaries after this subtask PASS.

### 범위 결정 근거

- Exclude Jira webhook intake, Jira issue property/custom field persistence, OAuth, JQL search, project metadata discovery, and live Jira smoke.
- Keep Jira REST DTOs under `services/core/internal/adapters/jira/`.
- Do not add a DB schema or cross-domain contract unless compile requires it.

### 빌드 등급

- build lane/grade: `local-G07` - new provider adapter and config with deterministic tests.
- review lane/grade: `local-G07` - bounded Go code, but new API surface needs careful review.

## 구현 체크리스트

- [ ] [JIRA-1] Jira adapter package를 provider-neutral workitem facets에 맞춰 추가한다.
- [ ] [JIRA-2] Jira config/server docs wiring을 최소 범위로 정리한다.
- [ ] `cd services/core && go test ./...`를 실행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

## [JIRA-1] Jira adapter package

문제: 마일스톤은 Jira issue 조회/comment/status transition을 요구하지만 `services/core/internal/adapters/`에는 `jira` package가 없다. `services/core/internal/workitem/provider.go:36`-`46`의 `Reader`, `Commenter`, `StatusProjector`를 구현할 provider가 필요하다.

해결 방법:

- `services/core/internal/adapters/jira/client.go` 생성.
- `Config`는 `BaseURL`, `Email`, `APIToken`, optional `Token` 중 기존 Jira Cloud basic auth에 맞는 최소값을 둔다. 우선 `Email + APIToken` basic auth를 기본으로 하고, bearer token이 필요하면 명시적으로 분기한다.
- `FetchWorkItem`: `GET /rest/api/3/issue/{key}`를 호출하고 summary, description fallback, status를 `workitem.WorkItem`으로 변환한다.
- `AppendComment`: `POST /rest/api/3/issue/{key}/comment`를 호출한다. Markdown/text는 Jira ADF body로 감싸거나 plain text paragraph로 변환한다.
- `ProjectStatus`: `POST /rest/api/3/issue/{key}/transitions` with `{"transition":{"id": provider_state}}`.
- Jira-specific DTOs and ADF helpers stay in the Jira package.

수정 파일 및 체크리스트:

- [ ] `services/core/internal/adapters/jira/client.go`: client, config validation, request helper, DTO mapping.
- [ ] `services/core/internal/adapters/jira/client_test.go`: lookup/comment/transition/error tests.
- [ ] `services/core/go.mod`: no new dependency unless justified; prefer standard library.

테스트 작성:

- `TestFetchWorkItemCallsIssueEndpointAndMapsFields`
- `TestAppendCommentPostsADFBody`
- `TestProjectStatusPostsTransition`
- `TestClientReturnsResponseBodyOnError`
- `TestClientImplementsWorkItemFacets`

중간 검증:

```bash
cd services/core && go test ./internal/adapters/jira ./internal/workitem
```

기대: Jira adapter and workitem tests pass.

## [JIRA-2] Jira config/server docs wiring

문제: `services/core/internal/config/config.go:25`-`28` only contains Mattermost/Plane provider config. README mentions Jira style work item intake but no config route.

해결 방법:

- Add Jira env config only if server wiring will instantiate the adapter. If no route uses Jira yet, keep config docs minimal and avoid dead wiring.
- If wiring is added, `cmd/server/main.go` should create Jira client separately from Plane and pass only provider-neutral readers where needed. Do not make `NewHandler` accept provider-specific DTOs.
- Update README environment table with Jira config only after code actually reads it.

수정 파일 및 체크리스트:

- [ ] `services/core/internal/config/config.go`: add Jira config fields only when used.
- [ ] `services/core/internal/config/config_test.go`: defaults/env loading.
- [ ] `services/core/cmd/server/main.go`: instantiate Jira adapter only if an integration endpoint or provider registry needs it.
- [ ] `services/core/README.md` and root `README.md`: document only implemented config/behavior.

테스트 작성:

- Config tests required if env fields are added.
- Handler/router tests required if any Jira HTTP endpoint is added. Otherwise skip endpoint tests and justify in review.

중간 검증:

```bash
cd services/core && go test ./internal/config ./cmd/server ./internal/adapters/jira
```

기대: packages compile and tests pass.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `services/core/internal/adapters/jira/client.go` | JIRA-1 |
| `services/core/internal/adapters/jira/client_test.go` | JIRA-1 |
| `services/core/internal/config/config.go` | JIRA-2 |
| `services/core/internal/config/config_test.go` | JIRA-2 |
| `services/core/cmd/server/main.go` | JIRA-2 |
| `services/core/README.md` | JIRA-2 |
| `README.md` | JIRA-2 |

## 최종 검증

```bash
cd services/core && go test ./...
cd services/core && go vet ./...
```

기대: both commands exit 0. Go test cache output is acceptable for this adapter work.

모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.
