Skip to content

Pregoi infrastructure: R2 URL and API Gateway

Purpose: Align code and docs with Cloudflare infra: R2 custom domain (static.pregoi.com), API Gateway (Zuplo), multi-tenant and typography. Plan only; implementation references and verification checklist included.

See also: font-pc-mobile-parity-plan.md, font-r2-and-local-setup.md.

English {#english}

Overview

  • Fonts: Use NEXT_PUBLIC_FONTS_BASE_URL only (e.g. https://static.pregoi.com). No hardcoded font base URL. Prebuild runs generate-fonts-css.js; R2 serves fonts.css and WOFF2 with cache-busting hashes.
  • API: Use NEXT_PUBLIC_API_URL (e.g. Zuplo URL) for all API calls; inject companyId in path and headers (e.g. X-Prego-Company). No hardcoded API host.
  • Verification: See §6 checklist (env vars, R2 MIME/CORS, preload, API gateway).

Infra and URLs

flowchart LR
  subgraph Client
    W[client-web]
  end
  subgraph Env
    F[NEXT_PUBLIC_FONTS_BASE_URL\nstatic.pregoi.com]
    A[NEXT_PUBLIC_API_URL\nZuplo]
  end
  W --> F
  W --> A
  F --> R2[R2\nfonts]
  A --> GW[Gateway]

한국어 {#korean}

1. 폰트 인프라 및 에셋 URL 변경

1.1 베이스 URL 통일

폰트 다운로드를 위한 R2 URL은 환경 변수 NEXT_PUBLIC_FONTS_BASE_URL만 사용한다. 코드에는 폰트 베이스 URL을 하드코딩하지 않고, 해당 환경 변수를 읽어 사용한다.

항목현재변경 목표
환경 변수NEXT_PUBLIC_FONTS_BASE_URL (값: https://pub-xxx.r2.dev 또는 미설정)NEXT_PUBLIC_FONTS_BASE_URL 사용. 값은 https://static.pregoi.com 으로 설정.
폰트 다운로드 R2 URLR2 공개 URL(r2.dev) 또는 동일 오리진R2 커스텀 도메인. 모든 폰트 요청(fonts.css, WOFF2)은 NEXT_PUBLIC_FONTS_BASE_URL 에 설정된 오리진(예: https://static.pregoi.com)을 사용.

변경 대상

  • 환경 변수: .env, .env.example, Cloudflare Pages 대시보드 Environment Variables 에 NEXT_PUBLIC_FONTS_BASE_URL=https://static.pregoi.com 설정. 폰트 관련 코드는 이 변수만 참조하도록 유지.
  • 문서: apps/client-web/scripts/README-fonts.md, docs/planning/font-pc-mobile-parity-plan.md 등에 기재된 예시 URL을 https://static.pregoi.comNEXT_PUBLIC_FONTS_BASE_URL 기준으로 수정.

검증

  • Pages 대시보드에서 NEXT_PUBLIC_FONTS_BASE_URL=https://static.pregoi.com 설정 여부 최종 확인.

1.2 CSS 생성 스크립트 (generate-fonts-css.js)

항목내용
파일apps/client-web/scripts/generate-fonts-css.js
역할빌드 전 NEXT_PUBLIC_FONTS_BASE_URL을 읽어 public/fonts/fonts.css 생성. @font-facesrc: url()이 해당 베이스 + /fonts/{locale}/{filename} 형태가 되도록 함.

검토·유지 사항

  • 베이스 URL: 이미 process.env.NEXT_PUBLIC_FONTS_BASE_URL 사용 중. 값을 https://static.pregoi.com으로 설정하면 출력 CSS의 URL이 https://static.pregoi.com/fonts/en/Inter-Regular.[hash].woff2 등이 됨. 추가 로직 변경 없이 환경 변수만 변경하면 됨.
  • R2 커스텀 도메인: 스크립트는 “fetch”가 아니라 로컬 manifest 기준으로 URL 문자열만 조합하므로, R2에서 실제로 static.pregoi.com으로 서빙되는지만 인프라에서 보장하면 됨.
  • 주석: 파일 상단 주석에 예시 URL을 https://static.pregoi.com 또는 “R2 custom domain”으로 갱신 권장.

1.3 Cache Busting (해시 파일명)

항목현재변경 목표
파일명font-manifest.jsonfonts.cssInter-Regular.8d71c824.woff2 등 해시 포함명 사용유지. R2 버킷에 이미 font.[hash].woff2 형태로 올라가 있다면, manifest/생성 스크립트가 그 파일명을 참조하도록 일치시킴.

변경 대상

  • generate-fonts-css.js: font-manifest.json에서 locale별 파일명을 읽고 있음. R2에 올라간 파일명(해시 포함)과 manifest가 일치하는지 확인.
  • build_fonts.py / upload_fonts_to_r2_wrangler.sh: 업로드 시 해시된 파일명 사용 여부 확인. 현재 구조 유지 시 추가 코드 변경 없이 기획서에 “R2 버킷 파일명과 manifest 일치 확인”만 체크리스트로 명시.

2. 글로벌 타이포그래피 및 Fallback 전략

2.1 언어별 폰트 스택 (:lang() 및 data-locale)

항목현재변경 목표
선택자app/globals.css에서 :root[data-locale="xx"]:root:lang(xx) body 등 사용유지. :lang() 및 data-locale 기반 로직 유지.
KO fallback'Noto Sans KR', 'Pretendard', -apple-system, 'Apple SD Gothic Neo', 'Malgun Gothic', sans-serif'Pregoi-KR', -apple-system, 'Apple SD Gothic Neo', 'Malgun Gothic', sans-serif (폰트 패밀리 이름이 Pregoi 전용으로 바뀌는 경우에 한함)
AR fallback'Noto Sans Arabic', 'IBM Plex Sans Arabic', 'Segoe UI Arabic', 'Geeza Pro', sans-serif'Pregoi-AR', 'Segoe UI Arabic', 'Geeza Pro', sans-serif
JP fallback'Noto Sans JP', 'Hiragino Sans', 'Hiragino Kaku Gothic ProN', 'Meiryo', 'Yu Gothic', sans-serif'Pregoi-JP', 'Hiragino Sans', 'Meiryo', sans-serif

참고

  • 폰트 패밀리 이름: R2/빌드에서 사용하는 실제 @font-facefont-family 이름이 Pregoi-KR / Pregoi-AR / Pregoi-JP로 배포된다면, globals.csslocales/*.css--locale-font@font-face의 family 이름을 위 스택에 맞춰 변경.
  • 현재는 Noto Sans KR, Noto Sans Arabic, Noto Sans JP 등으로 되어 있으므로, “Pregoi-*”로의 전환은 폰트 에셋·@font-face 정의가 바뀌는 시점에 맞춰 진행. 기획서에는 “변경 목표”만 명시.

변경 대상

  • apps/client-web/app/globals.css: :root[data-locale="ko"], :root[data-locale="ar"], :root[data-locale="ja"]--locale-font 값.
  • apps/client-web/public/locales/ko.css, ar.css, ja.css: 동일 fallback 스택으로 정렬.
  • apps/client-web/scripts/generate-fonts-css.js: FONT_FAMILIES에서 ko/ar/ja의 font-family 이름을 Pregoi-*로 바꿀 경우 함께 수정.

2.2 렌더링 안정화 (Windows/Chrome)

항목현재변경 목표
-webkit-font-smoothingbody-webkit-font-smoothing: antialiased 적용됨유지
transform hackh1, h2, h3, .smooth-texttransform: rotate(0.03deg), text-shadow 적용됨유지

변경 대상

  • 없음. 이미 반영되어 있으면 기획서에 “확인만” 표시.

3. 멀티테넌트 라우팅 및 API Gateway 연동

3.1 API 베이스 URL 및 환경 변수 통일

원칙: 향후 API 베이스 도메인 변경을 쉽게 하기 위해, API 베이스 URL은 반드시 환경 변수로만 관리하고 코드 내에는 하드코딩하지 않는다.

항목현재변경 목표
클라이언트 API 베이스/api/... 상대 경로 또는 미정의Zuplo URL 등 실제 주소는 환경 변수 값 사용 (기본값 예: https://prego-main-bb45748.d2.zuplo.dev)
환경 변수 이름(없을 수 있음)NEXT_PUBLIC_API_URL 로 통일. 모든 API 호출이 이 변수를 참조하도록 구현.
도메인 변경배포 환경별·시점별로 .env 또는 Pages env에서 NEXT_PUBLIC_API_URL만 변경하면 되도록, 코드 전반에 해당 환경 변수 적용.

변경 대상

  • 환경 변수: .env, .env.example, Cloudflare Pages Environment Variables에 NEXT_PUBLIC_API_URL=https://prego-main-bb45748.d2.zuplo.dev (또는 운영 도메인) 설정.
  • API 호출 레이어: fetch('/api/...') 또는 하드코딩된 호스트를 사용하는 모든 위치에서, 베이스 URL을 process.env.NEXT_PUBLIC_API_URL(또는 이를 읽는 공통 유틸)로만 구성.
    • 예: apps/client-web/app/page.tsx, apps/client-web/app/notices/page.tsx, apps/client-web/app/leaves/page.tsx 등.
    • apps/client-web/app/signin, app/signupcomponents/signin-form 등에서 사용하는 /api/auth/signin, /api/auth/signup 호출.
  • 공통화: lib/api-client.ts 또는 config/env.ts 등에서 getApiBaseUrl()process.env.NEXT_PUBLIC_API_URL 반환하도록 하고, 코드 어디에도 API 베이스 URL 문자열을 직접 쓰지 않도록 모든 API 호출이 이 함수/변수를 사용하도록 변경.

3.2 Tenant Context (companyId) 주입

항목내용
라우팅app/[companyId]/... 경로에서 companyId는 이미 URL에서 추출됨. CompanyLocaleProvider, layout params 등에서 사용 중.
API 경로요청 경로를 ${NEXT_PUBLIC_API_URL}/${companyId}/api/... 형태로 구성 (실제 값은 env에서 로드).
헤더X-Prego-Company: ${companyId} 를 모든 Gateway 요청에 포함.

변경 대상

  • API를 호출하는 컴포넌트/훅: companyId를 props/context에서 받아:
    1. URL: ${apiBase}/${companyId}/api/...
    2. Headers: { 'X-Prego-Company': companyId }
  • contexts/company-locale-context.tsx: 이미 companyId 제공. API 클라이언트가 이 context를 사용하거나, 호출부에서 companyId를 넘기도록 정책 통일.

3.3 Zuplo 대응 헤더

항목내용
헤더Gateway(Zuplo)에서 사용할 x-prego-email, x-prego-employee-id 등을 fetch 옵션의 headers에 포함.
적용 범위인증/세션 정보가 있는 요청(예: 로그인 후 API 호출)에서 해당 값을 읽어 헤더로 설정.

변경 대상

  • API 클라이언트 또는 인증 훅: 세션/쿠키에서 email·employee-id를 조회한 뒤, headers['x-prego-email'], headers['x-prego-employee-id'] 로 설정. (실제 키 이름은 Zuplo 설정에 맞춤.)

4. 빌드 설정 (package.json)

항목현재변경 목표
pages:buildnode scripts/generate-fonts-css.js && NEXT_BUILD_WORKERS=0 npx @cloudflare/next-on-pages유지. 이미 generate-fonts-css.js가 next-on-pages 이전에 실행됨.
환경 변수빌드 시 process.env.NEXT_PUBLIC_FONTS_BASE_URL 사용Cloudflare Pages 빌드 환경에 NEXT_PUBLIC_FONTS_BASE_URL=https://static.pregoi.com 설정되어 있는지 확인.

변경 대상

  • 코드 변경 없음. 문서·체크리스트에 “Pages 빌드 환경 변수에 NEXT_PUBLIC_FONTS_BASE_URL 설정 확인” 항목 추가.

5. 보안·메타데이터·CORS

5.1 CORS 정렬

항목현재변경 목표
R2 CORSPulumi/대시보드: app.pregoi.com, pregoi.com, prego-web-anm.pages.dev, localhosthttps://x.pregoi.com 등 새 오리진이 있다면 CORS Allowed Origins에 추가. 하드코딩된 오리진 검사가 있으면 충돌하지 않도록 정리.
클라이언트클라이언트 코드 내 하드코딩된 origin 검사가 있다면 x.pregoi.com 등 새 도메인 반영.필요 시 허용 목록을 env 또는 설정에서 읽도록 변경.

변경 대상

  • prego-pulumi/__main__.py: R2 CORS의 allowedOriginshttps://x.pregoi.com 추가 (해당 도메인이 프론트 서빙에 사용되는 경우).
  • 기타 CORS/allowlist가 하드코딩된 파일 검색 후, x.pregoi.com 반영 또는 설정 기반으로 전환.

5.2 Preload 태그 (layout)

항목현재변경 목표
폰트 preloadapp/layout.tsx에서 fontEnHref 등으로 preload. fontsBaseTrimmed 사용 시 R2 URL로 이미 설정됨.베이스 URL이 https://static.pregoi.com 이면 preload URL이 https://static.pregoi.com/fonts/en/... 가 되어 FOIT 최소화.

변경 대상

  • 코드 변경 없음. NEXT_PUBLIC_FONTS_BASE_URL=https://static.pregoi.com 설정만 하면 layout의 기존 로직으로 static.pregoi.com 도메인 preload 적용됨.
  • 기획서에 “Preload가 static.pregoi.com을 사용하는지 배포 후 검증” 항목 추가.

6. 테스트·검증 체크리스트 (SRE 관점)

다음 항목을 배포 후 또는 인프라 변경 후 확인한다.

#확인 항목방법기대 결과
1NEXT_PUBLIC_FONTS_BASE_URLPages 대시보드 Environment Variableshttps://static.pregoi.com
2폰트 MIME TypeR2 대시보드 → 버킷 → Objects → 파일 MetadataContent-Type: font/woff2
3폰트 URL 응답브라우저/curl로 https://static.pregoi.com/fonts/fonts.css 요청200, Content-Type: text/css, @font-face 내용
4WOFF2 URL 응답https://static.pregoi.com/fonts/en/Inter-Regular.[hash].woff2 요청200, Content-Type: font/woff2
5브라우저 캐시폰트 요청 응답 헤더cf-cache-status: HIT (MISS/DYNAMIC만 나오면 static.pregoi.com에 Cache Everything 페이지 규칙 검토)
6CORS앱 페이지에서 폰트 요청 시 Response HeadersAccess-Control-Allow-Origin에 앱 오리진 포함
7API Gateway로그인/데이터 로드 시 Network 탭NEXT_PUBLIC_API_URL에 설정된 도메인으로 ${companyId}/api/... 호출, 필요 시 X-Prego-Company, x-prego-email 등 헤더 포함
8Preload페이지 소스 또는 Network 탭<link rel="preload" href="https://static.pregoi.com/..."> 존재

7. 변경 대상 파일 요약 (구현 시 참고)

구분파일/위치변경 요약
폰트 URL.env, .env.example, Pages envNEXT_PUBLIC_FONTS_BASE_URL=https://static.pregoi.com
API URL.env, .env.example, Pages envNEXT_PUBLIC_API_URL (예: https://prego-main-bb45748.d2.zuplo.dev). 코드에는 하드코딩 없이 이 env만 사용.
폰트 CSS 생성apps/client-web/scripts/generate-fonts-css.js주석/예시 URL 갱신. (선택) FONT_FAMILIES를 Pregoi-*로 변경 시 ko/ar/ja 반영
타이포그래피apps/client-web/app/globals.cssKO/AR/JP fallback 스택을 Pregoi-* 기준으로 변경 (에셋 전환 시)
로케일 CSSapps/client-web/public/locales/ko.css, ar.css, ja.css위와 동일 fallback 정렬
Layoutapps/client-web/app/layout.tsx로직 변경 없음. env만 static.pregoi.com으로 설정 시 동작
API 베이스신규 또는 기존 lib/api-client.ts, configNEXT_PUBLIC_API_URL 환경 변수만 참조, 하드코딩 없음. companyId 경로/헤더 주입.
API 호출처app/page.tsx, notices/page.tsx, leaves/page.tsx, signin·signup 페이지·컴포넌트 등공통 API 클라이언트 사용, companyId·헤더 주입
CORSprego-pulumi/__main__.py, Cloudflare R2/대시보드https://x.pregoi.com 등 필요 오리진 추가
문서README-fonts.md, font-pc-mobile-parity-plan.mdstatic.pregoi.com, Zuplo URL 예시 및 체크리스트 반영

8. 기획서 상태

  • 코드 생성 없음: 본 문서는 변경 계획만 기술.
  • 구현 시: TypeScript 타입 안전성 유지, 기존 비즈니스 로직 변경 최소화.
  • 배포 후: §6 체크리스트로 폰트·캐시·API·CORS 검증.
Help