<!-- task=m-workspace-port-env-standardization/01_service_defaults plan=0 tag=PORT_DEFAULTS -->

# Plan - PORT_DEFAULTS

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

`CODE_REVIEW-local-G06.md`의 구현 에이전트 소유 섹션 작성까지가 구현입니다. 변경 후 검증을 실행하고 실제 stdout/stderr를 붙여 넣은 뒤 active 파일을 그대로 두고 리뷰를 요청하세요. 사용자 결정, 사용자 소유 외부 환경, 범위 충돌이 없이는 직접 질문하지 말고 `사용자 리뷰 요청` 섹션에 근거를 남깁니다. 최종 archive, `complete.log`, roadmap 갱신은 code-review/runtime 책임입니다.

## 배경

현재 API/worker runtime default는 `8080/8081/5432/6379`이고, Milestone은 backend `18030/18031`, DB/cache `15430/16330` 후보를 표준화하려 한다. service default를 먼저 바꿔야 compose/bin과 CLI/client 문서가 같은 기준을 바라볼 수 있다. 이 subtask는 service config와 service-local tests만 다룬다.

## 사용자 리뷰 요청 흐름

구현 중 blocker는 active `CODE_REVIEW-local-G06.md`의 `사용자 리뷰 요청` 섹션에 기록한다. 구현 에이전트는 사용자에게 직접 질문하지 않고, code-review가 해당 요청을 검증해 필요할 때만 `USER_REVIEW.md`를 작성한다.

## 분석 결과

### 읽은 파일

- `agent-roadmap/current.md`
- `agent-roadmap/phase/trading-expansion/PHASE.md`
- `agent-roadmap/phase/trading-expansion/milestones/workspace-port-env-standardization.md`
- `agent-ops/rules/project/domain/api/rules.md`
- `agent-ops/rules/project/domain/worker/rules.md`
- `agent-test/local/rules.md`
- `agent-test/local/api-smoke.md`
- `agent-test/local/worker-smoke.md`
- `services/api/internal/config/config.go`
- `services/api/internal/config/config_test.go`
- `services/worker/internal/config/config.go`
- `services/worker/internal/config/config_test.go`
- `services/worker/README.md`

### 테스트 환경 규칙

- test_env: `local`.
- `agent-test/local/rules.md`를 읽었다. local quick check는 현재 checkout에서 실행하고, raw secret/personal endpoint 출력 금지.
- matched profiles: `agent-test/local/api-smoke.md`, `agent-test/local/worker-smoke.md`.
- API 작은 변경 필수 검증: `go test ./services/api/...`.
- worker 작은 변경 필수 검증: `go test ./services/worker/...`.
- storage SQL 변경은 없으므로 `bin/worker-storage-check`는 대상이 아니다.
- `<확인 필요>` 값 없음. Go toolchain은 `/config/.local/bin/go`에서 확인했다.

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

- API default worker URL 변경은 `services/api/internal/config/config_test.go`가 직접 검증한다. API port default는 현재 직접 assertion이 없으므로 이 plan에서 추가한다.
- worker port default 변경은 `services/worker/internal/config/config_test.go`가 검증한다.
- worker DB/Redis fallback 변경은 현재 직접 assertion이 없으므로 이 plan에서 추가한다.

### 심볼 참조

- renamed/removed symbols: none.

### 분할 판단

- split policy를 먼저 평가했다. 전체 migration은 service runtime defaults, operations infra/bin, operator/client references가 다른 ownership과 검증 경로를 가진다.
- shared task group: `m-workspace-port-env-standardization`.
- `01_service_defaults`: API/worker config와 service-local tests. depends_on=[].
- `02+01_local_infra`: compose/bin/README 정렬. depends_on=[01].
- `03+01,02_operator_client_refs`: CLI/client URL 참조와 최종 stale reference sweep. depends_on=[01,02].

### 범위 결정 근거

- 이 subtask는 `services/api/internal/config/**`, `services/worker/internal/config/**`, `services/worker/README.md`만 수정한다.
- `deployments/local/**`, `bin/**`, root `README.md`, CLI/client URL 참조는 후속 split task에서 수정한다.
- proto-socket contracts, worker storage migrations, Flutter UI는 포트 default 변경 범위를 벗어난다.

### 빌드 등급

- build/review: `local-G06`. 두 service config를 건드리지만 변경은 fallback literal과 tests에 국한되고 검증이 deterministic하다.

## 구현 체크리스트

- [ ] API config default를 API `18030`, worker socket `18031` 기준으로 갱신하고 default test를 보강한다.
- [ ] worker config default를 worker `18031`, PostgreSQL `15430`, Redis `16330` 기준으로 갱신하고 default test를 보강한다.
- [ ] `services/worker/README.md` configuration table을 새 runtime default에 맞춘다.
- [ ] `go test ./services/api/...`와 `go test ./services/worker/...`를 실행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [PORT_DEFAULTS-1] API config defaults

문제: `services/api/internal/config/config.go:22-27`이 API port `8080`과 worker socket `8081`을 fallback으로 사용한다. `services/api/internal/config/config_test.go:44-45`도 worker URL default를 `8081`로 기대하고, API port default assertion은 없다.

Before:

```go
// services/api/internal/config/config.go:21-27
Host:                 getenv("ALT_API_HOST", "127.0.0.1"),
Port:                 getenvInt("ALT_API_PORT", 8080),
SocketPath:           getenv("ALT_API_SOCKET_PATH", "/socket"),
HeartbeatIntervalSec: getenvInt("ALT_SOCKET_HEARTBEAT_INTERVAL_SEC", 30),
HeartbeatWaitSec:     getenvInt("ALT_SOCKET_HEARTBEAT_WAIT_SEC", 10),
WSOriginPatterns:     getenvList("ALT_API_WS_ORIGIN_PATTERNS", "localhost:*,127.0.0.1:*"),
WorkerSocketURL:      getenv("ALT_WORKER_SOCKET_URL", "ws://127.0.0.1:8081/socket"),
```

해결 방법: `ALT_API_PORT` fallback을 `18030`으로, `ALT_WORKER_SOCKET_URL` fallback을 `ws://127.0.0.1:18031/socket`으로 바꾼다. `TestLoadDefaultsIncludeLocalWebSocketOrigins` 또는 별도 default test에서 `cfg.Port == 18030`과 worker URL default를 검증한다.

수정 파일 및 체크리스트:

- [ ] `services/api/internal/config/config.go`
- [ ] `services/api/internal/config/config_test.go`

테스트 작성: 기존 config test에 default assertion을 추가한다.

중간 검증:

```bash
go test ./services/api/...
```

기대 결과: exit code 0. Go test cache output은 허용한다.

### [PORT_DEFAULTS-2] Worker config defaults

문제: `services/worker/internal/config/config.go:20-25`가 DB/cache host fallback `5432/6379`, worker socket `8081`을 사용한다. `services/worker/internal/config/config_test.go:41-42`는 worker port `8081`만 확인하고 DB/Redis fallback은 확인하지 않는다.

Before:

```go
// services/worker/internal/config/config.go:20-25
DatabaseURL:    getenv("DATABASE_URL", "postgres://alt:alt@localhost:5432/alt?sslmode=disable"),
RedisURL:       getenv("REDIS_URL", "redis://localhost:6379/0"),
RedisKeyPrefix: getenv("ALT_REDIS_KEY_PREFIX", "alt"),
WorkerQueue:    getenv("ALT_WORKER_QUEUE", "default"),
Host:           getenv("ALT_WORKER_HOST", "127.0.0.1"),
Port:           getenvInt("ALT_WORKER_PORT", 8081),
```

해결 방법: fallback을 `postgres://alt:alt@localhost:15430/alt?sslmode=disable`, `redis://localhost:16330/0`, worker port `18031`로 갱신한다. default test에서 세 값을 모두 검증한다.

수정 파일 및 체크리스트:

- [ ] `services/worker/internal/config/config.go`
- [ ] `services/worker/internal/config/config_test.go`

테스트 작성: 기존 `TestConfigDefault`에 `DatabaseURL`, `RedisURL`, `Port` assertion을 둔다.

중간 검증:

```bash
go test ./services/worker/...
```

기대 결과: exit code 0. Go test cache output은 허용한다.

### [PORT_DEFAULTS-3] Worker README defaults

문제: `services/worker/README.md:47-48`가 worker DB/Redis defaults를 `5432/6379`로 문서화한다.

Before:

```markdown
<!-- services/worker/README.md:47-48 -->
| `DATABASE_URL` | PostgreSQL connection string | `postgres://alt:alt@localhost:5432/alt?sslmode=disable` |
| `REDIS_URL` | Redis connection string | `redis://localhost:6379/0` |
```

해결 방법: configuration table을 `15430/16330` fallback으로 바꾸고, worker socket env rows가 없으면 `ALT_WORKER_HOST`, `ALT_WORKER_PORT`, `ALT_WORKER_SOCKET_PATH`를 추가한다.

수정 파일 및 체크리스트:

- [ ] `services/worker/README.md`

테스트 작성: README 문서 변경이라 별도 test는 쓰지 않는다. `rg`로 stale defaults를 검증한다.

중간 검증:

```bash
rg --sort path -n "5432|6379|8081|18031|15430|16330" services/worker/README.md services/worker/internal/config
```

기대 결과: old default `5432/6379/8081`은 intentionally retained test fixtures 외 service README/config fallback에 남지 않는다.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `services/api/internal/config/config.go` | PORT_DEFAULTS-1 |
| `services/api/internal/config/config_test.go` | PORT_DEFAULTS-1 |
| `services/worker/internal/config/config.go` | PORT_DEFAULTS-2 |
| `services/worker/internal/config/config_test.go` | PORT_DEFAULTS-2 |
| `services/worker/README.md` | PORT_DEFAULTS-3 |

## 최종 검증

```bash
go test ./services/api/...
go test ./services/worker/...
rg --sort path -n "127\\.0\\.0\\.1:8081|localhost:5432|localhost:6379|ALT_WORKER_PORT.*8081" services/api/internal/config services/worker/internal/config services/worker/README.md
```

기대 결과: 두 `go test` 명령은 exit code 0. 마지막 `rg`는 migration 후 의도치 않은 old service default가 없음을 보여야 하며, 남는 항목이 있으면 CODE_REVIEW에 intentional exception으로 설명한다.

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