fix: 하네스 제거 및 keycloak 문서 보강
This commit is contained in:
@@ -1 +0,0 @@
|
||||
../../vault/10-projects/ca-skeleton-frontend-operational-contract/branch-notes/feature-server-state-caching-contract.md
|
||||
@@ -0,0 +1,304 @@
|
||||
---
|
||||
title: branch / feature-server-state-caching-contract
|
||||
source_type: branch-note
|
||||
status: raw
|
||||
branch: feature-server-state-caching-contract
|
||||
parent_branch:
|
||||
related_projects: [ca-skeleton-frontend, ca-skeleton]
|
||||
governing_docs: [raw/project-notes/ca-skeleton-frontend-operational-contract.md]
|
||||
tags: [branch, ca-skeleton, frontend, caching, react]
|
||||
created: 2026-07-18
|
||||
target_merge:
|
||||
status_label: in-progress
|
||||
id: BR-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-010
|
||||
kind: project-work-item
|
||||
project: ca-skeleton-frontend-operational-contract
|
||||
work_item: WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-010
|
||||
inherits: [DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-SERVER-STATE-001@1]
|
||||
refines: []
|
||||
overrides: []
|
||||
depends_on: [WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-005]
|
||||
contract_packet: 1
|
||||
contract_packet_sha256: 325526901b9b8aa64182bc9aced8ee5ab2600340f803e35d3b012da576da8a4e
|
||||
imports: [FE-GATE-005@1, FE-GATE-007@1, FE-GATE-010@1, FE-OC-002@1, FE-OC-009@1, FE-OC-013@1, FE-OC-020@1, FE-OC-022@1, FE-OC-023@1]
|
||||
---
|
||||
|
||||
# branch: feature-server-state-caching-contract
|
||||
|
||||
> Layer: `raw/branch-notes/` — 단일 브랜치의 TODO·결정·진행 기록. `/branch-spec` 로 채운 `planned` 사전 명세 단계다. **frontend 코드는 아직 존재하지 않으므로 모든 구현 주장은 `planned`** 이며, 경로/이름은 hub blueprint 기준 예정치다.
|
||||
|
||||
<!-- section-id: branch-parent -->
|
||||
## 부모 (필수)
|
||||
|
||||
- [[raw/project-notes/ca-skeleton-frontend-operational-contract]]
|
||||
|
||||
<!-- GENERATED: branch-contract:start -->
|
||||
<!-- section-id: branch-contract-packet -->
|
||||
## 브랜치 계약 패킷
|
||||
|
||||
- **생성 시 프로젝트 개정**: `1`
|
||||
- **패킷 스키마**: `contract_packet: 1`
|
||||
- **완료 조건**: QueryCachePort와 TanStack adapter의 invalidation·stale test가 통과한다
|
||||
|
||||
<!-- section-id: inherited-project-decisions -->
|
||||
### 상속한 프로젝트 결정
|
||||
|
||||
| Decision Ref | Project Summary | Branch Application | Source |
|
||||
|---|---|---|---|
|
||||
| `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-SERVER-STATE-001@1` | application-owned QueryCachePort와 TanStack Query adapter를 사용하고 client store에 server state를 복제하지 않는다 | Work Item 완료 조건에 적용 | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] |
|
||||
|
||||
<!-- section-id: branch-local-decisions -->
|
||||
### 브랜치 지역 결정
|
||||
|
||||
> 기존 branch-local 결정은 아래 `## Decision Evidence Map / 결정-근거 매핑`의 D-row가 소유하며 이 packet에서 복제하지 않는다.
|
||||
|
||||
| Decision ID | Decision | Relation | Supporting Claims | Status |
|
||||
|---|---|---|---|---|
|
||||
|
||||
<!-- section-id: declared-overrides -->
|
||||
### 선언한 예외
|
||||
|
||||
| Override ID | Overrides | Reason | Approval | Status |
|
||||
|---|---|---|---|---|
|
||||
<!-- GENERATED: branch-contract:end -->
|
||||
|
||||
<!-- section-id: branch-goal -->
|
||||
## 목표
|
||||
|
||||
이 브랜치는 hub 의 **server-state 캐싱 계약**을 구현 착수 가능한 수준으로 낮춘다. 프로젝트 전역 계약 `FE-OC-012`(query key 와 invalidation 은 registry factory 만 MUST 사용)의 single owner 이며, hub 결정 [[raw/project-notes/ca-skeleton-frontend-operational-contract]] FE-D006 §4(server state policy = application-owned `QueryCachePort` 정의 + TanStack Query adapter 구현 + client store 비복제)을 실제 port·registry·adapter·failure 매핑으로 전개한다. 부수적으로 `FE-OC-011`(async surface state), `FE-OC-022`(registry governance — 본 브랜치가 `FE-REG-QUERY` owner), `FE-OC-024`(sample fixture)에 기여한다. 핵심 설계 판단은 **port ownership split** — application 이 `QueryCachePort` 를 소유(정의)하고 adapter 가 구현하며, presentation·application 은 TanStack Query client 를 직접 import 하지 않는다는 hub project decision 이다. 등급: `planned`.
|
||||
|
||||
- 이슈: 없음 (repository 미생성)
|
||||
- PR: 없음 (repository 미생성)
|
||||
|
||||
<!-- section-id: branch-scope -->
|
||||
## 범위
|
||||
|
||||
### 포함 범위
|
||||
|
||||
- `QueryCachePort` 계약 정의 (application-owned) 와 TanStack Query adapter 구현 blueprint — `FE-OC-012`, FE-D006.
|
||||
- `FE-REG-QUERY` query key factory + invalidation registry (`src/contracts/query-keys.js`) 최소 스키마 — `FE-OC-012`, `FE-OC-022`, hub §5.7.
|
||||
- server-state 를 client store 에 복제하지 않는 non-duplication 규칙 — FE-D006.
|
||||
- query cache defaults (staleTime / gcTime / refetch-on-focus / persistence) 의 `planned` default 값과 예외 트리거 — hub §9.2.
|
||||
- `QUERY_CACHE_FAILURE` 정규화 + negative fixture 요구 — hub §8.2 / §8.5.
|
||||
|
||||
### 제외 범위
|
||||
|
||||
> 의도적으로 제외. 인접 계약은 다른 owner 브랜치가 소유한다.
|
||||
|
||||
- async surface 의 state 렌더링(initial-loading/success/empty/terminal-error, refreshing/stale-degraded 등 시각 표현) — owner [[raw/branch-notes/feature-async-ui-state-contract]] (`FE-OC-011`). 본 브랜치는 cache state → view-model 로 넘길 뿐 시각 계약은 정하지 않는다.
|
||||
- HTTP retry algorithm·timeout·abort·idempotency 내부 — owner [[raw/branch-notes/feature-api-client-response-envelope-contract]] (`FE-OC-006`, `FE-OC-009`). 본 브랜치는 API policy callback 을 *소비*만 한다.
|
||||
- frontend error kind/code/default UX 사전(`FE-REG-ERROR`) — owner [[raw/branch-notes/feature-frontend-error-classification-boundary-contract]] (`FE-OC-008`). 본 브랜치는 `QUERY_CACHE_FAILURE` 를 *어느 kind 로 매핑할지*만 선언한다.
|
||||
- 8-registry governance 의 schema validation·single-owner 검사 기구 — owner [[raw/branch-notes/feature-frontend-contract-registry-governance]] (`FE-OC-022`). 본 브랜치는 `FE-REG-QUERY` 한 registry 의 스키마만 채운다.
|
||||
- sample slice 자체와 removal smoke — owner [[raw/branch-notes/feature-sample-feature-slice-contract-fixture]] (`FE-OC-024`).
|
||||
- layer 의존 방향·composition root 주입 규약 자체 — owner [[raw/branch-notes/feature-frontend-clean-architecture-layering-contract]] (`FE-OC-002`). 본 브랜치는 `QueryCachePort`/adapter 의 *shape* 과 "presentation·application 이 TanStack Query client 를 직접 import 하지 않는다"는 금지 대상만 공급하고, port 를 composition root 에 어떻게 등록·주입하는지의 convention 과 allowed/forbidden import 매트릭스는 그 owner 가 정한다.
|
||||
- restricted-import fixture 엔진(dependency-cruiser/ESLint rule 구성·실행·리포트) — owner [[raw/branch-notes/feature-frontend-architecture-enforcement-lint-contract]] (`FE-OC-020`, gate `FE-GATE-010`). 본 브랜치는 금지 import 목록을 선언할 뿐 lint 엔진을 소유하지 않는다.
|
||||
- cache persistence 를 opt-in 할 때의 storage key namespace·version·classification 규약 — owner [[raw/branch-notes/feature-frontend-storage-registry-contract]] (`FE-OC-013`). default 가 off 이므로 본 브랜치는 "opt-in 시 version partition 필요"라는 요구만 선언한다.
|
||||
- token/secret lifecycle — 외부 auth owner. cache key 에 token/PII 를 넣지 않는 규칙만 여기서 강제한다.
|
||||
|
||||
## 근거 (필수, 최소 1개+)
|
||||
|
||||
| Source | 정당화하는 결정 |
|
||||
|---|---|
|
||||
| [[raw/official-docs/tanstack-query-server-state-official]] | D1(server-state 전용 라이브러리 채택, `TSQ-C1`), D2(client store 비복제 — server state 는 구조적 staleness, `TSQ-C3`), D4(background refetch/staleness 위임, `TSQ-C5`·`TSQ-C4`). 초기 source. |
|
||||
| [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | FE-D006(port ownership split·non-duplication, §4.4) → D1·D2; `FE-OC-012` + §5.7 → D3(registry factory only); §9.2 query cache defaults → D5·D6; §8.2 `QUERY_CACHE_FAILURE` → D6; §5.7 version bump + §9.2 discard → D7. |
|
||||
|
||||
> TanStack Query overview 발췌는 **구체 default 값(staleTime/gcTime/retry) 과 retry semantics 를 증명하지 않는다**(그 문서의 Usage Boundaries 가 명시). 따라서 D5·D6 의 수치·정책은 official-doc 이 아니라 **hub §9.2 project default** 를 근거로 인용한다.
|
||||
|
||||
## TODO
|
||||
|
||||
각 항목 옆 증거 등급 표기. 현재 전부 `planned` (frontend repo 미생성).
|
||||
|
||||
- [ ] `QueryCachePort` interface 정의 (application-owned, read/write/invalidate) — 등급: `planned`
|
||||
- [ ] TanStack Query adapter 구현 + `bootstrap/composition-root.js` 주입 wiring — 등급: `planned`
|
||||
- [ ] `FE-REG-QUERY` query key factory (`src/contracts/query-keys.js`) + §5.7 최소 스키마(namespace/serialization/identity/invalidation/version/persistence) — 등급: `planned`
|
||||
- [ ] query cache defaults wiring (staleTime 30s sample read / gcTime 5m / refetch-on-focus / persistence off) — 등급: `planned`
|
||||
- [ ] `QUERY_CACHE_FAILURE` 정규화 매핑 + negative fixture(adapter throw / invalid cache result) — 등급: `planned`
|
||||
- [ ] deterministic cache tests: key 안정성, mutation→namespace invalidation 좁힘, stale/refetch, non-duplication architecture fixture — 등급: `planned`
|
||||
- [ ] 구현 repository·검증 evidence 식별 — 등급: `needs-confirmation`
|
||||
|
||||
## 진행 중 메모
|
||||
|
||||
- hub §4.4 port matrix, §5.7 query key registry, §8.2/§8.5 failure, §9.2 cache defaults 를 근거로 자기 매핑 완료. web 조사 불필요(hub + archived TanStack Query 로 충분).
|
||||
|
||||
## 결정 사항
|
||||
|
||||
> 각 결정의 상세 근거·선택 조건·위험은 아래 Decision Evidence Map 참조.
|
||||
|
||||
- 2026-07-18: server state 는 application-owned `QueryCachePort` 가 정의하고 TanStack Query adapter 가 구현 (D1) / 이유: server-state 전용 캐싱을 라이브러리에 위임하되 의존 방향을 뒤집지 않기 위함 / 대안: 수기 `useEffect`+fetch, 다른 server-state 라이브러리(SWR/RTK Query) / 근거: `raw/official-docs/tanstack-query-server-state-official.md#TSQ-C1`, hub FE-D006.
|
||||
- 2026-07-18: server state 를 client store(Redux/Zustand 등)에 복제하지 않음 (D2) / 이유: 두 소스가 갈라지면 staleness 를 스스로 만든다 / 대안: normalized entity store 복제 / 근거: `#TSQ-C3`, FE-D006.
|
||||
- 2026-07-18: query key·invalidation 은 `FE-REG-QUERY` factory 로만 생성, page 내 ad hoc array key 금지 (D3) / 근거: `FE-OC-012`, hub §5.7.
|
||||
- 2026-07-18: staleness·background refetch 는 라이브러리에 위임 (D4) / 근거: `#TSQ-C5`, `#TSQ-C4`, hub §9.2.
|
||||
- 2026-07-18: query cache defaults 는 hub §9.2 project default 를 채택 (D5, conditional-default).
|
||||
- 2026-07-18: retry 는 page-local 숫자 없이 API policy callback 에 위임하고, port 자체 실패는 `QUERY_CACHE_FAILURE` 로 정규화 (D6) / 근거: hub §9.2, §8.2.
|
||||
- 2026-07-18: version-incompatible cache data 는 reuse 하지 않고 discard, breaking 시 namespace version bump (D7) / 근거: hub §5.7, §9.2.
|
||||
|
||||
## 결정-근거 매핑
|
||||
|
||||
| Decision ID | Decision | 선택 조건 (언제 이 결정 / 언제 대안) | Supporting Claims | Evidence Strength | Open Risk |
|
||||
|---|---|---|---|---|---|
|
||||
| D1 | server state 는 application-owned `QueryCachePort` 가 정의하고 TanStack Query adapter 가 구현한다 (`FE-OC-012` / FE-D006) | 원격 소유 비동기 데이터를 fetch/cache/sync 할 때 이 결정. presentation·application 이 TanStack Query client 를 직접 import 하지 않는 것이 고정 invariant. offline-first normalized entity cache 가 필요해지면 FE-D006 revisit 로 대안 검토. **대안 선택 기준**: 라이브러리 자체(TanStack Query vs SWR vs RTK Query)는 hub 결정 [[raw/project-notes/ca-skeleton-frontend-operational-contract]] FE-D006 에서 상류 고정되며 본 브랜치에서 재결정하지 않는다 — archived TanStack overview 는 대안 대비 우위를 증명하지 않으므로 라이브러리 우열 주장 금지 | `raw/official-docs/tanstack-query-server-state-official.md#TSQ-C1`; [[raw/project-notes/ca-skeleton-frontend-operational-contract]] FE-D006 §4 | `official-doc` + `project-decision` | port 실제 신호(로딩/에러/refetch)를 view-model 로 어떻게 노출할지는 async-ui 브랜치와 계약을 맞춰야 함 |
|
||||
| D2 | server state 를 client store(Redux/Zustand 등)에 복제하지 않는다 (non-duplication, FE-D006) | server-owned 데이터는 `QueryCachePort` 만이 소유. 순수 client-local UI state 는 별도 관리. offline-first normalized cache 요구 시 대안 | `raw/official-docs/tanstack-query-server-state-official.md#TSQ-C3`; [[raw/project-notes/ca-skeleton-frontend-operational-contract]] FE-D006 | `official-doc` + `project-decision` | 개발자가 편의로 server data 를 로컬 store 에 미러링할 수 있음 → architecture fixture 로 강제 필요 |
|
||||
| D3 | query key 와 invalidation 은 `FE-REG-QUERY` factory 로만 생성한다; page 내 ad hoc array key 금지 (`FE-OC-012`) | 모든 key 에 대해 항상 이 결정 (invariant, 분기 없음). 대안 없음 — factory 우회는 계약 위반 | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] `FE-OC-012` §5 | `project-decision` | factory 를 우회한 inline key 를 정적으로 잡아내는 lint rule 이 아직 미정 |
|
||||
| D4 | staleness·background refetch 를 라이브러리에 위임하고 수기 `useEffect`+fetch 를 쓰지 않는다 (`FE-OC-012` / FE-D006) | stale query 는 focus 시 refetch enabled. high-cost operation 은 owner 가 opt-out(§9.2 exception) | `raw/official-docs/tanstack-query-server-state-official.md#TSQ-C5`, `#TSQ-C4`; [[raw/project-notes/ca-skeleton-frontend-operational-contract]] FE-D006 §9 | `official-doc` + `project-decision` | overview 발췌는 `refetchOnWindowFocus` 등 구체 API·기본값을 증명하지 않음 → 코드에서 확인 필요 |
|
||||
| D5 | query cache defaults 는 hub §9.2 값 채택: staleTime 30s(sample read), gcTime 5m, refetch-on-focus enabled(stale), cache persistence off (`FE-OC-012`) | sample read 기본은 30s; operation owner measurement 가 나오면 조정. persistence 는 offline requirement + storage threat model 확정 시 opt-in | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §9 (query cache defaults) | `conditional-default` | 이 수치는 project-local 초기값 — 측정 근거 없음. TanStack Query overview 는 default 값을 증명하지 않으므로 수치를 official 로 인용 금지 |
|
||||
| D6 | retry 는 page-local 숫자 없이 API policy callback 에 위임하고, `QueryCachePort` 자체 실패는 `QUERY_CACHE_FAILURE` 로 정규화하며 자동 request retry 를 하지 않는다 (`FE-OC-012`) | query 는 API policy callback 사용; mutation retry 는 keyed idempotency contract 있을 때만(§9.2). port 실패는 uncached mode 선언 시만 fallback, 아니면 terminal | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §9 §8 (`QUERY_CACHE_FAILURE`) | `project-decision` | retry semantics 는 archived overview 로 증명 불가 → API client owner 계약(`FE-OC-009`) 확정에 의존 |
|
||||
| D7 | version-incompatible cache data 는 reuse 하지 않고 discard 하며, API/schema breaking change 시 namespace version bump 한다 (`FE-OC-012` → `FE-OC-022`/`FE-OC-023`) | release/config/API schema version 과 호환되면 reuse; 불일치면 discard. cache migration 을 선택하면 compatibility 브랜치가 fixture/rollback 소유(delegated) | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §5 §9 (version bump / discard) | `project-decision` | migration 을 도입하면 rollback fixture 소유권이 `FE-OC-023` owner [[raw/branch-notes/feature-frontend-contract-compatibility-governance]] 로 이동(hub §9.2) — 도입 시 경계 재확인 필요 |
|
||||
|
||||
## 구현 가이드
|
||||
|
||||
> `planned` blueprint. 경로는 hub §4.6 Planned directory blueprint + §5.1 registry owner map 기준 예정치이며 repo 생성 시 바뀔 수 있다. CLAUDE.md §15.5 3-rule 준수.
|
||||
|
||||
### 1. `QueryCachePort` 계약 (application-owned)
|
||||
|
||||
> **Trace**: D1 + FE-D006 §4.4 (port ownership matrix) + `FE-OC-012`. Supporting: `#TSQ-C1`.
|
||||
>
|
||||
> - **UNSUPPORTED_IMPL_DECISION**: 정확한 메서드명/시그니처(`readQuery`/`executeMutation`/`invalidateByNamespace` 등)는 hub 가 원칙(registry key + cache command → cache state/invalidation result)만 권고하고 구체 API 모양은 권고하지 않음 → 명명은 임의 trade-off(가독성 우선, 실제 use-case 와 맞춰 조정).
|
||||
|
||||
| 항목 | `planned` 명세 | 근거 |
|
||||
|---|---|---|
|
||||
| 정의 위치 | `src/application/ports/query-cache-port.js` (application 이 소유) | §4.6, §4.2 (application owns `QueryCachePort` policy) |
|
||||
| 입력/출력 | registry query key + cache command → cache state / invalidation result | §4.4 port matrix |
|
||||
| consumer | application query/mutation orchestration (use-case) | §4.4 |
|
||||
| 금지 | presentation·application 이 TanStack Query client 직접 import; application 이 adapter 이름 인지 | §4.3, §9.2 |
|
||||
| failure vocab | `QUERY_CACHE_FAILURE` | §4.4, §8.2 |
|
||||
|
||||
### 2. TanStack Query adapter + composition-root wiring
|
||||
|
||||
> **Trace**: D1 + FE-D006 §4.2 (`adapters/query-cache`) + §4.5 boot order. Supporting: `#TSQ-C1`.
|
||||
>
|
||||
> - **UNSUPPORTED_IMPL_DECISION**: adapter 파일/클래스명(`query-cache/tanstack-query-cache-adapter.js` 등)은 hub 미권고 → 임의 명명(blueprint 디렉토리 규약에 맞춤).
|
||||
|
||||
| 항목 | `planned` 명세 | 근거 |
|
||||
|---|---|---|
|
||||
| 구현 위치 | `src/adapters/query-cache/` — application-owned port 구현, TanStack Query key/invalidation bridge | §4.2, §4.6 |
|
||||
| 조립 지점 | `bootstrap/composition-root.js` 가 adapter 생성 후 application facade 에 주입 (boot order 7단계: HTTP/storage/telemetry/query-cache adapter 생성) | §4.5, §9.2 |
|
||||
| 의존 방향 | adapter → application port + TanStack Query. adapter 는 use-case policy / page-local key 를 소유하지 않음 | §4.2, §4.3 |
|
||||
| 조립 규약 owner (본 § 밖) | composition root 의 등록·주입 convention 은 `FE-OC-002` owner [[raw/branch-notes/feature-frontend-clean-architecture-layering-contract]], 이를 강제하는 restricted-import fixture 는 `FE-OC-020` owner [[raw/branch-notes/feature-frontend-architecture-enforcement-lint-contract]] 소유. 본 §는 *주입 대상 adapter 의 shape* 만 명세한다 | §4.3, §4.5(boot order 7), §15.1 `FE-GATE-010` |
|
||||
|
||||
### 3. `FE-REG-QUERY` query key factory registry
|
||||
|
||||
> **Trace**: D3 + `FE-OC-012` + §5.7 (query key registry minimum schema). Supporting: `FE-OC-012`, hub §5.
|
||||
>
|
||||
> - **UNSUPPORTED_IMPL_DECISION**: object key ordering canonicalize 알고리즘을 hub 는 "canonicalize" 원칙만 명시하고 구체 알고리즘 미권고 → stable JSON key-sort(재귀 정렬) 채택은 임의 trade-off(결정성 우선, 성능은 key 크기 작다는 가정).
|
||||
|
||||
| Rule | `planned` normative behavior | 근거 |
|
||||
|---|---|---|
|
||||
| 위치 | `src/contracts/query-keys.js`, single owner = 본 브랜치 | §5.1 |
|
||||
| factory 형태 | `queryKeys.<feature>.all()` / `.list(filters)` / `.detail(id)` | §5.7 |
|
||||
| namespace | feature prefix 를 첫 element 로 | §5.7 |
|
||||
| serialization | object key ordering canonicalize (동일 filters → 동일 key) | §5.7 |
|
||||
| identity | PII·token·raw URL 을 key 에 넣지 않음 | §5.7 |
|
||||
| invalidation | mutation outcome 과 mapping 된 factory 만 invalidate; 이유 없는 broad `invalidateQueries()` 금지 | §5.7, §9.2 |
|
||||
| version | API/schema breaking change 시 namespace version bump | §5.7 |
|
||||
| persistence | default disabled; opt-in 시 release/config version partition. storage key 의 namespace·version·classification 규약 자체는 `FE-OC-013` owner [[raw/branch-notes/feature-frontend-storage-registry-contract]] 소유 (조건부 의존, default off 이므로 미발동) | §5.7, §9.2 |
|
||||
|
||||
### 4. Query cache defaults wiring
|
||||
|
||||
> **Trace**: D5 + §9.2 (query cache defaults). Supporting: hub §9.
|
||||
>
|
||||
> - **UNSUPPORTED_IMPL_DECISION**: 없음 — 값이 전부 hub §9.2 인용이라는 것은 곧 **owner 가 §9.2** 라는 뜻이므로 표를 복제하지 않는다. (수치의 *적정성* 은 §Claims To Verify 에서 측정 대상.)
|
||||
|
||||
**query cache default 8행의 owner 는 [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §9.2 다.** 요약 한 줄: query key 는 registry factory 만 사용하고, stale 30초 / gc 5분 / focus refetch 켬 / cache persistence 끔이 project default 이며, invalidation 은 mutation 결과의 registry namespace 로 한정한다(이유 없는 broad invalidate 금지).
|
||||
|
||||
### 5. `QUERY_CACHE_FAILURE` 정규화 (매핑 선언만)
|
||||
|
||||
> **Trace**: D6 + §8.2 failure matrix row + §8.5 negative fixture. Supporting: hub §8.
|
||||
>
|
||||
> - **UNSUPPORTED_IMPL_DECISION**: 없음 — kind/UX/telemetry 규칙은 §8.2 그대로. (kind→code→UX 사전의 *정의* 자체는 `FE-REG-ERROR` owner 소관 — R3 로 아래 §의존에 위임.)
|
||||
|
||||
| 항목 | `planned` 명세 | 근거 |
|
||||
|---|---|---|
|
||||
| trigger | `QueryCachePort` read/write/invalidate 가 throw 하거나 invalid cache result 반환 | §8.2 |
|
||||
| normalized kind | `QUERY_CACHE_FAILURE` | §8.2 |
|
||||
| auto retry | no automatic request retry | §8.2 |
|
||||
| fallback | operation 이 uncached mode 를 선언한 경우만 허용, 아니면 terminal. stale 표시를 위조하지 않음 | §8.2 |
|
||||
| telemetry | phase + query namespace만; raw key/data 금지 | §8.2 |
|
||||
| negative fixture | adapter throw 또는 invalid cache result → `QUERY_CACHE_FAILURE` | §8.5 |
|
||||
|
||||
## 엣지·실패·의존
|
||||
|
||||
- **실패·엣지 경로**:
|
||||
- `QueryCachePort` adapter throw / invalid cache result → `QUERY_CACHE_FAILURE`, 자동 request retry 없음, uncached-safe fallback 또는 terminal (§8.2). raw key/data 를 telemetry·UI 에 노출 금지.
|
||||
- 동일 filters 로 생성한 두 query key 가 serialization 비결정성으로 갈라지면 캐시 miss·중복 fetch 발생 → canonicalize 알고리즘으로 방지, deterministic key test 로 검증.
|
||||
- version-incompatible cache data 는 discard (§9.2) — reuse 시 stale/incompatible model 렌더 위험.
|
||||
- mutation 후 broad `invalidateQueries()` 남용 → 불필요한 refetch storm. 좁은 namespace invalidation 으로 제한 (§5.7/§9.2).
|
||||
- server state 를 client store 에 복제하면 두 소스가 갈라져 위조된 stale 상태 발생 (D2 위반).
|
||||
- **다른 계약 의존** (owner 브랜치 + 소유 contract 로 링크 — Decision ID 재진술은 hub register 참조):
|
||||
- [[raw/branch-notes/feature-api-client-response-envelope-contract]] — `FE-OC-006`/`FE-OC-009` (shared client + retry/timeout/idempotency policy). 본 브랜치의 D6 retry 위임은 이 계약을 consume; 그 policy 가 바뀌면 cache 의 retry 동작이 바뀐다.
|
||||
- [[raw/branch-notes/feature-async-ui-state-contract]] — `FE-OC-011` (async surface state matrix). cache state(refreshing/stale-degraded/mutation-pending)를 view-model 로 넘길 때 이 계약과 정합.
|
||||
- [[raw/branch-notes/feature-frontend-error-classification-boundary-contract]] — `FE-OC-008` (`FE-REG-ERROR` 정의). `QUERY_CACHE_FAILURE` 의 code/UX 사전은 이 owner 가 정의.
|
||||
- [[raw/branch-notes/feature-frontend-contract-registry-governance]] — `FE-OC-022` (registry single-owner/compatibility). `FE-REG-QUERY` 는 이 governance 하에 관리.
|
||||
- [[raw/branch-notes/feature-frontend-clean-architecture-layering-contract]] — `FE-OC-002` (layer 의존 방향 + application-owned output port + 단일 composition root). **소유권 분할**: 본 브랜치는 `QueryCachePort` 계약과 query-cache adapter 의 shape 을 공급하고, 그 adapter 를 composition root 에서 *어떤 규약으로 생성·등록·주입하는지* 와 layer 별 allowed/forbidden import 매트릭스는 이 owner 가 소유한다. 이 계약이 흔들리면 §구현 가이드 2의 "조립 지점"과 D1 의 port ownership invariant 가 함께 바뀐다.
|
||||
- [[raw/branch-notes/feature-frontend-architecture-enforcement-lint-contract]] — `FE-OC-002`/`FE-OC-020` (restricted-import fixture 엔진, gate `FE-GATE-010`: "forbidden import fixtures including direct TanStack client import"). D1/D2 를 정적으로 강제하는 fixture 는 이 owner 가 구현·집행하며, 본 브랜치는 금지 대상(presentation·application → TanStack Query client 직접 import, server state 의 client store 미러링) 목록만 선언한다.
|
||||
- [[raw/branch-notes/feature-frontend-contract-compatibility-governance]] — `FE-OC-023` (breaking change migration / version bump governance). D7 의 "version-incompatible cache data discard" 는 이 계약에 종속이며, cache migration 을 도입하는 순간 migration fixture 와 rollback 소유권이 이 owner 로 넘어간다 (hub §9.2 명시).
|
||||
- [[raw/branch-notes/feature-frontend-storage-registry-contract]] — `FE-OC-013` (storage key namespace/version/classification). cache persistence 를 opt-in 할 때만 활성화되는 조건부 의존. default off 이므로 현재는 미발동.
|
||||
|
||||
## 검증해야 할 주장
|
||||
|
||||
| Claim | Why uncertain | How to verify | Status |
|
||||
|---|---|---|---|
|
||||
| 동일 filters 에 대해 query key factory 가 항상 동일 key 를 생성 (canonicalization) | serialization/canonicalize 알고리즘이 아직 미구현·미선택 | deterministic cache key unit test (`FE-OC-012` minimum evidence "cache tests"; `FE-GATE-005` unit) | `needs-confirmation` |
|
||||
| mutation outcome 이 mapping 된 registry namespace 만 좁게 invalidate (broad invalidate 없음) | 구현 편의로 broad `invalidateQueries()` 를 쓰기 쉬움 | invalidation unit/integration test (`FE-GATE-007` MSW) | `needs-confirmation` |
|
||||
| staleTime 30s / refetch-on-focus 가 sample read 에 적절 | project-local 초기값, 측정 근거 없음 (overview 문서가 default 미증명) | operation owner measurement + cache/refetch 동작 test (§9.2 exception trigger) | `needs-confirmation` |
|
||||
| `QueryCachePort` adapter throw 가 `QUERY_CACHE_FAILURE` 로 정규화되고 request retry 를 유발하지 않음 | mapping·total-function 보장이 코드로 미검증 | negative fixture(adapter throw / invalid cache result → `QUERY_CACHE_FAILURE`, §8.5) | `needs-confirmation` |
|
||||
| presentation·application 이 TanStack Query client 를 직접 import 하지 않고 client store 에 server state 미복제 (D1/D2) | 의존 방향 위반은 런타임에 드러나지 않음 | dependency-cruiser/ESLint restricted-import architecture fixture (§4.3, gate `FE-GATE-010`). fixture 엔진 owner = `FE-OC-020` ([[raw/branch-notes/feature-frontend-architecture-enforcement-lint-contract]]), layer 매트릭스 owner = `FE-OC-002` ([[raw/branch-notes/feature-frontend-clean-architecture-layering-contract]]); 본 브랜치는 금지 대상만 제공 | `needs-confirmation` |
|
||||
| application 이 `QueryCachePort` 를 정의·소유하고 adapter 이름을 모름 (port ownership split) | port 정의 위치·주입 방향이 미구현 | dependency graph snapshot + composition-root review (§4.3/§4.5) | `planned` |
|
||||
|
||||
## 관심사 커버리지 (coverage-auditor 자동 생성 — 있을 때)
|
||||
|
||||
| 관심사 | 상태 | owner | 심각도 | 근거 |
|
||||
|---|---|---|---|---|
|
||||
|
||||
## 마주친 문제
|
||||
|
||||
- 없음 — `planned` 사전 명세 단계.
|
||||
|
||||
## 묶음 (이 branch에서 파생된 자료)
|
||||
|
||||
<!-- GENERATED: project-contract-imports:start -->
|
||||
## 가져온 프로젝트 계약
|
||||
|
||||
| Ref | Owner | 요약 | Branch 적용 |
|
||||
|---|---|---|---|
|
||||
| `FE-GATE-005@1` | [[raw/branch-notes/feature-frontend-test-taxonomy-contract]] | unit 레벨이 실패하면 merge 를 MUST 차단하고 warning 으로 낮추면 안 됨 | import 참조로 적용 |
|
||||
| `FE-GATE-007@1` | [[raw/branch-notes/feature-frontend-test-taxonomy-contract]] | MSW 기반 integration 매트릭스가 미충족이면 merge 를 MUST 차단 | import 참조로 적용 |
|
||||
| `FE-GATE-010@1` | [[raw/branch-notes/feature-frontend-architecture-enforcement-lint-contract]] | 금지된 layer import 가 통과하면 merge 를 MUST 차단 | import 참조로 적용 |
|
||||
| `FE-OC-002@1` | [[raw/branch-notes/feature-frontend-clean-architecture-layering-contract]] | `domain <- application <- presentation` 의존 방향과 application-owned output port를 MUST 지킴 | import 참조로 적용 |
|
||||
| `FE-OC-009@1` | [[raw/branch-notes/feature-api-client-response-envelope-contract]] | retry는 safe/idempotent request에 한정하고 cap·jitter·`Retry-After`를 MUST 적용 | import 참조로 적용 |
|
||||
| `FE-OC-013@1` | [[raw/branch-notes/feature-frontend-storage-registry-contract]] | storage key는 namespace·version·classification을 MUST 가지며 token/secret 저장을 금지 | import 참조로 적용 |
|
||||
| `FE-OC-020@1` | [[raw/branch-notes/feature-frontend-test-taxonomy-contract]] | gate 종류별 책임·fixture·artifact를 분리하고 실패를 warning으로 낮추면 안 됨 | import 참조로 적용 |
|
||||
| `FE-OC-022@1` | [[raw/branch-notes/feature-frontend-contract-registry-governance]] | 8개 registry는 single primary owner와 compatibility impact를 MUST 기록 | import 참조로 적용 |
|
||||
| `FE-OC-023@1` | [[raw/branch-notes/feature-frontend-contract-compatibility-governance]] | API/config/storage/release schema의 breaking change는 migration 또는 version bump 없이 배포하면 안 됨 | import 참조로 적용 |
|
||||
<!-- GENERATED: project-contract-imports:end -->
|
||||
|
||||
### Sub-branches (세부 작업)
|
||||
|
||||
- 없음 — 사전 명세 단계
|
||||
|
||||
### 오류 기록 (이 branch 작업 중 발생)
|
||||
|
||||
- 없음 — 사전 명세 단계
|
||||
|
||||
### 면접 준비 (이 작업에서 나올 수 있는 면접 질문)
|
||||
|
||||
- 없음 — 사전 명세 단계
|
||||
|
||||
### 강의 (이 작업을 위해 학습한 강의)
|
||||
|
||||
- 없음 — 사전 명세 단계
|
||||
|
||||
### job-posting tie-ins (이 작업에서 파생된 글감)
|
||||
|
||||
- 없음 — 사전 명세 단계
|
||||
|
||||
## 관련 일일 노트
|
||||
|
||||
- 없음 — 사전 명세 단계
|
||||
|
||||
## 완료 후 정리
|
||||
|
||||
- PR 링크: 없음 (repository 미생성)
|
||||
- 리뷰 메모: 없음
|
||||
- 머지 결과 / 배포 환경: 없음 — 코드 미착수, 전 항목 `planned`
|
||||
- **wiki 추출 대상**: 없음 — verified 항목 없음
|
||||
- **추출하지 않을 항목**: 전 결정·구현 명세 (`planned` / `needs-confirmation`)
|
||||
Reference in New Issue
Block a user