<!-- task=m-provider-adapter-foundation/01_provider_store_boundary plan=0 tag=API -->

# Plan - API

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

이 계획의 구현이 끝나도 task는 완료가 아니다. 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 실제 구현 내용, 검증 명령, stdout/stderr로 채우고 active 파일을 그대로 둔 뒤 리뷰 준비를 보고한다. 최종 판정, log rename, `complete.log`, archive 이동은 code-review 전용이다. 선택된 SDD 결정 또는 선택된 Milestone `구현 잠금 > 결정 필요` 항목 때문에 막히면 review stub의 `사용자 리뷰 요청` 섹션에 연결 대상과 근거를 채우고 멈춘다. 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 환경/secret/service 차단, 일반 범위 변경, 검증 증거 공백은 사용자 리뷰 요청이 아니라 검증 결과나 후속 계획으로 기록한다.

## 배경

registry 에픽의 `provider-store`는 provider config를 저장/조회하는 boundary를 요구한다. 먼저 storage API와 in-memory Boundary wiring을 추가해야 PgStore 구현이 같은 계약에 맞춰 들어갈 수 있다. 이 subtask는 DB schema 없이 Go interface, accessor, boundary test만 만든다.

## 사용자 리뷰 요청 흐름

구현 중 직접 사용자 프롬프트는 금지된다. 선택된 SDD 결정 또는 Milestone `구현 잠금 > 결정 필요` 항목만 active review stub의 `사용자 리뷰 요청` 섹션에 기록하며, code-review가 검증 후 실제 `USER_REVIEW.md` 작성을 담당한다.

## 분석 결과

### 읽은 파일

- `AGENTS.md`
- `agent-ops/rules/project/rules.md`
- `agent-ops/rules/private/rules.md`
- `agent-ops/rules/common/rules-roadmap.md`
- `agent-ops/skills/common/router.md`
- `agent-ops/skills/common/plan/SKILL.md`
- `agent-ops/skills/common/_templates/implementation-user-review-request-section.md`
- `agent-roadmap/current.md`
- `agent-roadmap/phase/provider-change-request-integration/PHASE.md`
- `agent-roadmap/phase/provider-change-request-integration/milestones/provider-adapter-foundation.md`
- `agent-test/local/rules.md`
- `agent-test/local/core-smoke.md`
- `services/core/go.mod`
- `services/core/internal/provider/provider.go`
- `services/core/internal/provider/provider_test.go`
- `services/core/internal/provider/forgejo/push.go`
- `services/core/internal/provider/forgejo/push_test.go`
- `services/core/internal/core/model.go`
- `services/core/internal/core/model_test.go`
- `services/core/internal/storage/storage.go`
- `services/core/internal/storage/storage_test.go`
- `services/core/internal/storage/postgres.go`
- `services/core/internal/storage/postgres_internal_test.go`
- `services/core/internal/storage/postgres_repo_test.go`
- `services/core/internal/storage/postgres_test.go`
- `services/core/migrations/00001_initial.sql`

### 테스트 환경 규칙

- test_env: `local`
- `agent-test/local/rules.md` present/read. Routing matched `core / smoke`.
- `agent-test/local/core-smoke.md` present/read. Required command: `cd services/core && go test ./...`.
- Fresh focused command for this subtask: `cd services/core && go test -count=1 ./internal/storage ./internal/provider`.
- Fallback source: none needed.

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

- Provider model/capability helpers are covered by `services/core/internal/provider/provider_test.go`.
- Existing storage tests check Boundary base injection but not `ProviderConfigStore`; add coverage in `services/core/internal/storage/storage_test.go`.
- No DB persistence is expected in this subtask; that gap is intentionally deferred to `02+01_postgres_provider_store`.

### 심볼 참조

- none. This subtask adds storage API and should not rename or remove symbols.

### 분할 판단

- Split policy was evaluated before choosing files.
- Shared task group: `agent-task/m-provider-adapter-foundation`.
- `01_provider_store_boundary`: independent API/storage boundary setup.
- `02+01_postgres_provider_store`: depends on `01` and adds migration plus PgStore implementation.
- This plan is the independent predecessor. No predecessor `complete.log` is required.

### 범위 결정 근거

- Excludes PostgreSQL table/query implementation; that is owned by `02+01_postgres_provider_store`.
- Excludes webhook callback, signature verification, and normalization epics.
- Excludes provider read/write client behavior and external API calls.
- Excludes roadmap checkbox updates; code-review/runtime handles completion metadata.

### 빌드 등급

- `local-G04`: bounded Go API addition with local unit coverage and no external service dependency.

## 구현 체크리스트

- [ ] `storage.Store`에 provider config accessor와 `ProviderConfigStore` 계약을 추가한다.
- [ ] `storage.Boundary`에 provider config store injection/accessor를 연결하고 기존 constructors의 호환성을 유지한다.
- [ ] `storage_test.go`에 fake provider config store와 Boundary contract 테스트를 추가한다.
- [ ] `cd services/core && go test -count=1 ./internal/storage ./internal/provider` 및 `cd services/core && go test ./...`를 실행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [API-1] Provider config store 계약 추가

문제: [storage.go](/config/workspace/gito/services/core/internal/storage/storage.go:13)는 durable sub-store 목록을 제공하지만 provider config 저장/조회 boundary가 없다.

현재:

```go
// services/core/internal/storage/storage.go:13
type Store interface {
	Ping(ctx context.Context) error
	Repos() RepoStore
	WorkspaceLeases() WorkspaceLeaseStore
	Operations() OperationStore
	OperationEvents() OperationEventStore
	BranchWatches() BranchWatchStore
	RevisionCursors() RevisionCursorStore
	ProviderDeliveries() ProviderDeliveryStore
	AgentRunInputs() AgentRunInputStore
	WebhookDeliveries() WebhookDeliveryStore
}
```

해결 방법: `services/core/internal/provider`를 import하고 `ProviderConfigStore` interface를 추가한다. 권장 shape:

```go
type ProviderConfigStore interface {
	SaveProviderConfig(ctx context.Context, config provider.Config) (provider.Config, error)
	GetProviderConfig(ctx context.Context, id provider.ProviderID) (provider.Config, bool, error)
	ListProviderConfigs(ctx context.Context) ([]provider.Config, error)
}
```

`Store`에 `ProviderConfigs() ProviderConfigStore`를 추가한다. 입력 validation 에러는 `ErrInvalidProviderConfig`를 새로 둔다.

수정 파일 및 체크리스트:

- [ ] `services/core/internal/storage/storage.go`: provider import, `Store.ProviderConfigs`, `ErrInvalidProviderConfig`, `ProviderConfigStore` 추가.

테스트 작성: `storage_test.go`에서 fake store compile-time check를 추가한다.

중간 검증:

```bash
cd services/core && go test -count=1 ./internal/storage
```

기대 결과: storage package tests pass.

### [API-2] Boundary injection/accessor 연결

문제: [storage.go](/config/workspace/gito/services/core/internal/storage/storage.go:143)의 `Boundary`는 injected sub-store 접근자를 모으지만 provider config store 필드가 없다.

현재:

```go
// services/core/internal/storage/storage.go:143
type Boundary struct {
	repos             RepoStore
	leases            WorkspaceLeaseStore
	ops               OperationStore
	opEvents          OperationEventStore
	watches           BranchWatchStore
	cursors           RevisionCursorStore
	deliveries        ProviderDeliveryStore
	agentRunInputs    AgentRunInputStore
	webhookDeliveries WebhookDeliveryStore
}
```

해결 방법: `providerConfigs ProviderConfigStore` 필드와 `ProviderConfigs()` accessor를 추가한다. 기존 `New`와 `NewWithBranchEvents` 호출 호환성을 유지하기 위해 `New`는 nil provider config store를 유지하고, `NewWithBranchEvents`는 기존 signature를 깨지 않거나 별도 constructor를 추가한다. 권장: `NewWithProviderConfigs(...)`를 추가하고 기존 constructors는 그대로 둔다.

수정 파일 및 체크리스트:

- [ ] `services/core/internal/storage/storage.go`: Boundary 필드와 accessor 추가.
- [ ] `services/core/internal/storage/storage.go`: provider config store를 받을 constructor 추가 또는 기존 constructors 호환 유지.
- [ ] `services/core/internal/storage/storage_test.go`: fake store 주입 시 `ProviderConfigs()`가 같은 객체를 반환하는지 테스트.

테스트 작성: `TestBoundaryContract` 또는 새 테스트에서 provider config accessor를 검증한다.

중간 검증:

```bash
cd services/core && go test -count=1 ./internal/storage ./internal/provider
```

기대 결과: storage/provider package tests pass.

## 수정 파일 요약

| 파일 | 항목 |
| --- | --- |
| `services/core/internal/storage/storage.go` | API-1, API-2 |
| `services/core/internal/storage/storage_test.go` | API-1, API-2 |

## 최종 검증

```bash
cd services/core && go test -count=1 ./internal/storage ./internal/provider
cd services/core && go test ./...
```

기대 결과: 두 명령 모두 exit 0. `go test ./...`의 cached 출력은 허용된다.

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