Skip to content

www 루트 주소가 app으로 넘어가지 않던 문제에서 옛 주소 이동 검사 두 층까지 (2026-09-15)

  • 기간: 2026-09-15 10:15 ~ 02:05 KST (세션 1개 12f86128, 오너 지시 "#1609 해결좀" → "일단 관리자 권한으로 빠르게 staging, main 머지해" → "하고 제품 배포까지 쭉")
  • 랜딩: PR #1611(Phase 1 04e68073 · Phase 2 939aa5ea · QA1 핀 93cb5f6d → staging 3f434ac0) · PR #1613(main #1604 → staging 동기화, QA1 핀 충돌 해결 91e0db30 → staging fb56055a) · PR #1614 [Release v0.19.1] → main e94335aa — 마이그레이션·엣지 없음, Vercel 프런트 배포 성공(1-Production Deploy 34871745442, 태그 v0.19.1 = e94335aa)
  • 설계서: 없음(수리 건) — 분석·Phase 계획·예상 효과는 #1609 댓글
  • 정본: 앱 vercel.json 옛 주소 규칙(/:path(.*)<publicOrigin>/:path) · scripts/check-deployment-pipeline.mjs LEGACY_REDIRECT_SOURCE · deployment-targets.json production.legacyOrigins
  • 도구: 원인 재현에 @vercel/routing-utils 6.5.0 sourceToRegex/getTransformedRoutes(세션 scratchpad, 레포 밖)
  • 게이트: npm run check:deployment(형태) · QA1 suite/tests/react/barbelicWebMetadata.test.mjs(형태) · deploy-steps.yml 프런트 잡 "Legacy origins must redirect to the public origin"(실제 응답, Production만) · 로컬 precheck static·단위 통과(작업 93cb5f6d 2107+1777, 동기화 91e0db30 2107+1778, 실패 0). DB·pgTAP·e2e 미접촉
  • 버그리포트: bug-report/bug-146-20260915.md — 이 건의 정본. 아래는 그 리포트를 잇는 짧은 기록
  • 계약: 없음(기존 #1474 옛 주소 계약의 규칙 형태를 고정)

Phase 현황

Phase내용상태
Phase 1vercel.json 규칙 교체 + check:deployment가 루트 포함 형태만 통과✅ PR #1611 (04e68073)
Phase 2배포 프런트 잡에 옛 주소 루트·/home 308 실제 확인 단계✅ PR #1611 (939aa5ea)
병합·배포관리자 병합 staging(3f434ac0·fb56055a) → main(e94335aa) → Production1-Production Deploy 34871745442 성공, 태그 v0.19.1

1. 배경

#1474로 v0.19.0(2026-09-15 01:05 KST)부터 앱은 app.barbelic.com, 옛 주소 www.barbelic.com은 경로를 유지한 채 308로 보내기로 했다(오너 결정 "한 번에 옮김"). 배포 직후 승격 세션의 실측에서 루트 www.barbelic.com/만 앱을 그대로 내주는 것이 드러나 #1609로 등록됐다.

2. 문제 제기

/:path* 규칙이 빈 경로 /에 맞지 않는다

Vercel이 규칙을 정규식으로 바꿀 때 /:path*는 경로 조각을 하나 이상 요구하는 형태가 된다. 라이브러리로 재현: / 불일치, /home 일치. 상세는 BUG-146 §2.

검사가 결함 있는 형태를 정답으로 요구했다

정적 검사와 QA1 테스트가 source === "/:path*"를 단언했고, 배포 뒤 검사는 정규 주소만 봤다. staging에는 옛 주소가 없어 Production 배포가 첫 실행이었다.

3. 해결 방안

원칙 (오너 결정, 2026-09-15)

  • D1 "일단 관리자 권한으로 빠르게 staging, main 머지해" · "하고 제품 배포까지 쭉" — release 큐·GitHub Full CI 완주 없이 관리자 병합으로 Production까지(v0.19.0 #1606·#1608과 같은 방식). 채택.

접근

루트 전용 규칙 추가(기각: 규칙 분산, 함정 잔존) / /:path(.*)로 교체 + 검사 두 층(채택) / 검사만 추가(기각: 결함 잔존). 비교표는 BUG-146 §3.

4. 적용한 내용

Phase 1 — 규칙 교체와 정적 검사 (#1611 04e68073)

vercel.json 옛 주소 규칙 source: "/:path(.*)", destination: "https://app.barbelic.com/:path". check-deployment-pipeline.mjs는 옛 주소마다 이 형태만 통과시키고 /:path*는 "루트가 이동되지 않는다" 메시지로 실패(이유 주석).

Phase 2 — 배포 뒤 실제 이동 확인 (#1611 939aa5ea)

deploy-steps.yml 프런트 잡 "The public origin must serve this deployment" 뒤에 "Legacy origins must redirect to the public origin": legacyOrigins마다 /·/homepublicOrigin으로 308 이동하는지 curl 확인, 없는 환경은 건너뜀.

QA1 핀

QA1 bcc7e87b(테스트가 새 형태 요구) → main #1604 핀과 합친 af159b3f로 고정(PR #1613).

주요 결정과 그 근거

  • 규칙을 교체하고 검사가 형태를 고정: 다음에 옛 주소를 추가하는 사람이 같은 함정에 빠지지 않게(원칙 4 구조적 원인 해결).
  • 배포 검사를 정규 주소 검사 뒤에 배치: #1607의 반영 지연 오판을 키우지 않기 위해.
  • QA1 main에 합치지 않음: 앱 핀이 다른 세션 브랜치 위라 QA1 main이 조상이 아니어서, 합치면 남의 브랜치 커밋이 끌려 들어간다.

작업 중 드러난 것

  • 첫 precheck가 QA1 테스트 1건으로 빨간불 — 테스트가 결함 있는 형태를 단언하고 있었다(사전 검증 누락 아님, 테스트 자체의 가정 오류).
  • main이 작업 중 #1604(5d3d6ac1, qa1.lock.json 변경)로 앞서가 릴리스 PR이 충돌 → main을 staging에 동기화하는 PR(#1613)로 해결. 관리자 병합 경로에서는 큐가 이 충돌을 대신 잡아 주지 않는다.
  • PR 생성으로 자동 실행된 GitHub Full CI는 scope 잡("Promotion PR must be open and ready for review")에서 종료 — head가 release/*가 아닌 승격 PR을 정책 검사가 거부. 검증은 돌지 않았다.
  • check:deployment를 단독으로 돌리면 QA1이 가져오는 probe 파일이 없어 실패(#1591 이후) — npm run check/ci:precheck-local처럼 QA1 준비가 앞서는 진입점을 쓴다.
  • release/v0.19.1을 main(v0.19.0)에서 만들었지만 큐를 거치지 않아 비어 있다(= 1755f24a, ruleset이 삭제 금지). 다음 패치는 v0.19.2로 main에서 새로.

5. 적용 결과

항목결과
https://www.barbelic.com/200(앱) → 308 https://app.barbelic.com/(배포 뒤 실측, 쿼리 보존)
https://www.barbelic.com/home308 app.barbelic.com/home → 동일
옛 주소 규칙 형태 검사없음(결함 형태를 요구) → check:deployment·QA1 테스트가 /:path(.*)만 통과
배포 뒤 옛 주소 이동 확인없음 → Production 프런트 잡 단계(run 34871745442 프런트 잡에서 첫 실행에 통과)
staging 배포 34871126235 (3f434ac0)database·functions·frontend·smoke 성공
Production 배포 34871745442 (e94335aa)database·functions·frontend·smoke·release tag 성공(2026-09-15 02:01 KST). browser journeys는 조건부 skip(v0.19.0과 동일)
미검증www.barbelic.com/index.html의 2단 이동(cleanUrls → / → app) 실측 안 함

6. 이번 개선으로 향상된 것

옛 주소 루트 진입이 정규 주소로 간다

북마크·설치 아이콘·검색 결과로 www.barbelic.com/에 들어온 사용자가 app.barbelic.com/에서 앱을 쓴다 — #1474의 "옛 출처에 기록이 남지 않게" 전제가 루트 진입에서도 성립.

구조적으로 남는 것

옛 주소 → 정규 주소 계약을 형태(정적 검사·QA1)와 실제 응답(Production 배포 프런트 잡) 두 층이 지킨다. 옛 주소 추가는 legacyOrigins 한 줄로 세 검사가 자동으로 따라온다.

7. 후속 — www는 랜딩의 정규 주소 (2026-09-15, #1619)

오너 결정(같은 날 02:2x KST): www.barbelic.com = 랜딩 정규 주소(Vercel barbelic-landing), barbelic.com → www 308, 앱 = app.barbelic.com(www.app.barbelic.com 불필요). 이 결정으로 §5의 "www → app 308" 행은 더 이상 기대 동작이 아니다.

Phase내용상태
Phase 1legacyOrigins: [](deployment-targets.json·app-config.js), vercel.json www 규칙 제거, /landinghttps://www.barbelic.com/ 직행, QA1 deploymentTargets.test.mjs 완화(ca0bfa4b)PR #1620 → staging 4a899466 → #1612의 PR #1622로 main 157bf12b · 1-Production Deploy 34875556141 attempt 2 성공(frontend "no legacy origins" 건너뜀·smoke), 태그 v0.19.2. attempt 1 frontend 실패는 #1607 반영 지연 오판 → 실패 잡 재실행
Phase 2Supabase Production Auth Site URL → https://app.barbelic.com(관리 API)✅ 재조회 확인
Phase 3랜딩 canonical → https://www.barbelic.com/✅ 랜딩 PR #4 8af96022, 배포 뒤 실측
Phase 4이 문서·BUG-146 갱신✅ 이 절

작업 중 드러난 것: 결정 직후 #1612의 Production 배포 34874848468이 §4의 배포 검사에서 실패(www 200) — 검사는 설계대로 동작했고 원인은 결정 변경. 도메인 정본 docs/platform/domains.md(PR #84, 미병합)의 www 역할 서술은 이 결정으로 구식이며 그 PR 담당이 고친다.

남은 것

  • docs/platform/domains.md(#1474 문서 PR #84, 미병합)에 규칙 형태(/:path(.*)) 설명 반영 — 그 PR 담당.
  • #1607 배포 뒤 공개 주소 검사 반영 지연 — 별도 이슈.
  • release/v0.19.1 빈 브랜치 정리(ruleset 삭제 금지) — 오너 손 또는 다음 릴리스 때 판단.