Skip to content

Feat(extension, client): separate extension send token environment#319

Merged
constantly-dev merged 9 commits intodevelopfrom
feat/#315/separate-extension-send-token-environment
Mar 19, 2026
Merged

Feat(extension, client): separate extension send token environment#319
constantly-dev merged 9 commits intodevelopfrom
feat/#315/separate-extension-send-token-environment

Conversation

@constantly-dev
Copy link
Member

@constantly-dev constantly-dev commented Mar 19, 2026

📌 Related Issues

관련된 Issue를 태그해주세요. (e.g. - close #25)

📄 Tasks

  • 확장 프로그램 환경별 빌드 격리 아키텍처 구축 (Dev / Prod)
  • Vite loadEnv 및 define을 활용한 런타임 환경 변수 주입 로직 구현
  • crx 플러그인 기반의 동적 manifest.json 생성 로직 적용
  • Turborepo 기반의 확장 프로그램 전용 빌드 파이프라인(build:dev, build:prod) 구축
  • 확장 프로그램 내 도메인 화이트리스트(ALLOWED_ORIGINS) 보안 로직 강화

⭐ PR Point (To Reviewer)

1. 왜 "환경별 물리적 격리(앱 분리)" 방식을 선택했는가?

처음에는 하나의 확장 프로그램 내에서 키(token_dev, token_prod)만 나눠 저장하는 방식을 고민했으나, 아래와 같은 이유로 확장 프로그램 자체를 물리적으로 분리하는 방식을 채택했습니다.

  • 보안 및 데이터 오염 방지: chrome.storage는 확장 프로그램 ID별로 저장소가 생성됩니다. 앱을 분리함으로써 Dev 토큰과 Prod 토큰이 물리적으로 섞일 가능성을 원천 차단했습니다.
  • DX(개발자 경험) 향상: 이제 브라우저에 Prod 확장과 Dev확장 두 개를 동시에 띄워놓고 실시간 비교 개발 및 테스트가 가능합니다. 테스트할 때마다 기존 확장을 끄고 켤 필요가 없습니다.
  • 스토어 심사 리스크 최소화: 운영 환경(manifest.json)에 localhost 권한을 포함할 필요가 없어 보안 경고 문구를 깔끔하게 유지할 수 있습니다.

2. 환경 변수 주입 및 통신 플로우

Vite의 빌드 시점에 환경 변수를 주입하여, 확장 프로그램이 "내가 허용한 도메인의 메시지만 수락"하도록 설계했습니다.

graph LR
    subgraph Web_Environments
        A[localhost:5173]
        B[dev.pinback.today]
        C[pinback.today]
    end

    subgraph Chrome_Extensions
        D((Pinback DEV))
        E((Pinback PROD))
    end

    A -- "postMessage(token)" --> D
    B -- "postMessage(token)" --> D
    C -- "postMessage(token)" --> E

    D -- "Safe Save" --> DS[(Storage DEV)]
    E -- "Safe Save" --> PS[(Storage PROD)]

    style D fill:#f96,stroke:#333
    style E fill:#32CD32,stroke:#333

Loading

3. 변경 참고 사항

이제 확장 프로그램 수정 후 테스트 시 pnpm build:dev를 사용하여 dist 폴더를 생성하고, 크롬에서 압축해제된 확장 프로그램 로드로 해당 폴더를 올려주세요.

확장 프로그램 이름이 Pinback-dev로 뜨면 정상입니다.

apps/extension의 .env.development.env.production 설정에 따라 빌드 결과물이 달라지니 확인 부탁드립니다.
(해당 env 따로 전달 드리겠습니다!)


Summary by CodeRabbit

릴리스 노트

  • 새 기능

    • 허용 출처 검증을 추가하여 보안 강화
  • 개선 사항

    • 확장 프로그램이 환경 기반 웹 URL을 사용하도록 개선(온보딩/로그아웃 링크 동작 반영)
    • 로그인/온보딩 리디렉션 설정 단순화
  • 업데이트

    • 확장 프로그램 버전 1.0.3으로 업데이트
    • 개발·프로덕션 빌드 스크립트 및 파이프라인 개선 (명시적 모드 분리)

@vercel
Copy link

vercel bot commented Mar 19, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
pinback-client-client Ready Ready Preview, Comment Mar 19, 2026 8:43am
pinback-client-landing Ready Ready Preview, Comment Mar 19, 2026 8:43am

@github-actions github-actions bot requested review from jjangminii and jllee000 March 19, 2026 08:10
@github-actions github-actions bot added the feat 기능 개발하라 개발 달려라 달려 label Mar 19, 2026
@coderabbitai
Copy link

coderabbitai bot commented Mar 19, 2026

Warning

Rate limit exceeded

@constantly-dev has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 26 minutes and 5 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 63c79446-134b-4e4b-b60a-e86ece4b27c5

📥 Commits

Reviewing files that changed from the base of the PR and between 01f8933 and de53079.

📒 Files selected for processing (2)
  • apps/extension/src/content.ts
  • apps/extension/vite.config.ts

Walkthrough

Google OAuth 리다이렉트 URI 선택을 단순화(단일 VITE_GOOGLE_REDIRECT_URI 사용)했고, 확장 프로그램에 환경별 빌드 모드(dev/prod)와 관련 스크립트를 추가했으며, 메시지 원본 검증(__ALLOWED_ORIGINS__)과 런타임 웹 URL(VITE_WEB_URL) 구성을 도입했습니다. 매니페스트 버전과 .gitignore도 업데이트되었습니다.

Changes

Cohort / File(s) Summary
Google OAuth 리다이렉트 URI 단순화
apps/client/src/pages/onBoarding/GoogleCallback.tsx, apps/client/src/shared/utils/handleGoogleLogin.ts
리다이렉트 URI 선택 로직을 PROD/DEV 분기(VITE_GOOGLE_REDIRECT_URI_PROD/DEV)에서 단일 환경변수(VITE_GOOGLE_REDIRECT_URI) 사용으로 통합.
확장 프로그램 환경 설정 및 빌드
apps/extension/vite.config.ts, apps/extension/package.json, package.json, turbo.json
Vite 환경 변수 동적 로드(loadEnv)로 전환, __ALLOWED_ORIGINS__ 정의 주입, build:dev/build:prod 스크립트 및 Turbo 작업 추가, 빌드 모드 명시화(--mode).
확장 프로그램 메시지 보안 및 타입 정의
apps/extension/src/content.ts, apps/extension/src/vite-env.d.ts
window.postMessage 수신 시 event.origin__ALLOWED_ORIGINS__로 검증하고 단일 메시지 핸들러로 통합; 전역 __ALLOWED_ORIGINS__: string[] 타입 선언 추가.
확장 프로그램 런타임 웹 URL 구성
apps/extension/src/background.ts, apps/extension/src/pages/LogOutPop.tsx
하드코딩된 온보딩 URL들을 import.meta.env.VITE_WEB_URL(기본값 https://pinback.today) 기반의 webUrl로 교체하여 런타임 구성 가능.
확장 프로그램 유지보수·메타데이터
apps/extension/.gitignore, apps/extension/manifest.json
.env.development/.env.production을 .gitignore에 추가하고, 매니페스트 버전을 1.0.21.0.3로 증분.
소소한 변경
apps/client/... (공통) 기타 소폭 공백/포맷 변경
로직 불변의 사소한 공백/포맷 조정들.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 분

Possibly related PRs

Suggested labels

🛠️ Feature, ⚙️ Setting, frontend

Suggested reviewers

  • jllee000
  • jjangminii
  • karnelll

🐰 리다이렉트 하나로 깔끔히,
웹 URL은 바람 따라 유연히,
원본 검사로 메시지 지키고,
빌드 모드는 명확히 갈라놓았네,
작지만 단단한 변화에 깡총! 🥕✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 주요 변경사항(extension 및 client의 환경 분리)을 명확하게 요약하고 있습니다.
Linked Issues check ✅ Passed 변경사항은 #315의 extension send token 환경 분리 요구사항을 충족합니다(VITE_GOOGLE_REDIRECT_URI 통합, 환경 변수 분리). #25는 관련 없습니다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 extension 및 client의 환경 설정 분리를 목표로 일관성 있게 수행되었으며, 범위를 벗어난 변경은 없습니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description check ✅ Passed Pull request 설명이 대부분 완성되어 있습니다. 관련 Issue, 작업 내용, 리뷰어 주의사항이 모두 포함되어 있으며, 환경별 격리 아키텍처 선택 이유와 플로우도 명확하게 설명되어 있습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/#315/separate-extension-send-token-environment
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

github-actions bot commented Mar 19, 2026

✅ Storybook chromatic 배포 확인:
🐿️ storybook

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/client/src/pages/onBoarding/GoogleCallback.tsx (1)

49-57: ⚠️ Potential issue | 🟠 Major

redirectUri 누락 시 요청을 중단하는 가드가 필요합니다.

Line 49 값을 검증하지 않고 Line 57에서 uri로 전송해, 환경 변수 누락 시 undefined가 백엔드로 전달될 수 있습니다. handleGoogleLogin에는 같은 가드가 있으므로 여기에도 동일한 방어가 필요합니다.

수정 제안
   const redirectUri = import.meta.env.VITE_GOOGLE_REDIRECT_URI;

   const loginWithCode = async (code: string) => {
+    if (!redirectUri) {
+      alert('Google OAuth 설정이 누락되었습니다.');
+      navigate('/onboarding?step=SOCIAL_LOGIN');
+      return;
+    }
+
     try {
       const res = await apiRequest.post(
         '/api/v3/auth/google',
         {
           code,
           uri: redirectUri,
         },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/client/src/pages/onBoarding/GoogleCallback.tsx` around lines 49 - 57,
loginWithCode currently uses redirectUri without validating it and may send
undefined to the backend; add the same guard used in handleGoogleLogin to
validate import.meta.env.VITE_GOOGLE_REDIRECT_URI (redirectUri) at the start of
loginWithCode and abort early (return or throw) with a clear error if missing,
before calling apiRequest.post('/api/v3/auth/google', { code, uri: redirectUri
}); ensure the guard is placed in the loginWithCode function so the request
never proceeds when redirectUri is falsy.
🧹 Nitpick comments (1)
turbo.json (1)

11-20: build:devbuild:prod 태스크 설정이 동일합니다.

두 태스크의 dependsOn, inputs, outputs 설정이 완전히 동일합니다. 현재로서는 문제가 없지만, 향후 유지보수를 위해 공통 설정을 추출하는 것을 고려해볼 수 있습니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@turbo.json` around lines 11 - 20, The "build:dev" and "build:prod" entries in
turbo.json duplicate the same "dependsOn", "inputs", and "outputs"; extract
these shared settings into a single reusable pipeline entry (e.g., "build:base"
or "build:common") and have "build:dev" and "build:prod" reference or extend
that shared entry (or depend on it) to avoid duplication; update the "build:dev"
and "build:prod" definitions to keep only environment-specific differences and
point to the shared config so future changes to "dependsOn", "inputs", or
"outputs" only need to be made in one place.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/extension/src/content.ts`:
- Around line 3-8: ALLOWED_ORIGINS being an empty array (when
VITE_ALLOWED_ORIGINS is unset) causes the origin check in the
window.addEventListener handler to always fail and silently drop messages;
change the ALLOWED_ORIGINS initialization/validation so that if
__ALLOWED_ORIGINS__ is missing/empty you either (a) default it to a safe runtime
value such as [window.origin] or a known client origin, or (b) log a clear
console.warn and bypass the includes check (treat empty as permissive) so
extensionBridge messages (setToken/logout) are not ignored; update the
origin-checking code in the window.addEventListener callback to account for this
fallback and emit a runtime warning when the env var is not provided.

In `@apps/extension/vite.config.ts`:
- Around line 19-23: The current define block sets __ALLOWED_ORIGINS__ to
JSON.stringify(env.VITE_ALLOWED_ORIGINS?.split(',') || []) which returns ['']
when VITE_ALLOWED_ORIGINS is the empty string; update the logic for
__ALLOWED_ORIGINS__ to treat an empty or whitespace-only VITE_ALLOWED_ORIGINS as
no origins by splitting, trimming, and filtering out empty entries (e.g., use
env.VITE_ALLOWED_ORIGINS ?
env.VITE_ALLOWED_ORIGINS.split(',').map(...).filter(Boolean) : []), ensuring the
result passed to JSON.stringify contains no empty strings.

---

Outside diff comments:
In `@apps/client/src/pages/onBoarding/GoogleCallback.tsx`:
- Around line 49-57: loginWithCode currently uses redirectUri without validating
it and may send undefined to the backend; add the same guard used in
handleGoogleLogin to validate import.meta.env.VITE_GOOGLE_REDIRECT_URI
(redirectUri) at the start of loginWithCode and abort early (return or throw)
with a clear error if missing, before calling
apiRequest.post('/api/v3/auth/google', { code, uri: redirectUri }); ensure the
guard is placed in the loginWithCode function so the request never proceeds when
redirectUri is falsy.

---

Nitpick comments:
In `@turbo.json`:
- Around line 11-20: The "build:dev" and "build:prod" entries in turbo.json
duplicate the same "dependsOn", "inputs", and "outputs"; extract these shared
settings into a single reusable pipeline entry (e.g., "build:base" or
"build:common") and have "build:dev" and "build:prod" reference or extend that
shared entry (or depend on it) to avoid duplication; update the "build:dev" and
"build:prod" definitions to keep only environment-specific differences and point
to the shared config so future changes to "dependsOn", "inputs", or "outputs"
only need to be made in one place.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: be0e47d2-f34b-4c0c-b970-7ef103054f1f

📥 Commits

Reviewing files that changed from the base of the PR and between 06cc804 and d5def08.

📒 Files selected for processing (12)
  • apps/client/src/pages/onBoarding/GoogleCallback.tsx
  • apps/client/src/shared/utils/handleGoogleLogin.ts
  • apps/extension/.gitignore
  • apps/extension/manifest.json
  • apps/extension/package.json
  • apps/extension/src/background.ts
  • apps/extension/src/content.ts
  • apps/extension/src/pages/LogOutPop.tsx
  • apps/extension/src/vite-env.d.ts
  • apps/extension/vite.config.ts
  • package.json
  • turbo.json

@constantly-dev constantly-dev merged commit a122099 into develop Mar 19, 2026
9 checks passed
Copy link
Collaborator

@jjangminii jjangminii left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

환경 변수 주입과 통신 플로우가 복잡하다고 생각했는데 각 환경에 맞게 깔끔하게 정리해주셨네요,, 확실히 확장프로그램도 dev와 prod 둘다 띄어두고 작업할 수 있는게 너무 기대되네요 -! 수고하셨습니다-!!

"dev": "vite",
"build": "tsc -b && vite build",
"dev": "vite --mode development",
"build": "pnpm build:prod",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

build가 10 번쨰 줄 build:prod와 다를게 없는거 같은데 중복되어 있는 이유가 있나요?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feat 기능 개발하라 개발 달려라 달려

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat] extension send token (chrome storage) dev/prod 환경 분리

2 participants