42 KiB
title, source_type, status, id, kind, project, work_item, inherits, refines, overrides, depends_on, contract_packet, branch, parent_branch, related_projects, governing_docs, tags, created, target_merge, status_label, contract_packet_sha256, imports
| title | source_type | status | id | kind | project | work_item | inherits | refines | overrides | depends_on | contract_packet | branch | parent_branch | related_projects | governing_docs | tags | created | target_merge | status_label | contract_packet_sha256 | imports | |||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| branch / feature-frontend-env-runtime-config-contract | branch-note | raw | BR-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-004 | project-work-item | ca-skeleton-frontend-operational-contract | WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-004 |
|
|
1 | feature-frontend-env-runtime-config-contract |
|
|
|
2026-07-18 | in-progress | 781ef2d614370c6a8603dfd4c254c8584737803fa6f88b19159cb46a349e841c |
|
branch: feature-frontend-env-runtime-config-contract
Layer:
raw/branch-notes/— 단일 브랜치의 TODO·결정·진행 기록. 머지/종료 후 verified 결과는/ingest로wiki/projects/에 추출한다.
부모 (필수)
브랜치 계약 패킷
- 생성 시 프로젝트 개정:
1 - 패킷 스키마:
contract_packet: 1 - 완료 조건: build/runtime/secret registry와 boot-invalid matrix가 검증된다
상속한 프로젝트 결정
| Decision Ref | Project Summary | Branch Application | Source |
|---|---|---|---|
DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-RUNTIME-CONFIG-001@1 |
deploy별 public value는 runtime config, compiler value는 build-time config로 분리한다 | config registry와 pre-mount runtime config validation에 적용한다 | raw/project-notes/ca-skeleton-frontend-operational-contract |
DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-CONFIG-FALLBACK-001@1 |
runtime config fallback 시 environment별 rebuild는 허용하되 artifact의 multi-environment 재사용은 금지한다 | static-only hosting fallback과 artifact 재사용 금지에 적용한다 | raw/project-notes/ca-skeleton-frontend-operational-contract |
브랜치 지역 결정
| Decision ID | Decision | Relation | Supporting Claims | Status |
|---|---|---|---|---|
| D1 | build-time public·runtime-public·secret config를 분리한다 | local |
raw/project-notes/ca-skeleton-frontend-operational-contract | proposed |
| D2 | runtime config fallback은 environment별 rebuild만 허용한다 | local |
raw/project-notes/ca-skeleton-frontend-operational-contract | proposed |
| D3 | secret-name key를 build·runtime registry에서 거부한다 | local |
raw/official-docs/vite-build-tool-official.md#VITE-C4, raw/official-docs/vite-build-tool-official.md#VITE-C5 |
proposed |
| D4 | React mount 전에 runtime config를 fetch하고 검증한다 | local |
raw/project-notes/ca-skeleton-frontend-operational-contract | proposed |
| D5 | runtime config validation matrix를 고정한다 | local |
raw/project-notes/ca-skeleton-frontend-operational-contract | proposed |
| D6 | boot failure 화면은 safe field만 노출한다 | local |
raw/project-notes/ca-skeleton-frontend-operational-contract | proposed |
| D7 | 모든 public config는 FE-REG-ENV를 경유한다 | local |
raw/project-notes/ca-skeleton-frontend-operational-contract | proposed |
| D8 | boot config validation 시간 예산의 측정 구간을 고정한다 | local |
raw/project-notes/ca-skeleton-frontend-operational-contract | proposed |
선언한 예외
| Override ID | Overrides | Reason | Approval | Status |
|---|
없음.
목표
이 브랜치는 project-wide 계약 FE-OC-004("build-time / runtime-public / secret config를 MUST 분리하고 boot 전에 runtime config를 검증")를 되묻지 않고 코드를 작성할 수 있는 구현 명세로 내린다. 구체적으로 (1) 환경 config registry FE-REG-ENV(src/contracts/env.js)를 single owner로 소유하고, (2) React mount 이전에 실행되는 runtime config fetch·검증 게이트(boot sequence 2~4단계, hub §4.5/§6.3)를 정의하며, (3) 세 종류 config(build-time public / runtime public / secret)의 분리 규칙과 secret 유출 차단 규칙(hub §6.1)을 확정한다. 근거는 hub decision FE-D012(deploy별 public value = pre-render runtime config, compiler value = build-time config)·FE-D013(runtime config fallback 규칙)과 Vite 공식 문서의 import.meta.env build-time 정적 치환·VITE_ prefix 노출 경계·secret 금지 경고(VITE-C3/VITE-C4/VITE-C5)다. 이 계약은 FE-OC-016(release/cache — runtime config cache policy)과 FE-OC-023(compatibility — config/API schema version)에 기여한다. 현재 frontend repository는 존재하지 않으므로 본 노트의 모든 구현 항목 등급은 planned다.
- 이슈: (없음 — repository 미생성)
- PR: (없음 — repository 미생성)
범위
포함 범위
FE-REG-ENV환경 config registry(src/contracts/env.js)의 schema·초기 row·single-owner 규칙 (FE-OC-004, hub §5.4)- build-time public / runtime public / secret 3분류 규칙과
VITE_prefix 사용 경계 (FE-D012, hub §6.1) - secret-name(
SECRET/PASSWORD/PRIVATE_KEY/TOKEN) key를 build·runtime registry 양쪽에서 거부하는 정적 가드 (hub §6.1,VITE-C4/VITE-C5) - React mount 이전 runtime config fetch(
no-store) + 검증 게이트와 boot 실패/버전 불일치 분기 (FE-D012, hub §4.5/§6.3) - runtime config 검증 규칙 카탈로그(required key·URL protocol allowlist·int range·boolean parse·schema/contract version compat·unknown-key strict) (
FE-OC-004, hub §6.4) - boot 실패 시 화면 노출 safe-field allowlist + redaction (hub §6.4)
- environment별 rebuild fallback 규칙: 한 artifact를 여러 env에 재사용하지 않음 (
FE-D013) - boot config 검증 시간 예산
FE-NFR-006(≤ 500ms, network delay 제외)의 측정 경계와 valid-config timing fixture —FE-GATE-004pass condition의 timing 절반 (hub §14.2, §15.1)
제외 범위
의도적으로 제외 — 다른 owner 브랜치/계약 소유. 각 브랜치는 자신이 소유한
FE-OC-*계약으로 표기(하위FE-D*는 hub decision register 참조).
- normalized error kind 어휘(
BOOT_CONFIG_FAILURE,DEPLOY_MISMATCH)와 raw body/stack UI 유출 catalog → raw/branch-notes/feature-frontend-error-classification-boundary-contract (FE-OC-008) - runtime schema(Zod) 구성·parse 메커니즘 자체 → raw/branch-notes/feature-runtime-schema-validation-contract (
FE-OC-007) - release manifest 정합성 tuple·cache header·rollback·
DEPLOY_MISMATCHrecovery UI → raw/branch-notes/feature-frontend-release-cache-rollback-contract (FE-OC-016,FE-OC-017) - config/API schema version breaking-change migration 정책 → raw/branch-notes/feature-frontend-contract-compatibility-governance (
FE-OC-023) - 8-registry governance(single-owner diff·compatibility 추적) → raw/branch-notes/feature-frontend-contract-registry-governance (
FE-OC-022) - telemetry endpoint redaction/전송 → raw/branch-notes/feature-frontend-observability-logging-trace-contract (
FE-OC-014) — 본 registry는TELEMETRY_ENABLED/TELEMETRY_ENDPOINTkey와 분류만 선언, 전송·redaction 메커니즘은 관측 브랜치 소유 - token/session lifecycle → raw/branch-notes/feature-frontend-auth-session-integration-contract (
FE-OC-010) — 본 registry는AUTH_MODEkey만 선언 - Vite/toolchain·
import.meta.env노출 메커니즘 자체 → 의존 브랜치 raw/branch-notes/feature-frontend-project-bootstrap-toolchain-contract (FE-OC-003) - composition root 조립 순서 enforcement → raw/branch-notes/feature-frontend-clean-architecture-layering-contract (
FE-OC-002)
근거 (필수, 최소 1개+)
| Source | 정당화하는 결정 |
|---|---|
| raw/official-docs/vite-build-tool-official | VITE-C3(import.meta.env build-time 정적 치환) → build-time config는 재빌드로만 바뀐다는 D1/D2 전제; VITE-C4(오직 VITE_ prefix만 client 노출) → D3 노출 경계; VITE-C5(VITE_*에 secret 금지, 프로덕션 secret은 backend/serverless) → D3 secret 차단 규칙; VITE-C2(정적 자산 output) → static-only hosting fallback(D2) 전제 |
| raw/project-notes/ca-skeleton-frontend-operational-contract | 이 branch가 owner인 FE-D012/FE-D013 decision, FE-OC-004 계약, FE-REG-ENV(§5.4), boot order(§4.5)·boot sequence(§6.3)·runtime config 검증 규칙(§6.4)·boot 실패 safe-output(§6.4)·FE-RB-001 runbook(§16.1)의 project-decision 근거. 추가로 §14.2 FE-NFR-006(boot config validation ≤ 500ms, deterministic mocked fetch)·§15.1 FE-GATE-004(valid boot config validation timing 을 pass condition 에 포함)가 D8 시간 예산의 근거 |
TODO
각 항목 옆에 증거 등급 표기.
FE-REG-ENVregistry schema + 초기 14 key row 구현 (src/contracts/env.js) — 등급:planned- build/runtime/secret 3분류 + secret-name 거부 정적 가드 구현 — 등급:
planned src/bootstrap/load-runtime-config.js— mount 이전no-storefetch + boot 분기 구현 — 등급:planned- runtime config 검증 규칙(§6.4 8항) 구현 (schema 메커니즘은
FE-OC-007브랜치 consume) — 등급:planned - boot 실패 safe-field allowlist + redaction 구현 — 등급:
planned - boot invalid-config matrix 테스트(§20 Measurable completion) 작성 — 등급:
planned - config schema test(
FE-OC-004minimum evidence) 작성 — 등급:planned - valid-config timing fixture 작성 —
FE-NFR-006(≤ 500ms, mocked network delay 제외) 측정 +FE-GATE-004timing report 산출 — 등급:planned
진행 중 메모
없음 — scaffolding 단계. repository 미생성이므로 모든 항목 planned.
결정 사항
각 결정의 근거는 아래 Decision Evidence Map과 1:1 대응. 대안·선택 조건 포함.
- 2026-07-18: build-time public / runtime-public / secret 3분류 분리(
FE-D012) / 이유: deploy마다 달라지는 public value(API endpoint 등)를 재빌드 없이 바꾸려면 build-time 정적 치환(import.meta.env)이 아닌 pre-render runtime config가 필요 / 검토한 대안: 모든 값을 build-time으로 고정(env별 재빌드) / 근거:VITE-C3, hub §6.1·FE-D012 - 2026-07-18: runtime config fallback = env별 rebuild 허용하되 artifact 재사용 금지(
FE-D013) / 이유: hosting이 atomic config publish를 못 할 때 deploy ambiguity를 제한 / 검토한 대안: 단일 artifact를 여러 env에 재사용 + build-time fallback / 근거: hubFE-D013 - 2026-07-18: secret-name key 양쪽 registry 거부 +
VITE_는 build metadata·non-secret 상수만 / 이유:VITE_*는 번들에 정적 치환되어 client에 노출되므로 secret 금지 / 검토한 대안: 관례 문서화만(정적 강제 없음) / 근거:VITE-C4,VITE-C5, hub §6.1 - 2026-07-18: React mount 이전 runtime config fetch+검증 게이트(boot 2~4단계) / 이유: 잘못된 config로 product route를 mount하지 않기 위해 / 검토한 대안: mount 이후 lazy config load / 근거: hub §4.5 boot order, §6.3 sequence
- 2026-07-18: runtime config 검증 8항 커버리지 + unknown-key strict default / 이유: config는 신뢰 경계 밖 입력이므로 boot 전 전량 검증 / 검토한 대안: 필수 key 존재만 확인 / 근거: hub §6.4 (schema 메커니즘은
FE-OC-007위임) - 2026-07-18: boot 실패 화면 safe-field allowlist + endpoint/stack redaction / 이유: 실패 화면으로 endpoint·raw config·stack 유출 금지 / 검토한 대안: raw error 그대로 표시 / 근거: hub §6.4 (error kind 어휘는
FE-OC-008위임) - 2026-07-18: 모든 public config는
FE-REG-ENV경유(ad hocimport.meta.env금지) / 이유: rename·compatibility 영향 추적 single owner / 검토한 대안: 파일마다import.meta.env직접 접근 / 근거: hub §5.1·§5.4,FE-D018 - 2026-07-20:
MAX_RETRY_ATTEMPTS허용 범위를 retry cap 소유 결정에 정렬(0–2) / 이유: config가 owner 결정보다 넓은 값을 통과시키면 하류 client가 조용히 clamp 하게 되어 "설정한 값 ≠ 동작하는 값" 이 되므로, 경계 검증을 owner cap 과 동일하게 둔다 / 검토한 대안: config는 0–5를 통과시키고 API client가 clamp(설정-동작 괴리 허용) / 근거: raw/project-notes/ca-skeleton-frontend-operational-contractFE-D015(initial call 이후 최대 2회) — cap 소유는FE-OC-009, 본 branch는 그 cap 을 config 경계에서 재선언만 하고 값 자체를 정하지 않음 - 2026-07-20: boot config 검증 시간 예산
FE-NFR-006은 "검증 구간만" 측정하며 mocked network delay 를 제외한다 / 이유:FE-GATE-004pass condition 이 timing 을 포함하는데(hub §15.1) 측정 구간을 고정하지 않으면 fetch 대기 시간이 예산을 잠식해 gate 가 무의미해짐 / 검토한 대안: fetch 시작~mount 직전 end-to-end 측정(hosting/network 변동에 좌우) / 근거: raw/project-notes/ca-skeleton-frontend-operational-contractFE-NFR-006(§14.2, deterministic mocked fetch, ≤ 500ms excluding network delay), §15.1FE-GATE-004
결정-근거 매핑
Supporting Claims: 공식 문서는raw/official-docs/<slug>.md#<CLAIM>(백틱), project decision은 hub wikilink + FE-D/§ 참조. 위임 대상 sibling 브랜치는 소유FE-OC-*로 표기(하위FE-D*는 hub register).
| Decision ID | Decision | 선택 조건 (언제 이 결정 / 언제 대안) | Supporting Claims | Evidence Strength | Open Risk |
|---|---|---|---|---|---|
| D1 | FE-D012 — deploy별 public value는 pre-render runtime config(/config.json), compiler value·asset identity는 build-time config로 분리 |
hosting이 HTML보다 먼저 runtime config를 atomic publish 가능 → runtime config 경로; 정적 파일만 제공 → D2 env별 rebuild fallback; SSR/edge 도입 → 본 계약 그대로 적용 않고 별도 project fork(hub §6.2) | raw/official-docs/vite-build-tool-official.md#VITE-C3, raw/official-docs/vite-build-tool-official.md#VITE-C2; raw/project-notes/ca-skeleton-frontend-operational-contract FE-D012 §6.1 |
conditional-default + official-doc |
hosting이 runtime config atomic publish를 미지원하면 재검토(hub revisit trigger) |
| D2 | FE-D013 — runtime config fallback은 env별 rebuild를 허용하되 한 artifact를 여러 env에 재사용하지 않음 |
atomic config publish 불가한 static-only hosting일 때만 env별 rebuild; runtime config endpoint 도입되면 단일 artifact + runtime fetch로 복귀. 어떤 경우에도 동일 artifact를 여러 env로 재배포 금지 | raw/project-notes/ca-skeleton-frontend-operational-contract FE-D013; raw/official-docs/vite-build-tool-official.md#VITE-C3 |
conditional-default + project-decision |
runtime config endpoint 도입 시 재검토; artifact 재사용 시 deploy ambiguity 재발 |
| D3 | secret-name(SECRET/PASSWORD/PRIVATE_KEY/TOKEN) key를 build·runtime registry 모두 거부; VITE_ prefix는 build metadata·non-secret compile-time 상수만 |
항상 적용되는 invariant; auth owner가 browser storage를 꼭 써야 하는 경우에만 별도 threat model + owner evidence로 예외(skeleton default 아님, hub §6.1) | raw/official-docs/vite-build-tool-official.md#VITE-C4, raw/official-docs/vite-build-tool-official.md#VITE-C5; raw/project-notes/ca-skeleton-frontend-operational-contract §6.1 |
official-doc |
로그·디버그 등 다른 경로의 우발적 유출은 VITE-C4가 커버 안 함 → FE-OC-019 browser-security와 교차 필요 |
| D4 | runtime config + release manifest를 React mount 이전에 no-store fetch → 검증 → (valid) 조립·mount / (invalid) boot error shell / (mismatch) recovery UI. boot 2~4단계 실패 시 product route mount 안 함 |
config invalid → BOOT_CONFIG_FAILURE(product route mount 중단); version mismatch → DEPLOY_MISMATCH(controlled recovery, reload loop 금지); valid → mount. telemetry adapter 생성 실패는 non-blocking(console-safe fallback) |
raw/project-notes/ca-skeleton-frontend-operational-contract §4.5 boot order, §6.3 sequence, FE-OC-004 |
project-decision |
bounded refetch(최대 1회, §16.1)와 recovery UI 경계가 FE-OC-016/FE-OC-025 소유와 겹침 |
| D5 | runtime config 검증은 required-key·URL protocol allowlist(prod https)·int range(timeout/retry)·boolean strict parse·config schema version·API contract version·release/build ID coherence·unknown-key strict를 모두 커버 | unknown key는 strict reject default; schema가 명시적으로 passthrough할 때만 additive key 허용. protocol allowlist는 prod https 강제, local 예외는 문서화된 경우만 | raw/project-notes/ca-skeleton-frontend-operational-contract §6.4, FE-OC-004; schema 메커니즘은 raw/branch-notes/feature-runtime-schema-validation-contract (FE-OC-007) 위임 |
project-decision |
REQUEST_TIMEOUT_MS 경계 값은 hub 미규정(아래 impl §4 UNSUPPORTED_IMPL_DECISION); MAX_RETRY_ATTEMPTS 범위는 retry cap owner(FE-OC-009)에 정렬해 해소(0–2); version compat 정책은 FE-OC-023 위임 |
| D6 | boot 실패 화면은 safe-field(error.kind,error.code,buildId,configSchemaVersion,releaseId,supportReference)만 노출; endpoint·query·header·raw config·stack은 화면 금지 |
항상 적용되는 redaction invariant — 어떤 실패 종류에서도 forbidden field는 user-facing screen에 표시 안 함 | raw/project-notes/ca-skeleton-frontend-operational-contract §6.4, FE-OC-004; error kind 어휘는 raw/branch-notes/feature-frontend-error-classification-boundary-contract (FE-OC-008) 위임 |
project-decision |
supportReference 생성 방식 미규정(impl §5 UNSUPPORTED_IMPL_DECISION); telemetry로의 상관 전송은 FE-OC-014 소유 |
| D7 | 모든 build/runtime public config key는 FE-REG-ENV(src/contracts/env.js) 등록 후 사용; registry 밖 import.meta.env·config key 직접 사용은 violation. public-sensitive=browser 가시이나 로그·telemetry 원문 금지 |
항상 적용(hub FE-D018 8-registry single-owner invariant); code generation SSOT 채택 시 registry 형태 재검토 |
raw/project-notes/ca-skeleton-frontend-operational-contract §5.1 §5.4 FE-D018 |
project-decision |
registry diff·single-owner 강제와 compatibility 추적은 FE-OC-022/FE-OC-023 위임 |
| D8 | boot config 검증 시간 예산 FE-NFR-006(≤ 500ms) 은 검증 구간만 측정한다 — config 본문이 메모리에 있는 시점부터 normalized config 반환 또는 BOOT_CONFIG_FAILURE 확정까지. fetch·mocked network delay·mount 이후는 제외. FE-GATE-004 는 이 branch 가 config invalid matrix + valid-config timing fixture 를, schema 브랜치가 content-type/JSON/envelope/payload invalid matrix 를 각각 제공해 함께 PASS 시킨다 |
deterministic mocked fetch 환경에서 항상 측정(hub §14.2 context); 실제 network 를 타는 환경에서는 이 예산을 주장하지 않음(lab 값을 production 수치로 표현 금지) | raw/project-notes/ca-skeleton-frontend-operational-contract §14.2 FE-NFR-006, §15.1 FE-GATE-004, FE-OC-004; invalid fixture 절반은 raw/branch-notes/feature-runtime-schema-validation-contract (FE-OC-007) 소유 — 해당 노트도 timing fixture 소유를 본 branch 로 귀속 |
project-decision |
측정 시작점·통계(단일 실행 vs 중앙값)는 hub 미규정(impl §6 UNSUPPORTED_IMPL_DECISION); 검증 대상 fixture 규모가 커지면 500ms 예산 재검토 필요 |
구현 가이드
plannedblueprint — frontend repository 미생성. 경로는 hub §4.6 Planned directory blueprint + §5.1 registry owner map에서 도출되어 grounded지만, 코드가 없으므로 전체가planned다.
1. 환경 config registry FE-REG-ENV
Trace: D7 (hub §5.1·§5.4
FE-REG-ENV,FE-D018) + D3. Planned pathsrc/contracts/env.js(§5.1 owner map).
- UNSUPPORTED_IMPL_DECISION: registry의 JS 표현(row 배열
export const ENV_REGISTRY = [...]vs key→meta object map)은 hub가 schema 컬럼만 규정하고 JS 구조는 미규정 → row 배열 선택. trade-off: 순서 보존 + snapshot diff(FE-OC-022)가 단순.
초기 14 key(hub §5.4 그대로 — 신규 발명 아님):
| Key | Phase | Classification | Required | Default | Failure |
|---|---|---|---|---|---|
VITE_BUILD_ID |
build | public metadata | yes | none | build fail |
VITE_COMMIT_SHA |
build | public metadata | yes in CI | local sentinel allowed | release evidence fail |
VITE_ROUTER_BASE_PATH |
build | non-secret compile-time constant | yes | / |
route mount fail |
VITE_RUNTIME_CONFIG_URL |
build | non-secret compile-time constant | yes | /config.json |
boot fail |
APP_ENV |
runtime | public | yes | none | boot fail |
API_BASE_URL |
runtime | public-sensitive | yes | none | boot fail |
REQUEST_TIMEOUT_MS |
runtime | public | no | 10000 |
invalid value boot fail |
MAX_RETRY_ATTEMPTS |
runtime | public | no | 2 after initial (허용 범위 0–2, cap owner FE-OC-009) |
invalid value boot fail |
TELEMETRY_ENABLED |
runtime | public | yes | false |
invalid value boot fail |
TELEMETRY_ENDPOINT |
runtime | public-sensitive | conditional | none | telemetry degrade |
AUTH_MODE |
runtime | public | yes | external |
unsupported mode boot fail |
CONFIG_SCHEMA_VERSION |
runtime | public | yes | none | compatibility fail |
API_CONTRACT_VERSION |
runtime | public | yes | none | compatibility fail |
RELEASE_MANIFEST_URL |
runtime | public | yes | /release-manifest.json |
mismatch detection degrade/fail per policy |
public-sensitive(예:API_BASE_URL,TELEMETRY_ENDPOINT) = browser 가시이나 로그·telemetry에 원문 금지 (hub §5.4). secret 분류 아님.- ad hoc 사용 위반(hub §5.1): registry 없는
import.meta.env또는 config key 사용.
2. runtime / secret 3분류 + secret-name 거부 가드
Trace: D1 (
FE-D012, hub §6.1,VITE-C3) + D3 (VITE-C4,VITE-C5, hub §6.1).
- UNSUPPORTED_IMPL_DECISION: secret-name 거부 매칭 알고리즘(case-insensitive substring
/(SECRET|PASSWORD|PRIVATE_KEY|TOKEN)/ivs 정확 word 매칭) 미규정 — hub는 4개 토큰만 나열(§6.1) → case-insensitive substring(fail-safe) 선택. trade-off:TOKENIZER같은 정당한 이름 false-positive 위험 → 문서화된 명시적 예외 목록으로 완화.
| Class | 예시 | Browser 가시 | 변경 메커니즘 | Cache | 규칙 |
|---|---|---|---|---|---|
| build-time public | VITE_BUILD_ID, VITE_COMMIT_SHA, VITE_ROUTER_BASE_PATH |
yes | rebuild(정적 치환) | bundled | compiler behavior·asset identity만 |
| runtime public | API_BASE_URL, public feature flag, TELEMETRY_ENDPOINT |
yes | runtime config publish | no-store |
React mount 이전 검증 |
| secret | client secret, private key, DB credential, refresh token material | 번들 금지 | server/auth owner | N/A | frontend env·bundle·HTML 어디에도 금지 |
VITE_prefix는 build metadata + non-secret compile-time 상수(base path,/config.json위치)에만 (hub §6.1,VITE-C4).- 이름에
SECRET/PASSWORD/PRIVATE_KEY/TOKEN포함 key는 build·runtime registry 양쪽에서 거부 (hub §6.1). 프로덕션 secret은 backend/serverless 소관 (VITE-C5).
3. mount 이전 runtime config 로더 + boot 분기
Trace: D4 (hub §4.5 boot order, §6.3 sequence). Planned paths
src/bootstrap/load-runtime-config.js,src/bootstrap/composition-root.js,src/bootstrap/main.jsx(§4.6). 의존: build/import.meta.env노출은 raw/branch-notes/feature-frontend-project-bootstrap-toolchain-contract (FE-OC-003); composition root 조립은 raw/branch-notes/feature-frontend-clean-architecture-layering-contract (FE-OC-002) 소유.
- UNSUPPORTED_IMPL_DECISION: (a) boot error shell 컴포넌트 명/경로(예:
presentation/boundaries/BootErrorShell.jsx) — hub는 "boot error shell" 개념만, 명명/경로 미규정 → presentation/boundaries 하위에 두어 layering(FE-OC-002) 위반 회피. (b) pre-mount config fetch 클라이언트(rawfetchvs shared client) — boot 2단계 시점엔 shared client(FE-OC-006)가 아직 조립 전 → rawfetch선택. trade-off: shared client의 timeout/retry 정책은 config 로드에 적용 안 됨(부트 전용 최소 fetch).
본 branch 소유 구간은 단계 번호가 아니라 의미로 정의한다: "runtime config 취득 + 검증 완료까지, React mount 이전". 그 앞(build identity 읽기)과 뒤(adapter 조립·mount)는 타 owner 구간이다. hub 의 두 절이 나열 순서를 서로 다르게 쓰므로(§4.5 는 config 검증 → release manifest 정합성, §6.3 sequence 는 두 fetch → 검증) 번호 기반 참조는 깨지기 쉽다. 아래 목록은 §6.3 실행 순서를 따르고, 각 행에 hub §4.5 번호를 명시 매핑한다.
| 실행 순서(hub §6.3 기준) | hub §4.5 번호 | Owner |
|---|---|---|
| build identity 읽기 (build-time config, §1) | 1 | build/toolchain (FE-OC-003) — 본 branch 는 key 분류만 |
runtime config fetch — GET {VITE_RUNTIME_CONFIG_URL} no-store |
2 | 본 branch |
release manifest fetch — GET {RELEASE_MANIFEST_URL} no-store |
4의 입력 취득 | 본 branch (정합성 판정 자체는 FE-OC-016) |
| config envelope·schema·compatibility 검증 (§4) | 3 | 본 branch (schema 메커니즘은 FE-OC-007 consume) |
| registry snapshot → auth adapter → HTTP/storage/telemetry/query-cache adapter → application facade → router → React root mount | 5–10 | composition root (FE-OC-002) |
분기(hub §6.3):
- valid & compatible → normalized public config로 dependency 조립 + mount.
- invalid config →
BOOT_CONFIG_FAILURE→ boot error shell, product route mount 안 함. automatic refetch 최대 1회(hub §16.1). - version mismatch →
DEPLOY_MISMATCH→ controlled recovery UI, reload loop 금지. (recovery UI 상세는 raw/branch-notes/feature-frontend-release-cache-rollback-contract 소유 — 본 branch는 트리거/분기까지만.) - telemetry adapter 생성 실패 → console-safe fallback로 계속(boot 실패 아님, hub §4.5).
4. runtime config 검증 규칙
Trace: D5 (hub §6.4). schema 구성·parse 메커니즘은 raw/branch-notes/feature-runtime-schema-validation-contract (
FE-OC-007) 위임 — 본 §는 무엇을 검증하고 어떤 boot 결과로 이어지는지만.
- UNSUPPORTED_IMPL_DECISION:
REQUEST_TIMEOUT_MS정수 범위(제안 1000–60000)는 hub가 default(10000)만 주고 경계 미규정 → 0/음수 timeout 방지용으로 제안. trade-off: 상한 60000 은 임의값이며 api-client owner(FE-OC-009)가 total timeout 정책을 lock 할 때 재확인 필요.- 해소됨(구
UNSUPPORTED_IMPL_DECISION):MAX_RETRY_ATTEMPTS허용 범위는 0–2 — raw/project-notes/ca-skeleton-frontend-operational-contractFE-D015(initial call 이후 최대 2회)의 cap 을 config 경계에서 그대로 재선언한다. 이전 초안의 0–5 는 owner cap 보다 넓어 "config 는 통과, client 는 clamp" 하는 설정-동작 괴리를 만들었으므로 폐기. cap 값의 owner 는FE-OC-009이고 본 branch 는 값을 정하지 않으므로, cap 이 개정되면 이 범위도 따라 개정한다(본 노트 단독 변경 금지).
검증 MUST 커버(hub §6.4):
- required key 존재 (§1 Required=yes 전부)
- URL protocol allowlist — prod policy는
https, local 예외는 문서화된 경우만 - timeout/retry 정수 범위 —
REQUEST_TIMEOUT_MS1000–60000(제안),MAX_RETRY_ATTEMPTS0–2(cap ownerFE-OC-009에 정렬) - boolean parse — truthy-string 모호성 없이(
"false"가 true 되지 않게) - config schema version 호환 (
CONFIG_SCHEMA_VERSION) - API contract version 호환 (
API_CONTRACT_VERSION) - provider가 둘 다 노출하면 release/build ID coherence
- unknown-key 정책: default strict, schema가 명시적 passthrough일 때만 additive 허용
compat 실패 시 migration/version bump 정책은 raw/branch-notes/feature-frontend-contract-compatibility-governance (FE-OC-023) 위임.
5. boot 실패 safe-output (redaction)
Trace: D6 (hub §6.4). normalized error kind 어휘와 raw body/stack UI 유출 catalog는 raw/branch-notes/feature-frontend-error-classification-boundary-contract (
FE-OC-008) 위임.
- UNSUPPORTED_IMPL_DECISION:
supportReference생성 방식(무작위 correlation id vsreleaseId+timestamp) 미규정 — hub는 field만 나열 → 무작위 opaque id 선택. trade-off: deploy timing 유출 방지하나, 트리아지용으로 telemetry event와 매핑되어야 함(FE-OC-014소유).
boot error shell 노출 허용 field(allowlist, hub §6.4):
error.kind
error.code
buildId
configSchemaVersion
releaseId (if present)
supportReference
화면 금지: endpoint, query, header, raw config object, stack (hub §6.4).
6. boot config 검증 시간 예산 (FE-NFR-006) + FE-GATE-004 소유 분할
Trace: D8 (hub §14.2
FE-NFR-006— deterministic mocked fetch, ≤ 500ms excluding network delay; hub §15.1FE-GATE-004pass condition). invalid fixture 의 나머지 절반(content-type/JSON/envelope/payload)은 raw/branch-notes/feature-runtime-schema-validation-contract (FE-OC-007) 소유 — 해당 노트도 timing fixture 소유를 본 branch 로 귀속시키므로 양방향 일치.
- UNSUPPORTED_IMPL_DECISION: 측정 시작·종료 지점을 hub 가 규정하지 않음("excluding network delay" 만 명시) → 시작 = config 원문(text/object)이 validator 에 전달되는 시점, 종료 = normalized config 반환 또는
BOOT_CONFIG_FAILURE확정 시점으로 고정. trade-off: JSON parse 비용이 예산 안에 포함되어 보수적으로 측정되지만, transport 구현(fetch·캐시·mock)에 무관한 재현 가능 구간이 된다.- UNSUPPORTED_IMPL_DECISION: 회차·통계(단일 실행 vs 다회 중앙값)를 hub 가 미규정 → 동일 fixture 5회 실행의 중앙값을 판정값으로 쓰고 최댓값도 report 에 함께 기록. trade-off: CI 노이즈로 인한 flake 를 줄이지만 tail latency 를 판정에서 제외하므로, 최댓값이 예산의 2배를 넘으면 report 를 근거로 재검토한다.
측정 대상(무엇을 재는가). FE-NFR-006 은 검증 구간만 잰다. 포함: required-key 검사, URL protocol allowlist, int range, boolean strict parse, config/API version 호환 비교, release/build ID coherence, unknown-key strict 판정(§4 8항 전부). 제외: GET {VITE_RUNTIME_CONFIG_URL}·GET {RELEASE_MANIFEST_URL} 의 network 대기, mock 이 주입한 인위적 지연, 검증 이후의 adapter 조립·mount(그 구간은 FE-OC-002 소유이며 본 예산의 대상이 아님).
fixture 가 network delay 를 배제하는 방법. transport 를 deterministic mock 으로 대체하고(hub §14.2 context), config 본문을 이미 메모리에 있는 값으로 validator 에 직접 전달한다. 즉 fixture 는 fetch 를 거치지 않거나, 지연을 주입한 mock 을 쓰더라도 타이머를 fetch resolve 이후에 시작한다. 따라서 mock 지연을 늘려도 측정값이 변하지 않아야 하며, 이 불변식 자체를 fixture 의 self-check 로 둔다(지연 0ms 와 지연 200ms 두 실행의 측정값 차이가 노이즈 범위 내).
valid-config fixture 형태. §1 registry 의 runtime key 10개를 모두 채운 valid config 1건(= 실제 boot 가 받는 최대 폭). 판정: 중앙값 ≤ 500ms.
FE-GATE-004@1 소유 분할 (hub §15.1 의 Covered FE-OC 가 다수라 fixture 소유를 명시해야 중복·누락이 없다 — 어느 계약이 묶여 있는지는 hub §15.1 소유):
FE-GATE-004 구성요소 |
소유 |
|---|---|
| config invalid matrix (required key 부재·protocol 위반·range 위반·boolean 모호·unknown key·version 비호환) | 본 branch (FE-OC-004) |
valid-config timing fixture + timing report (FE-NFR-006) |
본 branch (FE-OC-004) |
| content-type / JSON / envelope / payload invalid matrix | FE-OC-007 |
| 각 invalid 입력의 기대 error kind 어휘 | FE-OC-008 |
| version 비호환 시 migration 판정 | FE-OC-023 |
gate 는 두 소유자의 fixture 가 모두 있어야 PASS 하므로, 어느 한쪽만 준비된 상태에서 FE-GATE-004 를 PASS 로 올리지 않는다.
엣지·실패·의존
- 실패·엣지 경로:
- config fetch non-2xx / JSON parse 실패 / schema 비호환 →
BOOT_CONFIG_FAILURE, product route mount 중단, auto refetch 최대 1회 (hub §6.3·§16.1). - config/API/release version mismatch →
DEPLOY_MISMATCH, controlled recovery UI, reload loop 금지 (hub §6.3). - invalid value(timeout/retry 범위 밖, boolean truthy-string, required key 부재) → boot fail (hub §5.4).
- URL protocol 위반(prod에서 non-https) → boot fail (hub §6.4).
TELEMETRY_ENABLED=true인데TELEMETRY_ENDPOINT부재 → telemetry degrade(boot fail 아님, hub §5.4).- telemetry adapter 생성 실패 → console-safe fallback, boot 계속 (hub §4.5).
- secret-name key가 env에 존재 → registry 거부(build/runtime), boot·build fail (hub §6.1).
- config fetch non-2xx / JSON parse 실패 / schema 비호환 →
- 다른 계약 의존:
- raw/branch-notes/feature-frontend-project-bootstrap-toolchain-contract (
FE-OC-003) —import.meta.env·VITE_prefix 노출과 build identity 주입. 이 계약(checkJs·Vite build)이 바뀌면 build-time config 접근 방식 영향. - raw/branch-notes/feature-frontend-clean-architecture-layering-contract (
FE-OC-002) — composition root(bootstrap) 소유. boot 2~4단계는 이 composition root 안의 단계로 slot in. - raw/branch-notes/feature-runtime-schema-validation-contract (
FE-OC-007) — config 검증에 쓰는 Zod schema 메커니즘 consume.FE-GATE-004협업: 본 branch 가 config invalid matrix + valid-config timing fixture(FE-NFR-006)를, 그쪽이 content-type/JSON/envelope/payload invalid matrix 를 제공(impl §6 분할표). - raw/branch-notes/feature-frontend-browser-security-boundary-contract (
FE-OC-019) — D3 의 secret 차단은 key 이름 기반 정적 거부까지만 담당하고, 번들 scan·로그/telemetry 유출 등 실제 노출 경로 차단은 그쪽 소유. 두 계약이 함께 있어야 "secret 이 브라우저에 안 간다"가 성립한다. - raw/branch-notes/feature-frontend-error-classification-boundary-contract (
FE-OC-008) —BOOT_CONFIG_FAILURE/DEPLOY_MISMATCHnormalized kind consume. - raw/branch-notes/feature-frontend-release-cache-rollback-contract (
FE-OC-016/FE-OC-017) — release manifest 정합성·DEPLOY_MISMATCHrecovery·cache header. 본 branch는 검증된 config를 provide, recovery는 그쪽 소유. - raw/branch-notes/feature-api-client-response-envelope-contract (
FE-OC-006) — 검증된API_BASE_URL/REQUEST_TIMEOUT_MS/MAX_RETRY_ATTEMPTS를 consume(하류 소비자). - raw/branch-notes/feature-frontend-operational-runbook-contract (
FE-OC-025) — boot config failure containment/escalation runbook(FE-RB-001, hub §16.1)의 technical escalation.
- raw/branch-notes/feature-frontend-project-bootstrap-toolchain-contract (
검증해야 할 주장
| Claim | Why uncertain | How to verify | Status |
|---|---|---|---|
| build/runtime/secret 분류가 실제로 강제됨(secret-name key가 양쪽 registry에서 거부) | 코드·정적 가드 미존재, 규칙 문서만 있음 | config schema test + secret-name 거부 negative fixture (FE-OC-004 minimum evidence) |
needs-confirmation |
boot invalid-config matrix의 각 invalid 입력이 기대 boot 결과(BOOT_CONFIG_FAILURE/DEPLOY_MISMATCH/boot fail)로 매핑 |
다양한 실패 조합의 실제 boot 분기 미검증 | boot invalid-config matrix 테스트(§20 Measurable completion) | needs-confirmation |
runtime config가 no-store로 fetch되고 React mount 이전에 검증됨(실패 시 product route mount 안 됨) |
조립 순서·no-store가 코드로 보장되는지 미검증 | boot ordering 통합 테스트(mount 이전 fetch·실패 시 route 미mount 확인) | needs-confirmation |
| boot 실패 화면이 safe-field만 노출(endpoint·raw config·stack 미유출) | redaction 강제 여부 미검증 | boot error shell redaction negative fixture | needs-confirmation |
한 artifact를 여러 env에 재사용하지 않음(FE-D013) |
배포 프로세스 속성 — unit test로 완전 증명 불가 | 배포 파이프라인 assertion + env별 artifact hash 대조(문서화된 deploy check) | needs-confirmation |
non-VITE_ build 변수가 client 번들로 유출되지 않음 |
번들 정적 치환 경계는 실제 빌드로만 확인 | build 후 bundle scan (FE-OC-019 browser-security와 교차) |
needs-confirmation |
valid config 검증이 FE-NFR-006 예산(≤ 500ms, mocked network delay 제외) 안에 들어옴 |
코드·검증 로직 미존재. 8항 검증 + schema 라이브러리(FE-OC-007)의 deep clone/parse 비용이 미측정이라 500ms 가 여유인지 빠듯한지 알 수 없음 |
runtime key 10개를 채운 valid-config timing fixture 5회 실행의 중앙값 측정(impl §6) → FE-GATE-004 timing report |
needs-confirmation |
| timing fixture 의 측정값이 mocked network delay 에 영향받지 않음(예산이 검증 구간만 잰다) | 측정 시작점이 fetch resolve 이후인지 코드로 강제되는지 미검증 | 동일 fixture 를 mock 지연 0ms / 200ms 로 각각 실행해 측정값 차이가 노이즈 범위 내인지 확인(impl §6 self-check) | needs-confirmation |
관심사 커버리지 (coverage-auditor 자동 생성 — 있을 때)
/coverage가 채우는 생성물이며 손으로 유지하지 않는다.
| 관심사 | 상태 | owner | 심각도 | 근거 |
|---|---|---|---|---|
TODO — /coverage 실행 전 |
missing | (없음) | 미평가 | TODO |
마주친 문제
없음 — scaffolding 단계
묶음 (이 branch에서 파생된 자료)
가져온 프로젝트 계약
| Ref | Owner | 요약 | Branch 적용 |
|---|---|---|---|
FE-GATE-004@1 |
raw/branch-notes/feature-runtime-schema-validation-contract | invalid fixture 가 예상 kind 로 거부되지 않으면 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-003@1 |
raw/branch-notes/feature-frontend-project-bootstrap-toolchain-contract | package manager, engine, lockfile, source language, checkJs command를 한 곳에서 MUST 고정 | import 참조로 적용 |
FE-OC-007@1 |
raw/branch-notes/feature-runtime-schema-validation-contract | JSON envelope와 payload는 boundary에서 runtime schema를 MUST 통과 | import 참조로 적용 |
FE-OC-008@1 |
raw/branch-notes/feature-frontend-error-classification-boundary-contract | 모든 failure는 stable frontend error kind로 MUST 정규화하고 raw body·stack을 UI에 노출하면 안 됨 | 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-014@1 |
raw/branch-notes/feature-frontend-observability-logging-trace-contract | telemetry는 best-effort이며 render·API success를 차단하면 안 되고 PII·token을 전송하면 안 됨 | import 참조로 적용 |
FE-OC-016@1 |
raw/branch-notes/feature-frontend-release-cache-rollback-contract | HTML, asset, runtime config, release manifest cache policy를 MUST 구분 | import 참조로 적용 |
FE-OC-019@1 |
raw/branch-notes/feature-frontend-browser-security-boundary-contract | browser bundle에 secret을 넣지 않고 untrusted HTML injection을 기본 금지 | 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 참조로 적용 |
FE-OC-025@1 |
raw/branch-notes/feature-frontend-operational-runbook-contract | boot, chunk mismatch, API degradation, telemetry failure, rollback runbook을 MUST 유지 | import 참조로 적용 |
Sub-branches (세부 작업)
없음 — scaffolding 단계
오류 기록 (이 branch 작업 중 발생)
없음 — scaffolding 단계
면접 준비 (이 작업에서 나올 수 있는 면접 질문)
없음 — scaffolding 단계
강의 (이 작업을 위해 학습한 강의)
없음 — scaffolding 단계
job-posting tie-ins (이 작업에서 파생된 글감)
없음 — scaffolding 단계
관련 일일 노트
없음 — scaffolding 단계
완료 후 정리
- PR 링크:
- 리뷰 메모:
- 머지 결과 / 배포 환경:
- wiki 추출 대상 (verified만,
wiki/projects/로만 추출):actually-implemented항목:locally-verified항목:prod-verified항목:
- 추출하지 않을 항목 (planned / documented-only / abandoned):