Deployment Pipeline
2026-09-10 #1491 승인 정책 (v0.17.8 대상): 일반 작업→release는 precheck 후 Merge Check만 수행하고, 최종 release→staging에서 full을 실행한다. staging→main은 동일 tree의 유효한 full 기록과 현재 staging 배포·smoke를 확인한다. 진단용 dry-run·부분 재현은 유지한다. 앱 main
6afe58ec설치를 확인했다. 정상 큐의 새 실행·운영 배포 결과는 적용 기록에서 확인하며 아래 과거 실행 이력과 구분한다.
#1463 저장소 분리 이후 적용: 아래 앱 release·DB·데이터 보호 규칙은 앱 저장소에 적용한다. 과거 docs/admin 결합 빌드·같은 SHA 배포·앱 main 문서 직행·문서 문자열 검사 설명은 이관 전 기록이다. 모든 문서와 작업 기록은 dekerd/Barbelic-docs에서 관리하며, 현행 저장소 경계와 문서·관리자 독립 운영이 그 부분을 대체한다. 세션 제목은 현재 Phase/전체 Phase 규칙을 따른다. 코드 준비·원격 활성화·실제 배포 성공은 독립 운영 문서의 기록으로 구분한다.
2026-09-09 개정 (이슈 #1456·#1457·#1458, 오너 결정) — 명령·워크플로 이름이 바뀌었다. 작업 PR 통합 요청
npm run merge:request(구 landing:request), PR 전 사전 검증npm run ci:precheck-local(최신 release 합치기 → verify → 서버 변경 시 DB 단계, 브라우저 없음), 전체 검증npm run ci:full-local(릴리스 큐 runner 안에서만; 세션은--only <단계>재현만). 워크플로 표시 이름:3-Release Merge Request(release-merge-request.yml) ·GitHub Full CI(policy-contract.yml) ·1-Production Deploy/2-Staging Deploy(production-deploy.yml·staging-deploy.yml, 단계 정의는 deploy-steps.yml) ·Production smoke (manual)·Social login daily check·Daily data backup.landing:lock·db:preflight스크립트는 폐기됐다(GitHub concurrency 가 잠금, DB 검사는 사전 검증과 큐가 한다). 아래 본문의 옛 이름은 그 개정 전 기록이다. 2026-09-15 개정(#1659, 오너 지시) — 승격 CI·배포 실행의 이름은[vX.Y.Z] Release -> Stage Merge·[vX.Y.Z] Staging Deploy·[vX.Y.Z] Stage -> Main Merge·[vX.Y.Z] Production Deploy4종으로 고정하며 버전은 저장소 변수RELEASE_VERSION에서 읽는다(실행 이름).
2026-09-15 개정(오너 지시, #1659) — v0.19.3 출시부터 QA1은 완전히 퇴역한다(워크플로 어디서도 자동 실행되지 않음). 승격 CI는 두 레인뿐이다: release→staging = precheck 레인(
static-checks+migration-smoke: 마이그레이션 전체 재적용·schema.sql 대조), staging→main = QA2 레인(qa2-product-contracts)뿐. 동일 tree 성공 기록 재사용, QA1 단위·브라우저·viewport·e2e-evidence 잡, 배포 뒤 QA1 CRUD smoke 잡(smoke (staging/production)),prod-smoke.yml·social-login-daily-check.yml, 앱의qa1.lock.json·scripts/qa1.mjs·npm run test·smoke:*·QA1 npm 자동 훅은 모두 제거됐다. 배포 단계는 DB → Edge → 프론트(→ Production은 release-tag)이며, 아래 본문의 smoke·browser-journeys 서술은 그 이전 기록이다.
브랜치·CI·승격의 정본은 **릴리스 프로세스**다. 확정 경로는 작업 → release → staging → main(Production)이며, release→staging은 최신 base의 최종 후보에서 GitHub full CI를 실행하고 staging→main은 유효한 동일 tree 성공 기록과 현재 staging 배포·smoke 증거를 확인한다. 이 문서는 새 브랜치 매핑과 DB → Edge Functions → frontend → smoke의 기술 순서를 설명한다.
DB 계약을 먼저 배포하고 검증한 뒤, 그 계약을 사용하는 Edge Functions와 프론트엔드를 배포한다. 브랜치 경로를 바꾸어도 이 순서는 유지한다.
v0.18.0 worker 전환 준비 — R05 #1544
R05 후보에 구현·로컬 리허설된 순서이며 실제 release/staging 반영은 R05 장부에서 확인한다. 기존 release-v0171-projection-rollout.mjs는 검증된 migration suffix가 있을 때 dry-run 이후, SQL 적용 전에 quiesce-stats-worker.mjs로 기존 worker가 쓰던 claim/compute advisory key를 한 psql 연결에서 확보한다. 진행 중 compute가 끝나고 live computed 결과가 정상 publish될 때까지 기다린 뒤 DDL을 시작한다. cron 설정과 pending/claimed/failed 작업·사용자 사실은 바꾸지 않는다.
준비는70초를 넘으면 적용 전에 실패하고, 성공·실패 모두 연결을 닫아 기존 worker를 재개한다. 준비 연결 유실은 실행 중 migration CLI의 AbortSignal로 전달한다. 이미 적용된 suffix면 정지하지 않으며 worker가 아직 없는 이전 스키마도 구분한다. 배포 DB 단계는 psql 가용성을 확인한 뒤 기존 DB→Edge→웹→smoke 순서를 유지한다. 새 배포 큐나 전역 승격 락을 추가하지 않는다.
실제188→219 전체31개 이관에서4년 입력의 최대 파일346ms/잠금0, 실제 사본359ms/잠금0을 확인했다. 기존60초는 파일별 최대 적용 시간이고 전체31개 wall69,825ms/70,191ms와 별개다. 적용 전 준비70초를 파일 적용·잠금 예산의 완화로 사용하지 않는다. 원래 무보호 잠금 실패와 원본·영수증·중단/재개 비교는 R05 실행 증거에 보존한다.
배포 후 사후 브라우저 자동 실행 중단 — #1564
2026-09-11 사용자가 반복 실패와 GitHub Actions 사용량을 확인한 뒤, 사후 브라우저 검사를 끄고 이후 배포에서도 실행하지 않도록 지시했다. 이후 “hotfix 트랙으로 검사없이 stage, main 머지”를 명시했다. staging #1566과 main #1567에 반영 완료했으며 main 1587cb7aa368294b9390c63f25b139193dd1ceb3에서 두 잡 비활성화를 확인했다. #1564 작업 기록에 기존 로컬 검증과 이번 검사 생략 병합을 구분한다.
- 앱
deploy-steps.yml의browser-journeys와browser-journeys-report는 모두if: $false로 비활성화돼 있다. 이후 Production 배포를 해도 두 잡은 runner를 할당받지 않고 skipped로 남으며 검사·경고 댓글을 실행하지 않는다. - DB → Edge → frontend → 기본 CRUD smoke → Production 태그 순서와 필수 검사 조건은 유지한다. 공용 CASE·Playwright 설정·Full CI의 브라우저 검사도 유지한다.
- 중단은 사후 실패14개를 수리하거나 통과 처리한 것이 아니다. 실제 운영 화면에서만 발생하는 문제의 자동 점검 범위는 줄어든다. 재개는 사용자 지시와 운영 환경에 맞는 검증을 갖춘 별도 변경으로 처리한다.
- 수동
Production smoke (manual)과 소셜 로그인 정기 검사는 이번 자동 실행 중단 범위 밖이며 변경하지 않는다. 현재 요청으로 수동 브라우저 검사를 새로 실행하지 않는다. - 이번 한 건은 사용자가 승인한 hotfix 예외로 기존 관리자 권한·CI 생략 커밋을 사용했다. 원격 CI·Merge Check·추가 로컬 검사·자동 배포는 실행하지 않았으며 보호 규칙도 수정하지 않았다. 워크플로는 main 반영 자체로 다음 실행에 적용된다. 앱 재배포·새 태그 발행이나 미실행 검사의 성공을 주장하지 않는다. 이후 작업의 일반 검증 절차를 바꾸는 예외가 아니다.
v0.17.7 사후 브라우저 점검 분리 — #1485 (이전 운영)
2026-09-09 사용자 지시로 준비해 v0.17.7 Production에 반영한 변경이다. 아래는 #1564 중단 변경이 운영에 반영되기 전의 동작이다. 작업 기록에 커밋과 배포 증거를 구분해 기록한다.
1-Production Deploy와2-Staging Deploy가 공통deploy-steps.yml을 호출한다. 앱 배포 순서는 DB → Edge → frontend → smoke이며, Production의release-tag는 smoke 성공 직후 실행한다. 태그 실패는 여전히 배포 실패다.- Production
browser-journeys는 smoke 뒤 태그와 독립적으로 실행한다. 잡의continue-on-error: true로 사후 점검이 배포 성공을 막지 않으며 실행 상한은 20분에서 40분으로 늘린다. 테스트별 제한·실패 판정과 점검 계정의production-smoke직렬 실행은 유지한다. - 준비·테스트·결과 업로드가 모두 성공해야 마지막 단계가 성공 표식을 출력한다. 별도
browser-journeys-report잡은 smoke 성공 뒤 이 표식이 없으면 실패·준비 오류·시간초과를 #1485에 실행 링크와 커밋을 포함한 댓글, Actions 경고 및 요약으로 남긴다. 알림 잡도 비차단이다. 댓글 전송 자체가 실패하면 Actions 경고·로그에서 확인할 수 있다. - 호출자 두 잡이
contents: write와issues: write를 전달하며, 재사용 워크플로에서는 태그 잡에만 contents 쓰기, 결과 보고 잡에만 issues 쓰기를 준다. Production 브라우저 trace·영상·스크린샷 비활성화와 JSON 결과 목록만 업로드하는 범위는 유지한다. - 태그 또는 배포 성공은 사후 브라우저 점검 통과를 뜻하지 않는다. 점검의 성공 표식과 실패 댓글을 별도로 확인한다. 전체 워크플로는 사후 잡 종료까지 실행 중일 수 있으나 태그 생성은 이를 기다리지 않는다.
- CASE-011의 사전 DB 초안 정리는 추가하지 않았다. 문제 실행의 첫 실패는 해당 테스트 실행 중 새로 저장된 browser localStorage 초안이며, 기존 점검 계정 데이터가 원인이라는 추정은 확인되지 않았다. 기존 테스트가 소유한 데이터의 정리만 유지한다.
잡 의존성과 비차단 실패 처리는 GitHub Actions 워크플로 문법을 따른다.
2026-09-09: #1436에서 새 연결을 설치·활성화했다. 실제 배포 성공 여부는 실행 기록과 구분한다. 새 매핑은 main=Production, staging=staging이다. repository variable DEPLOYMENT_BRANCH_CUTOVER=true가 설정되어 새 Deploy가 활성화됐다. Vercel 앱·docs의 Production=main, custom staging=staging과 docs staging 공개 Supabase 값·BARBELIC_TARGET 및 VERCEL_DOCS_PROJECT_ID 설정을 원격 확인했다. 로컬 docs Production 및 staging 관리자 빌드·산출물 검사는 통과했지만 원격 main 설치·활성화·Linux Deploy 검증은 아직 완료하지 않았다. 실제 완료 상태는 릴리스 프로세스의 체크리스트에 실행 링크·SHA와 함께 기록한다.
환경 분리 이후의 배포 (deploy.yml)
이 절은 전환 코드를 설치하고 활성화 변수를 설정한 뒤의 동작이다. 아래 "Production Deployment"의 수동 명령들은 비상 복구 절차로만 남고, 평시 배포는 전부 .github/workflows/deploy.yml이 한다.
staging= staging.release/vX.Y.Z → staging승격 PR 병합 후 deploy.yml이 staging Supabase (ajqddlglezvxzsawquku)에 마이그레이션·Edge Function을 적용하고 Vercelstaging환경에 배포한다.main= Production. 릴리스 = 검증한staging → mainPR 병합(오너 승인 필수). 머지 푸시가 deploy.yml의 production 레인을 시작한다. GitHub Environmentproduction의 required reviewer(오너)가 설정돼 있으면 Production 잡은 오너의 승인 클릭까지 멈춘다.- 순서는 잡 의존으로 강제된다: database(링크 프리플라이트 → [production] staging-applied 게이트 → dry-run → [production] dry-run 목록 = release diff → db push → remote-schema 게이트) → functions(배포 + 버전 헤더 프로브) → frontend(Vercel CLI prebuilt) → smoke(CRUD roundtrip). DB·함수가 초록이기 전에는 프론트가 나가지 않는다.
- 앱과 docs의
vercel.json에서main·stagingGit 직접 배포를 끄고 DB보다 프론트가 먼저 배포되는 것을 막는다. 앱의 git 통합은 PR 프리뷰에 사용하며, 프리뷰는 Vercel Preview 환경변수로 staging을 본다. - 사람이 Production에
db push --linked·functions deploy를 하지 않는다(오너 결정 D5). staging 조작은 전용 폴더에서만 하고 본체 체크아웃의 링크는 바꾸지 않는다 (environment-separation-runbook.md의 링크 규칙). - 빌드는 자기 배포 대상을 선언한다 (이슈 #1332, 빌드·배포 대상 표). frontend 잡이
BARBELIC_TARGET=<staging|production>으로vercel build를 돌리고, Vite 플러그인(vite.deploymentTarget.mjs)이 대상과VITE_SUPABASE_*가 어긋나면 빌드를 실패시킨다 — staging 값이 빠졌다고 Production 을 바라보게 두지 않는다. 배포 직전scripts/check-build-artifact.mjs가 산출물의 대상 도장(__BARBELIC_DEPLOYMENT__)과 서버 비밀 부재를 확인한다(값은 출력하지 않는다). smoke·DB 비밀번호·프로젝트 ref 가 없으면 해당 잡이 이름을 적고 실패한다(건너뜀·다른 환경 값 대체 없음). - 브랜치 생성 push는 배포를 일으키지 않는다. 수동 실행도 Production은 main, staging은 staging에서만 허용한다. resolve와 DB·Edge·프론트 쓰기 잡에서 대상 브랜치의 최신 SHA를 다시 확인한다. 성공했던 resolve를 재사용하는 실패 잡 재실행도 오래된 SHA이면 중단한다.
- 작업→release의 release별 슬롯은 최신 후보의 Merge Check·병합까지만 보유한다. 명시적 dry-run만 같은 슬롯에서 진단용 full을 실행한다. 두 승격은 담당자가 한 후보씩 진행하며 별도 전역 락이나 CI·병합·배포를 묶는 새 큐를 사용하지 않는다.
- 릴리스 버전(SemVer): 릴리스 PR 제목에
vX.Y.Z를 넣는다(수정만=patch, 기능 포함=minor, 큰 이정표=major — 정식 출시가v1.0.0). 릴리스 PR은 Create a merge commit으로만 머지한다(squash/rebase 금지 — staging과 main의 승격 이력을 보존한다). v0.17.7의 #1485 적용 후에는 Production smoke가 성공하면 release-tag 잡이 머지 커밋 메시지에서 버전을 찾아 git 태그 + GitHub Release(자동 릴리스 노트)를 만든다. 버전이 없으면 태그만 건너뛴다(배포는 정상). DB·Edge·frontend·smoke가 실패하면 버전이 붙지 않는다. 사후 브라우저 점검 결과는 별도다. - docs/admin도 앱과 같은 환경·배포 SHA로 전달한다. DB·Edge 검증 이후 Actions가 별도 docs Vercel 프로젝트를 빌드·배포하며,
BARBELIC_TARGET=staging또는production을 명시한다. staging 관리자 셸에는 staging Supabase 공개 URL/key를 사용한다. 관리자 패널에 별도 제품 버전을 만들지는 않지만 서버 호환을 바꾸는 관리자 변경은 승격 PR의 포함·검증 목록에 기록한다. - 순수 Markdown을 main에 CI·배포 생략 예외로 직접 합치면 문서 사이트는 다음 해당 환경 배포에서 갱신된다. main 푸시로 docs/admin이 먼저 공개되던 이전 Git 배포 경로는 새 프로세스의 기준이 아니다.
Required Release Order
아래는 활성화 이후 release → staging → main의 배포 순서다. 코드 설치와 활성화 확인은 릴리스 프로세스의 전환 목록을 따른다.
release/vX.Y.Z → staging의 최신 base에서 GitHub Full CI의 precheck 레인(static-checks+migration-smoke)을 통과하고 병합합니다(2026-09-15 개정). staging 배포(database·functions·frontend)·QA의 성공 SHA와 tree를 확인합니다.staging → main릴리스 PR(제목[Release vX.Y.Z] 요약, Create a merge commit)의 최신 base에서 GitHub Full CI의 QA2 레인(qa2-product-contracts)을 통과하고 오너가 승인합니다(2026-09-15 개정). QA한 tree와 동일한 결과를 병합하면 아래 3~8을deploy-steps.yml(1-Production Deploy·2-Staging Deploy 가 호출) production 레인으로 집행합니다.- Supabase DB migration을 dry-run 하고, dry-run 목록이 릴리스 diff와 같은지 확인합니다(release diff 게이트).
- Supabase DB migration을 적용합니다.
- 원격 migration 이력과 exact RPC contract를 검증합니다.
- Supabase Edge Functions를 배포하고 health probe를 확인합니다.
- Vercel production deployment 완료를 기다립니다(frontend 잡 — DB·함수가 초록이기 전에는 시작하지 않습니다).
- 운영 canary(smoke)를 수행합니다.
- smoke 성공 직후 Production 태그·GitHub Release를 생성합니다. #1564 반영 이후 사후 브라우저 점검과 경고 잡은 비활성화돼 실행하지 않습니다.
DB 검증보다 frontend activation이 앞설 수 없습니다. 특히 writer RPC를 교체하는 릴리스는 구 RPC fallback을 두지 않으므로 이 순서를 위반하면 저장 CRUD가 즉시 실패합니다.
Pre-Merge Gate
릴리스 브랜치에서 다음 명령을 모두 통과시킵니다.
npm run check:deployment
npm run check
npm run buildnpm run check:deployment는 Edge Function manifest, 문서 링크, 배포 순서를 검사합니다. npm run check는 migration 및 정책 계약과 TypeScript/tests를 함께 검사합니다.
Production Deployment
1. DB migration dry-run
npx supabase@latest db push --linked --dry-run출력에 릴리스에 포함된 migration만 나타나는지 확인합니다.
2. DB migration apply
npx supabase@latest db push --linked3. Remote DB contract gate
npm run check:remote-schema이 gate는 다음을 모두 검증해야 합니다.
- 모든 로컬 migration version이
supabase_migrations.schema_migrations에 적용됨 - current write RPC의 exact signature가 존재함
- current writer body가 구 writer/reconcile RPC를 호출하지 않음
- 구 workout writer/reconcile RPC가 원격에서 제거됨
- rolling read contract인
get_volume_overview(date,integer)selector의 v3/v4가 존재하고 각 payload를 유지하며, v2 presentation이 privateget_volume_overview_v2_core(date)로 남아 있음. 공개 한 인자 오버로드get_volume_overview(date)는20260820120300이 드롭했으므로 원격에 있으면 안 됩니다
현재 세션(완료·계획·그룹 운동 계획) write contract(이슈 #1215, 2026-09-04):
public.save_session_v5(jsonb,uuid,text)
public.delete_session_v5(uuid,bigint,uuid,text)아래 옛 문은 원격에 LG426 스텁(아무것도 쓰지 않고 "앱 업데이트 필요"를 던지는 함수)으로만 남아 있어야 한다 — 실제 쓰기 본문이 남아 있으면 안 된다:
public.save_workout_v4(jsonb,uuid,text)
public.update_completed_session_v4(uuid,jsonb,bigint,uuid,text)
public.delete_completed_session_v4(uuid,uuid,bigint,uuid,text)
public.save_plan_v3(jsonb,uuid,text)
public.delete_planned_session_v2(uuid,uuid,timestamptz,uuid,text)4. Supabase Edge Functions deploy
운영 project ref는 kobxeylancdimqhfkbnl입니다.
npx supabase@latest functions deploy stats-process-refresh-jobs --project-ref kobxeylancdimqhfkbnl
npx supabase@latest functions deploy wodup-process-import-jobs --project-ref kobxeylancdimqhfkbnl
npx supabase@latest functions deploy wodup-start-import --project-ref kobxeylancdimqhfkbnl각 함수의 x-barbelic-deployment-version 헤더(전이 기간 동안 구 x-lift-guild-deployment-version도 병행 노출)와 deployment_version 응답을 확인합니다.
5. Frontend activation
DB와 Edge Function 검증이 끝난 뒤에만 프론트를 활성화합니다.
새 브랜치 매핑 활성화 이후(맨 위 절): 평시에는
staging → main승격 PR 병합이deploy-steps.yml(1-Production Deploy·2-Staging Deploy 가 호출)의 production 레인을 돌려 여기까지 자동 집행합니다. staging 병합은 staging 환경에 배포합니다. 아래 문장은 비상 복구로 사람이 직접 배포할 때의 기준입니다.
https://www.barbelic.com공개 웹과 새 iOS 빌드의 정규 주소는 모두 https://www.barbelic.com이다. preview 성공은 운영 활성화 완료를 의미하지 않습니다.
Post-Deployment Verification
npm run check:remote-schema
curl -I https://www.barbelic.com/
curl -i https://kobxeylancdimqhfkbnl.supabase.co/functions/v1/wodup-start-import
curl -i https://kobxeylancdimqhfkbnl.supabase.co/functions/v1/wodup-process-import-jobs
curl -i https://kobxeylancdimqhfkbnl.supabase.co/functions/v1/stats-process-refresh-jobs운영 canary는 기존 세션 복구, 홈 로딩, 달력 조회, 세션 생성·수정·삭제, 계획 생성·삭제를 포함합니다. 관리자 운영 콘솔의 Edge Function 배포 및 DB migration 상태도 확인합니다. 정규 웹 origin의 /은 직접 200을 반환해야 한다.
Vercel 자동 배포 범위
새 배포 경로의 main/staging은 앱·docs 모두 직접 Git 배포를 끄고 Actions가 DB·Edge 이후 배포한다. 아래 브랜치 필터는 Git 프리뷰 범위에 적용한다.
에이전트 브랜치는 프리뷰를 만들지 않는다. vercel.json의 git.deploymentEnabled가 claude/*와 agent/*를 끄고, 앱 프로젝트만 claude/ui-*를 다시 켠다 — 디자인 딜리버리는 프리뷰가 리뷰 수단 자체이기 때문이다. 한 브랜치가 여러 규칙에 걸리면 하나라도 true면 배포되므로 claude/ui-v64는 앱 프리뷰를 받고 문서 프리뷰는 받지 않는다.
특정 브랜치의 프리뷰가 필요하면 그 맵에 "<브랜치>": true 한 줄을 넣거나, 브랜치 이름을 두 접두사 밖으로 두면 된다.
전면 차단("deploymentEnabled": false)은 쓰지 않는다. 두 가지 이유가 있다. 첫째, Vercel 문서는 이 설정의 전신인 github.enabled = false가 있으면 Deploy Hook이 아예 트리거되지 않는다고 명시한다 — 전면 차단 후 수동 배포 수단까지 잃을 위험이 있다. 둘째, deploymentEnabled가 무시되고 빌드가 계속 걸린다는 보고(vercel/vercel#11176)가 있어, 차단을 신뢰하려면 실측이 먼저다. 필요해지면 Deploy Hook을 먼저 만들어 동작을 확인한 뒤에 바꿀 것.
과거 Git 직접 배포에서는 Settings → Environments → Production → Branch Tracking → Auto-assign Custom Production Domains를 끄고 Staged 배포를 수동 promote하여 공개 시점을 제어했다. 새 main/staging 경로의 평시 배포는 Actions가 DB·Edge 성공 뒤 실행하므로 이 수동 promote 절차를 요구하지 않는다.
staged 배포도 빌드는 그대로 한다 — 도메인만 안 붙일 뿐이라 하루 배포 한도는 똑같이 소비한다. 한도 문제를 푸는 것은 위의 브랜치 필터와 아래의 경로 필터이고, staged는 언제 보일지를 정하는 별개 수단이다.
관리자 셸 — barbelic-docs /admin
관리자 페이지(운동 종목 카탈로그·계열·디테일·Wodup 매핑·Wodup 인입·운영 콘솔)는 앱이 아니라 문서 사이트 프로젝트(barbelic-docs)의 /admin/ 에서 서비스한다 (2026-08-21 이전). 소스는 앱과 같은 src/react(관리자 UI·컨트롤러는 제자리)이고, 엔트리만 다르다.
- 엔트리:
admin/index.html→src/react/vite/admin/main.tsx(독립 셸: 로그인 게이트 →is_lift_guild_admin권한 게이트 → 운동 종목 카탈로그 위에서DesktopAdminFeature구동). - 빌드:
vite.admin.config.mjs(레포 루트 기준, 산출물admin/index.html+admin/assets/*). 로컬 확인은npm run dev:admin→http://127.0.0.1:5175/admin/, 번들 확인은npm run build:admin→dist-admin/admin/. - docs 동봉:
docs/package.json의build가vitepress build뒤docs/scripts/build-admin.mjs를 실행해BARBELIC_ADMIN_OUT_DIR=.vitepress/dist로 같은 산출물 안에/admin/을 만든다. Actions는 DB·Edge 이후 같은 SHA의 docs/admin을 별도 Vercel 프로젝트에 배포한다. 빌드의BARBELIC_TARGET과 해당 환경의 공개 Supabase 값이 일치해야 하며/admin/index.html존재와 대상 도장을 검사한다.docs/vercel.json의 main/staging 직접 Git 배포는 끄고 기존 경로 필터는 프리뷰 범위에만 사용한다. - 서버 측은 무변경: 관리자 RPC·RLS는 전부
is_lift_guild_admin()으로 잠겨 있어 origin과 무관하다. 임퍼서네이션(view-as-user)은 앱 오버레이이므로 앱에 남는다. - 데스크톱 앱 쪽은 제거됐다: 사이드바 '관리자' 항목·
/admin(?view=dashboard.admin,#dashboard.admin) URL 라우트·adminRuntime공급이 없고, 앱 번들은 관리자 feature를 싣지 않는다. 관리자 UI·컨트롤러 파일(ui/desktop/screens/DesktopAdmin*.tsx,features/admin/,controllers/admin*.ts,desktop-admin.css)은 독립 셸이 제자리에서 import 한다.
오너 콘솔 선행 작업(한 번):
- Vercel
barbelic-docs→ Settings → General → Root Directory(docs) 아래 "Include source files outside of the Root Directory in the Build Step" 를 켠다. 꺼져 있으면build-admin.mjs가 레포 루트를 찾지 못해 관리자 셸만 건너뛰고(경고 출력) 문서 사이트는 그대로 배포된다 — 실패가 아니라/admin/404 로 나타난다. - Supabase → Authentication → URL Configuration → Redirect URLs 에 docs 도메인
https://<docs-domain>/admin/**을 추가한다. 카카오 OAuth 콜백은 현재 origin으로 돌아오므로 이 등록이 없으면 관리자 로그인이 완료되지 않는다. (로컬은http://127.0.0.1:5175/**.) - Vercel
barbelic-docs의 Node.js 버전이 루트package.jsonengines(^22.13.0 || >=24)를 만족하는지 확인한다 — 관리자 셸 빌드는 레포 루트에서npm ci후 vite를 실행한다. - docs 프로젝트의 Production은 main, custom staging은 staging으로 맞춘다. docs staging의 공개 Supabase URL/key와 인증 redirect는 staging 프로젝트에 맞추고 운영 값과 섞지 않는다. 앱과 별도 docs 프로젝트 ID를 Actions의 repository variable
VERCEL_DOCS_PROJECT_ID로 지정한다. 환경 생성·설정 확인과 실제 배포·로그인 검증은 각각 기록한다.
Vercel 빌드 스킵 조건
아래는 2026-08-20에 도입한 Git 직접 빌드 필터의 배경과 프리뷰 운영 규칙이다. 새 main/staging 배포에는 이 경로 필터로 앱·docs/admin을 생략하지 않고 Actions가 같은 SHA·환경을 함께 배포한다.
이 저장소는 Vercel 프로젝트 둘(barbelic 앱, barbelic-docs 문서 사이트)에 함께 연결돼 있다. 기본 동작은 모든 푸시가 두 프로젝트를 다 빌드하는 것이라, 마이그레이션만 바꾼 커밋도 문서 사이트를 다시 빌드하고 문서만 바꾼 커밋도 앱을 다시 빌드했다. 2026-08-20에 하루 배포 100건(Hobby 한도)을 소진해 Deployment rate limited — retry in 24 hours로 체크가 막혔다.
그래서 각 vercel.json에 ignoreCommand로 경로 필터를 걸었다. 명령이 0으로 끝나면 빌드를 건너뛰고, 0이 아니면 빌드한다 (git diff --quiet의 반환값이 그대로 맞아떨어진다).
- 앱 (
vercel.json) —index.html,app-config.js,vite.config.mjs,package.json,package-lock.json,vercel.json,src/,public/,api/중 하나라도 바뀌어야 빌드한다. 이 목록이 곧 vite 빌드와 Vercel 함수의 입력 전부다. - 문서 (
docs/vercel.json) — 이 프로젝트의 루트 디렉터리가docs/라./에 더해, 동봉하는 관리자 셸의 입력(../admin,../src,../app-config.js,../vite.admin.config.mjs,../package.json,../package-lock.json)을 감시한다.
목록에 없는 것(supabase/, tests/, test/, e2e/, scripts/, ios/, error-cases/)은 빌드 산출물에 들어가지 않으므로 스킵이 정답이다. 2026-08-20 커밋 27건에 시뮬레이션하면 Production 빌드가 54회에서 24회로 준다.
앱 목록에 새 빌드 입력을 추가할 때는 ignoreCommand도 같이 늘릴 것. 빠뜨리면 그 변경만 담은 커밋이 조용히 배포되지 않고 직전 배포가 그대로 서비스된다 — 실패가 아니라 무반응이라 알아채기 어렵다. 반대로 판단이 서지 않으면 목록에 넣는 쪽이 안전하다.
스킵된 배포는 Vercel에서 별도 rate-limit 버킷(Skipped deployments per minute)으로 세고, 빌드 시간을 소비하지 않는다.
Rollback Notes
단계별 절차는 rollback.md가 정본이다 — 층별 판단, Vercel Instant Rollback 클릭 순서, 되돌린 뒤 브랜치·버전 정리, 수정 릴리스 후 도메인 되살리기까지. 아래는 그 문서가 따르는 방침이다.
- frontend-only regression은 Vercel의 이전 production deployment로 되돌립니다 (Instant Rollback). 되돌리면 실서비스 도메인 자동 배정이 꺼지므로, 이후 수정 릴리스는 배포가 초록이어도 도메인이 옛 배포본을 가리킬 수 있습니다 —
frontend잡의 "public origin must serve this deployment" 검사가 이 어긋남을 잡습니다. - Volume v4 frontend rollback은 보존된 selector v3를 사용하므로 DB v3/v4 selector를 forward-fix 없이 제거하지 않습니다. v2 presentation은
20260820120300이후 private core라 클라이언트 rollback 경로가 아닙니다 — v2로 되돌려야 하면 selector를 경유하는 forward-fix migration이 필요합니다. - DB migration은 이미 적용된 파일을 수정하지 않고 새 forward-fix migration을 추가합니다.
- writer contract regression은 구 RPC를 다시 살리는 방식으로 우회하지 않습니다. current contract를 고치는 migration을 먼저 적용한 뒤 frontend를 재배포합니다.
- Edge Function regression은 이전 정상 함수 버전을 재배포하거나 hotfix 함수를 배포합니다.
docs Vercel CLI 실행 위치
CLI는 저장소 루트에서 --local-config docs/vercel.json을 지정해 실행한다. Vercel 프로젝트 Root Directory는 docs를 유지한다. CLI까지 docs 디렉터리에서 실행해 경로가 중복 적용되지 않게 한다. docs 설정의 installCommand: npm ci로 자체 lockfile의 VitePress 의존성을 설치하며, 관리자 빌드 스크립트는 필요한 루트 의존성을 별도로 준비한다.