Skip to content

[WEB-USER,BE,COMMON][UPDATE]: 홈·상품상세 초기 진입 성능 개선 및 테스트 인프라·admin API 키 인증 반영 - #172

Merged
IceMilk1996 merged 6 commits into
mainfrom
staging
Sep 1, 2026
Merged

[WEB-USER,BE,COMMON][UPDATE]: 홈·상품상세 초기 진입 성능 개선 및 테스트 인프라·admin API 키 인증 반영#172
IceMilk1996 merged 6 commits into
mainfrom
staging

Conversation

@IceMilk1996

Copy link
Copy Markdown
Contributor

📋 요약

web-user 초기 진입 성능 개선 두 건과, 그동안 staging에만 올라가 있던 테스트 인프라·백엔드 변경을 함께 main으로 올립니다. 홈 진입 시 상품 목록이 두 번 조회되던 문제와, 상품 상세 진입 시 예약 바텀시트 코드까지 같은 청크로 끌려오던 문제를 각각 해결했습니다.

✨ 주요 변경사항

  • [WEB-USER] 홈 진입 시 상품 목록 중복 조회 제거 — 지역 정보를 storage에서 먼저 확정한 뒤 목록을 조회하도록 순서를 정리해, 지역 확정 전/후로 두 번 나가던 요청을 한 번으로 줄임
  • [WEB-USER] 예약 바텀시트를 상품 상세 진입 경로에서 분리 — 바텀시트를 동적 청크로 떼어내 상세 페이지 초기 번들에서 제외
  • [WEB-USER] Storybook 컴포넌트 인터랙션 테스트 활성화 및 그 과정에서 발견된 Calendar SVG 렌더링 버그 수정
  • [WEB-USER] 유닛테스트 추가(jwt/orderForm-validator/product-price) 및 vitest 설정 도입
  • [BE] 관리자 전용 API 키 인증 추가 — 자동화/AI가 사람 로그인 없이 admin API를 호출할 수 있도록 함 (Prisma 마이그레이션 포함)
  • [BE] 프로덕션 빌드를 막던 통합테스트 헬퍼 타입 에러 수정, 알림 mock 불완전성 수정
  • [COMMON] 프론트엔드 테스트 CI(test-web.yml) 신설, 커밋·배포 슬래시 명령어 추가

🧪 테스트 계획

  • 홈 진입 시 상품 목록 요청이 1회만 나가는지 (네트워크 탭)
  • 지역 미설정 상태 / 지역 저장된 상태 양쪽에서 홈 목록이 정상 노출되는지
  • 상품 상세 진입 후 예약 바텀시트가 정상적으로 열리고 주문 흐름이 끊기지 않는지
  • 웹뷰(앱) 환경에서 지역 정보 전달이 기존과 동일하게 동작하는지
  • 캘린더 날짜 선택 UI가 정상 렌더링되는지

📎 참고 사항

  • 백엔드 변경(ca6db6d1, 4eecc688)은 이미 backend/production-v0.0.14 태그로 운영 배포가 완료된 커밋입니다. 이 PR은 해당 커밋을 main 히스토리에 반영하는 것이며, 이번 머지 후 추가로 붙이는 production 태그는 web-user 하나입니다.
  • admin API 키 인증은 Prisma 마이그레이션(20260901120000_add_admin_api_key)을 포함하지만, 위와 같이 운영 DB에는 이미 적용된 상태입니다.
  • staging 확인 완료: web-user/staging-v0.0.230, backend/staging-v0.0.173 모두 배포 성공, https://staging.picakes.com/ 200, https://api-staging.picakes.com/health 200.

IceMilk1996 and others added 6 commits September 1, 2026 13:04
지역 스토어에 persist가 없어 첫 렌더의 selectedRegion은 항상 null이다.
Header가 localStorage에서 지역을 복원한 뒤에야 값이 채워지므로, regions가
undefined → 값으로 바뀌며 queryKey가 교체되어 같은 목록을 두 번 조회했다.

지역이 확정될 때까지 조회를 보류한다. 저장된 지역 유무는 localStorage로만 알 수
있으므로 첫 렌더에 1회 판정하고 이후 고정한다.

- 재방문(지역 저장됨): /products 4건 → 2건
- 신규 사용자: 첫 화면 지연을 피하려 즉시 조회하므로 4건 유지 (기존과 동일)
- 무한 대기 방지: 지역 목록 API 실패 시, 그리고 복원이 3초 내 끝나지 않으면
  지역 필터 없이 조회
- 확정 상태는 되돌리지 않음 — selectedRegion이 다시 null이 되어도 이미 보고 있던
  목록이 스켈레톤으로 회귀하지 않도록 래치 처리

지역 저장 키는 Header/webview.bridge에 흩어져 있던 것을 region-storage.util로 모았다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ScM4roFnvWcR1hmDuw7Zi
시트를 isOpen과 무관하게 항상 마운트하면 상품 상세 진입만으로 청크가 즉시 내려와
(프로덕션 gzip 24KB) 이미지·LCP와 대역폭을 나눠 쓴다.

- 마운트는 열릴 때만 하고, 청크는 idle 시점과 버튼 hover/touch 시점에 preload
- requestIdleCallback 미지원 환경(iOS Safari 16.3 이하)은 setTimeout으로 대체
- 청크 도착 전에는 아무것도 그리지 않아 기존 UI 변화 없음

제출 중에는 시트를 닫지 않도록 막았다. 조건부 마운트라 제출 중 닫히면 컴포넌트가
언마운트되어 useCreateOrder의 onSuccess(완료 페이지 이동)가 실행되지 않고,
서버에는 주문이 생성된 채 화면만 상품 상세에 남는다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ScM4roFnvWcR1hmDuw7Zi
Google OTP 없이는 admin API를 호출할 수 없어 매일 자동 리포트 같은 자동화가 불가능했다.
x-admin-api-key 헤더를 admin JWT와 체이닝되는 별도 passport 전략으로 처리해, 발급된 키는
기존 admin 컨트롤러 전체에 그대로 통한다. 키 자체의 발급/폐기는 always 사람 로그인(JWT)만
가능하도록 별도 차단해 키가 스스로를 재발급하는 순환 상승을 막았다.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Au6qVAM3RXf7rAakifYDcL
프로덕션 배포(backend/production-v0.0.13) 중 tsc가 test/integration/db.ts·factories.ts에서
에러 4건을 내며 빌드 실패 → 자동 롤백됨. 이번 작업(admin API 키)과는 무관한 기존 버그였지만
빌드를 막고 있어 함께 수정.

- db.ts: connectTestDb()가 모듈 스코프 let 변수를 await 이후 그대로 반환해 좁혀진 타입이
  풀리는 문제 — await 이전에 얻은 지역 변수를 반환하도록 변경.
- factories.ts: overrides 타입을 Partial<Parameters<...create>[0]["data"]>로 유도하면
  Prisma의 XOR<CreateInput, UncheckedCreateInput> 유니온이 Partial로 무너져 관계형 필드와
  스칼라 FK 필드가 동시에 존재하는 모양이 됨 — 실제 팩토리가 쓰는 스칼라 FK 형태에 맞춰
  Prisma.*UncheckedCreateInput을 직접 타입으로 지정.

로컬 통합테스트(9개)·e2e(3개) 모두 통과 확인.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Au6qVAM3RXf7rAakifYDcL
커밋 접두사, 태그 버전, 배포 절차를 매번 사람이 기억해서 맞추고 있었다.
skill에 규칙은 있지만 실행 흐름은 매번 손으로 이어붙여야 했다.

- /commit — diff를 성격별로 나눠 커밋, [WEB-USER] 등 접두사 자동 판단
- /push-staging — 브랜치 푸시 + staging 태그 마지막 버전 +1 + 배포 확인
- /push-production — PR 생성·머지 + production 태그 +1 + 운영 검증

실제 배포에서 겪은 함정을 절차에 넣었다.

- remote는 upstream 고정. origin에는 push URL이 개인 포크와 ServicePlayground
  두 개가 걸려 있어 포크에도 함께 푸시된다 (picake-deploy-release skill은
  origin으로 안내하고 있어 그대로 따르면 안 된다).
- 태그는 한 번에 하나씩 푸시. 묶어서 푸시하면 태그는 생성되는데 Actions가
  트리거되지 않아, 푸시 후 run 생성 여부를 확인하고 없으면 삭제 후 재푸시한다.
- production 태그는 main의 머지 커밋에 붙인다. 기존 릴리스가 모두 이 방식이다.
- 린트는 --max-warnings=0이라 기존 경고만으로도 실패하므로 차단 조건으로 쓰지 않고
  기존 대비 증가분만 본다.
- index.lock은 바로 지우지 않고 실행 중인 git이 없는지 확인한 뒤 stale일 때만 제거한다.

/push-production만 머지 직전 1회 확인을 받는다. 실제 사용자에게 나가고 되돌리기
어렵기 때문이다. 브랜치 보호는 --admin으로 우회하지 않고 막히면 보고 후 멈춘다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ScM4roFnvWcR1hmDuw7Zi
@IceMilk1996 IceMilk1996 self-assigned this Sep 1, 2026
Comment thread apps/backend/src/modules/admin-api-key/services/admin-api-key.service.ts Dismissed
@IceMilk1996
IceMilk1996 merged commit ed77053 into main Sep 1, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants