Skip to content

fix: 게스트 인증 플로우 버그 2건 수정 + 관련 UX 개선#291

Merged
iOdiO89 merged 18 commits into
devfrom
fix/290-auth
Jul 5, 2026
Merged

fix: 게스트 인증 플로우 버그 2건 수정 + 관련 UX 개선#291
iOdiO89 merged 18 commits into
devfrom
fix/290-auth

Conversation

@iOdiO89

@iOdiO89 iOdiO89 commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

작업 요약

비회원(게스트) 인증 플로우 버그 수정 + 앱(웹뷰) 토큰 처리 보강 + 관련 UX 개선.

작업 내용

버그 수정

1. 게스트 자동 로그인 시 첫 요청에 토큰 미주입 → 500

  • proxy.tshandleGuestLogin이 발급받은 게스트 토큰을 set-cookie(다음 요청용)에만 넣고 현재 요청 헤더엔 주입하지 않아 그 렌더가 토큰 없이 진행 → getMe 401 → 페이지 500.
  • handleTokenRefresh와 동일하게 게스트 쿠키를 현재 요청 헤더에 주입하도록 수정.

2. 게스트가 MEMBER_ONLY 접근 시 archive ↔ login 무한 루프

  • 기존 로그인 페이지가 "유효 토큰이면" 무조건 redirect → 게스트(유효 토큰 보유)도 되돌려져 무한 루프.
  • 로그인 페이지에서 게스트를 리다이렉트하지 않도록 정리. 멤버 리다이렉트는 layout이 identityType으로 처리하므로 page에서는 중복 로직 제거.

3. proxy가 앱(웹뷰) 토큰을 처리 못 해 딥링크 진입 시 401

  • 백엔드는 토큰을 web엔 Set-Cookie, 앱(X-Client-Type: app)엔 응답 body로 내려줌. 그런데 proxy의 handleGuestLogin/handleTokenRefreshset-cookie 헤더만 읽어, 앱은 갱신/발급된 토큰이 요청·쿠키에 반영되지 않아 getMe 401.
  • isWebview(UA)로 분기 — 앱이면 응답 body 토큰을 현재 요청 쿠키맵 + 응답 Set-Cookie에 반영.

4. 앱 부팅 시 죽은 refresh 토큰으로 갱신 실패 → 로그인 튕김

  • 토큰 rotation으로 새 토큰이 발급될 때 앱 SecureStore가 갱신되지 않으면, 이미 소비된(죽은) 토큰이 남아 딥링크 진입 시 refresh 실패.
  • 앱 부팅 시(웹뷰 로드 전) 네이티브 refresh로 SecureStore를 최신 토큰으로 동기화. 401(죽은 토큰)이면 정리, 네트워크 등 일시적 실패면 기존 토큰 유지(스퓨리어스 로그아웃 방지).
  • share extension의 토큰 갱신도 공유 postTokenRefresh로 통일.

관련 개선

  • 게스트 세션 재사용: "비회원으로 시작하기" 클릭 시 살아있는 게스트 세션이 있으면 새로 발급하지 않고 토큰만 refresh (게스트 데이터 유지). 세션 판단은 httpOnly 때문에 서버(page)에서 identityType으로 확인 후 prop 전달.
  • MEMBER_ONLY 폴백: 게스트 로그인 후 redirect 타겟이 회원 전용 경로(예: /archive)면 /home?action=member-only로 보내고, 홈 도착 시 useQueryAction으로 안내 토스트 노출.
  • 로그인 약관 문구 분리: 정적 콘텐츠라 LoginButtons(client)에서 page(RSC)로 이동.
  • 토스트 폭/위치: sonner가 ≤600px에서 토스터를 width:100%로 강제해 컨텐츠(480px)를 넘치던 문제를, Toaster style(인라인)로 폭 제한 + 중앙 정렬해 보정.

🧭 설계 의도 (리뷰 참고)

  • proxy: 세션 유지·체크 담당 (토큰 유효성 / refresh / 게스트 자동 발급, 앱·웹 토큰 전달 형식 차이 흡수). role(권한)은 보지 않음.
  • layout: 권한 검증 담당 (identityType 기반 회원 전용 가드).

→ proxy의 MEMBER_ONLY 분기가 게스트를 토큰 유효성만으로 통과시키는 건 의도된 동작입니다. 권한 차단은 layout이 맡습니다.

스크린샷

2026-06-30.1.46.53.mov

연관 이슈

closes #290

Summary by CodeRabbit

  • New Features

    • 로그인 후 게스트 세션을 이어서 사용할 수 있는 흐름이 추가되었습니다.
    • 홈에서 회원만 이용 가능한 기능을 눌렀을 때 안내 토스트가 표시됩니다.
  • Bug Fixes

    • 로그인/쿠키 동기화 시 토큰 갱신이 더 안정적으로 처리되도록 개선되었습니다.
    • 토큰 갱신이 실패하면 세션 정리가 더 일관되게 동작합니다.
    • 토스트 위치와 크기가 조정되어 화면 하단 UI와 겹침이 줄었습니다.

@iOdiO89 iOdiO89 self-assigned this Jun 30, 2026
@iOdiO89 iOdiO89 added fix Something isn't working WEB labels Jun 30, 2026
@vercel

vercel Bot commented Jun 30, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
depromeet Ready Ready Preview, Comment Jul 5, 2026 11:13pm

@github-actions
github-actions Bot requested review from soyeong0115 and ychany June 30, 2026 04:50
@github-actions

Copy link
Copy Markdown

No description provided.

@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: dc9feade-87f8-4431-8ead-54d579a264fb

📥 Commits

Reviewing files that changed from the base of the PR and between e1c0df4 and 43ed800.

📒 Files selected for processing (4)
  • apps/app/utils/postWishLinkFromShare.ts
  • apps/web/src/app/login/_components/LoginButtons.tsx
  • apps/web/src/app/login/_hooks/usePostGuestLogin.ts
  • apps/web/src/utils/loginRedirect.ts

📝 Walkthrough

Walkthrough

앱의 토큰 갱신을 postTokenRefresh 공통 API로 통합해 웹뷰 쿠키 동기화와 공유 위시 등록에 반영했고, 웹에서는 프록시의 게스트 로그인/토큰 갱신 시 요청 쿠키 재주입 로직, 로그인 페이지의 게스트 세션 재사용 판단, 로그인 후 리다이렉트 경로(MEMBER_ONLY 분기), 회원 전용 토스트, 토스트 컨테이너 스타일을 함께 변경했다.

Changes

토큰 갱신과 웹 인증 흐름

Layer / File(s) Summary
앱 토큰 갱신 공통화
apps/app/apis/postTokenRefresh.ts, apps/app/hooks/useWebviewCookieSync.ts, apps/app/utils/postWishLinkFromShare.ts
공통 postTokenRefresh API가 5초 타임아웃과 AbortController를 사용해 추가되었고, 웹뷰 쿠키 동기화와 위시 공유 재시도 흐름이 이 API의 data.access_token/refresh_token 응답을 사용하도록 변경됨.
프록시 쿠키 재주입
apps/web/src/proxy.ts
handleGuestLoginNextRequest를 받아 발급된 토큰을 현재 요청 쿠키에 병합·재주입하고, handleTokenRefresh가 사용자 에이전트로 앱/웹을 분기해 응답 body 또는 set-cookie를 파싱해 쿠키 맵과 요청 헤더를 갱신함.
웹 인증 재사용과 안내
apps/web/src/app/login/page.tsx, apps/web/src/app/login/_components/LoginButtons.tsx, apps/web/src/app/login/_hooks/usePostGuestLogin.ts, apps/web/src/utils/loginRedirect.ts, apps/web/src/consts/queryAction.ts, apps/web/src/app/home/*, apps/web/src/components/toast/index.tsx
LoginPagegetMe로 게스트 세션 재사용 가능 여부를 계산해 LoginButtons에 전달하고, canReuseGuestSession이면 refreshClientToken을 먼저 시도한 뒤 실패 시 게스트 로그인으로 폴백함. 로그인 후 이동 경로는 getPostLoginRedirectPath로 MEMBER_ONLY 여부에 따라 홈+토스트 쿼리 또는 원경로로 분기되고, 홈 페이지에 MemberOnlyToast가 추가되며 토스트 컨테이너 오프셋/폭 스타일이 조정됨.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

Suggested reviewers: soyeong0115

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed 게스트 요청 쿠키 주입과 MEMBER_ONLY 루프 방지용 로그인 분기 수정이 #290의 두 핵심 요구사항과 맞습니다.
Out of Scope Changes check ✅ Passed 토스트, 로그인 문구, 앱 토큰 동기화, 프록시 보강은 모두 PR의 인증/UX 개선 목표와 직접 연관됩니다.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 게스트 인증 플로우 버그 수정과 관련 UX 개선이라는 핵심 변경을 정확히 요약합니다.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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.

@iOdiO89 iOdiO89 changed the title Fix/290 auth fix: 게스트 인증 플로우 버그 2건 수정 + 관련 UX 개선 Jun 30, 2026
@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{}

1 similar comment
@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{}

@iOdiO89

iOdiO89 commented Jun 30, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

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

⚠️ Outside diff range comments (1)
apps/app/utils/postWishLinkFromShare.ts (1)

38-38: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

갱신 401에서는 저장된 토큰도 정리해 주세요.

공유 링크 등록 경로는 refresh token이 만료되어도 TokenStorage를 그대로 둡니다. 이후 재시도마다 stale access/refresh token으로 같은 실패를 반복할 수 있어, useWebviewCookieSync와 동일하게 401에서 정리하는 편이 안전합니다.

수정 예시
-      if (!refreshResponse.ok) return { ok: false, message: '로그인이 만료됐어요' };
+      if (!refreshResponse.ok) {
+        if (refreshResponse.status === 401) await TokenStorage.clearTokens();
+
+        return { ok: false, message: '로그인이 만료됐어요' };
+      }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/app/utils/postWishLinkFromShare.ts` at line 38, The refresh failure path
in postWishLinkFromShare currently returns the expired-login message without
clearing persisted auth state, which can leave stale tokens behind. Update the
refresh handling in postWishLinkFromShare so that when refreshResponse.ok is
false and the status is 401, it also clears the saved TokenStorage, matching the
cleanup behavior used by useWebviewCookieSync. Keep the existing error return,
but ensure the token cleanup happens before returning.
🧹 Nitpick comments (3)
apps/web/src/app/login/_hooks/usePostGuestLogin.ts (2)

20-29: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

TanStack Query 콜백의 data 이름을 도메인 기준으로 맞춰 주세요.

여기서는 data보다 guestLoginData처럼 구체적인 이름이 가이드와 일치하고, 아래 토큰/리다이렉트 처리의 대상도 더 바로 읽힙니다. As per coding guidelines "In TanStack Query hooks, rename data to {domain}Data".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/app/login/_hooks/usePostGuestLogin.ts` around lines 20 - 29, In
usePostGuestLogin’s TanStack Query onSuccess callback, rename the generic data
parameter to a domain-specific name like guestLoginData to match the coding
guideline. Update all references in this callback, including the accessToken and
refreshToken checks, cookie writes, and WebBridge.postMessage payload, so the
flow reads clearly and stays consistent with the hook’s purpose.

Source: Coding guidelines


32-40: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

MEMBER_ONLY fallback 분기를 공용 helper로 묶어 두는 편이 안전합니다.

같은 redirectPath → isMemberOnly → home/action 분기가 apps/web/src/app/login/_components/LoginButtons.tsx에도 한 번 더 들어가 있어서, 이후 한쪽만 수정되면 게스트 세션 재사용 경로와 신규 발급 경로의 이동 규칙이 쉽게 어긋납니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/app/login/_hooks/usePostGuestLogin.ts` around lines 32 - 40, The
MEMBER_ONLY redirect fallback logic is duplicated in usePostGuestLogin and
LoginButtons, so extract the shared redirectPath/isMemberOnly/home-with-action
decision into a common helper and use it from both places. Keep the helper
responsible for normalizing the path, checking getRouteType, and returning
either ROUTES.HOME with QUERY_ACTION.MEMBER_ONLY or the original redirectPath so
both guest-session reuse and new-login flows stay consistent.
apps/web/src/app/home/page.tsx (1)

8-8: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

apps/web/src 아래에서는 상대 경로 import를 피해주세요.

새로 추가한 import도 @/* 절대 경로로 맞춰 두는 편이 이 경로 규칙과 일관되고, 이후 파일 이동 시에도 덜 깨집니다. As per coding guidelines "Use absolute path alias @/* for imports instead of relative paths".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/app/home/page.tsx` at line 8, The new import in the page
component violates the project’s path rule by using a relative path; update the
import in the home page module to use the `@/*` alias instead of
`./_components/MemberOnlyToast`. Keep the change localized to the `page.tsx`
import statement and ensure any similar imports in this area follow the same
absolute-path convention.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/app/apis/postTokenRefresh.ts`:
- Around line 2-10: The token refresh request in postTokenRefresh currently has
no timeout, so a stalled network can block useWebviewCookieSync from reaching
setIsSynced(true) and keep Page from rendering WebView. Update postTokenRefresh
to use an AbortController with a bounded timeout for the fetch call, and make
sure the caller can handle abort/timeout errors cleanly so the sync flow can
fail fast instead of hanging.

In `@apps/app/hooks/useWebviewCookieSync.ts`:
- Line 5: The import in useWebviewCookieSync cannot be resolved by static
analysis because the `@/apis/postTokenRefresh` alias is not available here. Update
the import in useWebviewCookieSync to use a path that resolves from this file,
preferably a relative path to postTokenRefresh, so the lint/import resolution
error is removed.
- Around line 38-43: 401 처리 분기에서 TokenStorage.clearTokens()만 호출하지 말고 WebView 쿠키도
함께 정리하도록 useWebviewCookieSync의 401 경로를 수정하세요. access_token과 refresh_token이 쿠키에
남지 않도록, 같은 분기에서 쿠키 삭제 로직을 추가해 SecureStore와 WebView 상태가 동시에 초기화되게 하십시오. 관련 위치는
useWebviewCookieSync와 401 응답을 처리하는 refreshResponse.status 분기입니다.

In `@apps/app/utils/postWishLinkFromShare.ts`:
- Line 1: The import in postWishLinkFromShare.ts uses an alias path that the
linter cannot resolve. Update the postTokenRefresh import in this file to use a
resolvable path, either by fixing the app alias configuration for apps/app or by
switching to the appropriate relative path so the symbol postTokenRefresh can be
resolved cleanly.

In `@apps/web/src/app/login/page.tsx`:
- Around line 1-6: The login page currently only checks whether the guest query
should be reused, so already-authenticated MEMBER users can still see the login
screen. Update the logic in the login page component around the
getMe/getQueryClient flow to restore an explicit MEMBER-only branch and trigger
an immediate redirect via ROUTES when the current user is a MEMBER, while
keeping the existing GUEST reuse behavior unchanged.

---

Outside diff comments:
In `@apps/app/utils/postWishLinkFromShare.ts`:
- Line 38: The refresh failure path in postWishLinkFromShare currently returns
the expired-login message without clearing persisted auth state, which can leave
stale tokens behind. Update the refresh handling in postWishLinkFromShare so
that when refreshResponse.ok is false and the status is 401, it also clears the
saved TokenStorage, matching the cleanup behavior used by useWebviewCookieSync.
Keep the existing error return, but ensure the token cleanup happens before
returning.

---

Nitpick comments:
In `@apps/web/src/app/home/page.tsx`:
- Line 8: The new import in the page component violates the project’s path rule
by using a relative path; update the import in the home page module to use the
`@/*` alias instead of `./_components/MemberOnlyToast`. Keep the change
localized to the `page.tsx` import statement and ensure any similar imports in
this area follow the same absolute-path convention.

In `@apps/web/src/app/login/_hooks/usePostGuestLogin.ts`:
- Around line 20-29: In usePostGuestLogin’s TanStack Query onSuccess callback,
rename the generic data parameter to a domain-specific name like guestLoginData
to match the coding guideline. Update all references in this callback, including
the accessToken and refreshToken checks, cookie writes, and
WebBridge.postMessage payload, so the flow reads clearly and stays consistent
with the hook’s purpose.
- Around line 32-40: The MEMBER_ONLY redirect fallback logic is duplicated in
usePostGuestLogin and LoginButtons, so extract the shared
redirectPath/isMemberOnly/home-with-action decision into a common helper and use
it from both places. Keep the helper responsible for normalizing the path,
checking getRouteType, and returning either ROUTES.HOME with
QUERY_ACTION.MEMBER_ONLY or the original redirectPath so both guest-session
reuse and new-login flows stay consistent.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: ef238d48-640a-47ec-8f80-5a07b3d232c2

📥 Commits

Reviewing files that changed from the base of the PR and between c1dd8f9 and 7891945.

📒 Files selected for processing (11)
  • apps/app/apis/postTokenRefresh.ts
  • apps/app/hooks/useWebviewCookieSync.ts
  • apps/app/utils/postWishLinkFromShare.ts
  • apps/web/src/app/home/_components/MemberOnlyToast.tsx
  • apps/web/src/app/home/page.tsx
  • apps/web/src/app/login/_components/LoginButtons.tsx
  • apps/web/src/app/login/_hooks/usePostGuestLogin.ts
  • apps/web/src/app/login/page.tsx
  • apps/web/src/components/toast/index.tsx
  • apps/web/src/consts/queryAction.ts
  • apps/web/src/proxy.ts

Comment thread apps/app/apis/postTokenRefresh.ts Outdated
Comment thread apps/app/hooks/useWebviewCookieSync.ts
Comment thread apps/app/hooks/useWebviewCookieSync.ts
Comment thread apps/app/utils/postWishLinkFromShare.ts
Comment thread apps/web/src/app/login/page.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
apps/web/src/proxy.ts (1)

8-8: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

isWebview import를 절대 경로로 바꿔주세요.

apps/web/src 하위 파일은 @/* alias를 사용해야 합니다.

수정 예시
-import { isWebview } from './utils/webBridge';
+import { isWebview } from '`@/utils/webBridge`';

As per coding guidelines, apps/web/src/**/*.{ts,tsx}: Use absolute path alias @/* for imports instead of relative paths.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/proxy.ts` at line 8, The import in proxy.ts uses a relative path
for isWebview instead of the required `@/`* alias. Update the import in the proxy
module to use the absolute alias path for isWebview, following the same pattern
used throughout apps/web/src, and keep the rest of the file unchanged.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/app/apis/postTokenRefresh.ts`:
- Around line 4-17: postTokenRefresh currently returns the raw fetch Response,
but app callers like useWebviewCookieSync and postWishLinkFromShare expect
accessToken/refreshToken while the refresh API actually returns
access_token/refresh_token. Normalize the response contract in postTokenRefresh
by parsing the JSON and mapping the snake_case keys to the camelCase shape used
by the app, or export a shared snake_case type and update all call sites to use
the same contract. Keep the fix centered around postTokenRefresh and the
consuming hooks/utils so token storage and retry logic always read the correct
fields.

In `@apps/web/src/proxy.ts`:
- Around line 47-50: The `access_token` and `refresh_token` cookies in
`proxy.ts` are being set without `HttpOnly`, so update the cookie construction
used in the `bodyAccess`/`bodyRefresh` branch to include `HttpOnly` in the
shared `cookieOptions`. Make the same change anywhere else the same cookie
pattern is used in this file (including the later matching block mentioned in
the comment) so both tokens are consistently protected.

---

Nitpick comments:
In `@apps/web/src/proxy.ts`:
- Line 8: The import in proxy.ts uses a relative path for isWebview instead of
the required `@/`* alias. Update the import in the proxy module to use the
absolute alias path for isWebview, following the same pattern used throughout
apps/web/src, and keep the rest of the file unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 0ee3788d-1926-4aed-ac08-db620a78c71d

📥 Commits

Reviewing files that changed from the base of the PR and between 7891945 and 0bd3216.

📒 Files selected for processing (2)
  • apps/app/apis/postTokenRefresh.ts
  • apps/web/src/proxy.ts

Comment thread apps/app/apis/postTokenRefresh.ts
Comment thread apps/web/src/proxy.ts
Comment on lines +33 to +41
const redirectPath = getLoginRedirectPath();
const isMemberOnly =
getRouteType(redirectPath.split('?')[0] ?? redirectPath) === 'MEMBER_ONLY';

router.replace(
isMemberOnly
? `${ROUTES.HOME}?${QUERY_ACTION.KEY}=${QUERY_ACTION.VALUE.MEMBER_ONLY}`
: redirectPath
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LoginButtons.tsx와 겹치는 부분인듯 헬퍼 유틸로 따로 추출해도 될듯

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

중복되는 곳이 2곳이라 공통화할지말지 고민하다가 안했었당
getPostLoginRedirectPath 로 추출 완료!

Comment thread apps/app/utils/postWishLinkFromShare.ts Outdated
Comment on lines 34 to 38
@@ -47,12 +39,12 @@ export const postWishLinkFromShare = async (

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

useWebviewCookieSync 는 401 시 clearTokens 하는데 이쪽은 안 함. Share Extension 이 재시도할 때마다 계속 죽은 토큰으로 시도.

제안: refreshResponse.status === 401 일때, TokenStorage.clearTokens() 추가

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

놓쳤던 부분 ~ 땡큐 수정했어

      if (!refreshResponse.ok) {
        /** 죽은 토큰으로 재시도가 반복되지 않도록 정리 */
        if (refreshResponse.status === 401) await TokenStorage.clearTokens();
        return { ok: false, message: '로그인이 만료됐어요' };
      }

Comment on lines +17 to +21
/** 게스트 세션 재활용 가능 여부 판단 */
const user = await getQueryClient()
.fetchQuery({ queryKey: ['me'], queryFn: getMe })
.catch(() => null);
const canReuseGuestSession = user?.identityType === 'GUEST';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

나중에 후속으로 서버에러에 대한 분기가 있으면 좋을듯

'axios status 로 401 vs network/5xx 구분해서 network 실패는 클릭 시점에 재확인, 또는 백엔드에 identityType 전용 lightweight 엔드포인트 요청.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

이건 작업 범위가 커질듯하여 후속으로 필요할 때 하겠음 ~!

iOdiO89 added 2 commits July 3, 2026 16:58
- 로그인 성공 후 경로 계산 중복 제거 (getPostLoginRedirectPath)
Share Extension이 만료된 토큰으로 재시도를 반복하지 않도록 refresh 401 시 clearTokens 호출
@iOdiO89
iOdiO89 merged commit b5dc6db into dev Jul 5, 2026
4 of 5 checks passed
@iOdiO89
iOdiO89 deleted the fix/290-auth branch July 5, 2026 23:15
iOdiO89 added a commit that referenced this pull request Jul 6, 2026
* fix: 게스트 MEMBER_ONLY 접근 시 로그인 무한 루프 수정

회원(MEMBER) 토큰일 때만 로그인 페이지를 건너뛰도록 제한.
게스트는 로그인에 남아 archive↔login 무한 루프 방지.

* fix: 게스트 자동 로그인 시 현재 요청부터 token 적용되도록 수정

* refactor: 로그인 약관 안내 문구를 page로 분리

* feat: 게스트 세션 살아있는 경우 게스트 로그인 선택 시 리프레시 진행

* style: 토스트 위치 오류 수정

* feat: 게스트 로그인 redirect path가 /archive인 경우 /home으로 이동 및 안내 토스트 노출

* fix: 앱 부팅 시 refresh cookie 죽는 문제 해결

* fix: proxy에서 앱 auth token 도 처리 가능하도록 수정

* refactor: 앱 token refresh timeout 추가

* fix: 앱 토큰 만료(401) 시 WebView 쿠키도 정리

* fix: 앱 refresh 응답 snake_case 파싱 수정

* chore: proxy.ts refresh 401 임시 안전망 제거 (백엔드 rotation grace 적용) (#295)

* chore: proxy.ts refresh 401 임시 안전망 제거 (백엔드 rotation grace 적용) (#295)

* fix: iOS 26 Safari 노치 영역이 흰색으로 보이는 문제 수정 (#293)

Co-authored-by: Jung Sun A <amber0809@naver.com>

* refactor: 로그인 후 리다이렉트 로직 유틸로 추출

- 로그인 성공 후 경로 계산 중복 제거 (getPostLoginRedirectPath)

* fix: 공유 위시 등록 시 refresh 401이면 죽은 토큰 정리

Share Extension이 만료된 토큰으로 재시도를 반복하지 않도록 refresh 401 시 clearTokens 호출

---------

Co-authored-by: 조영찬 <tigerbone@naver.com>
iOdiO89 added a commit that referenced this pull request Jul 10, 2026
* fix: 게스트 MEMBER_ONLY 접근 시 로그인 무한 루프 수정

회원(MEMBER) 토큰일 때만 로그인 페이지를 건너뛰도록 제한.
게스트는 로그인에 남아 archive↔login 무한 루프 방지.

* fix: 게스트 자동 로그인 시 현재 요청부터 token 적용되도록 수정

* refactor: 로그인 약관 안내 문구를 page로 분리

* feat: 게스트 세션 살아있는 경우 게스트 로그인 선택 시 리프레시 진행

* style: 토스트 위치 오류 수정

* feat: 게스트 로그인 redirect path가 /archive인 경우 /home으로 이동 및 안내 토스트 노출

* fix: 앱 부팅 시 refresh cookie 죽는 문제 해결

* fix: proxy에서 앱 auth token 도 처리 가능하도록 수정

* refactor: 앱 token refresh timeout 추가

* fix: 앱 토큰 만료(401) 시 WebView 쿠키도 정리

* fix: 앱 refresh 응답 snake_case 파싱 수정

* chore: proxy.ts refresh 401 임시 안전망 제거 (백엔드 rotation grace 적용) (#295)

* chore: proxy.ts refresh 401 임시 안전망 제거 (백엔드 rotation grace 적용) (#295)

* fix: iOS 26 Safari 노치 영역이 흰색으로 보이는 문제 수정 (#293)

Co-authored-by: Jung Sun A <amber0809@naver.com>

* refactor: 로그인 후 리다이렉트 로직 유틸로 추출

- 로그인 성공 후 경로 계산 중복 제거 (getPostLoginRedirectPath)

* fix: 공유 위시 등록 시 refresh 401이면 죽은 토큰 정리

Share Extension이 만료된 토큰으로 재시도를 반복하지 않도록 refresh 401 시 clearTokens 호출

---------

Co-authored-by: 조영찬 <tigerbone@naver.com>
iOdiO89 added a commit that referenced this pull request Jul 10, 2026
* docs: 역할 분배 문서 추가

* docs: 현재 api 에러 대응 현황 문서 추가

* docs: 에러 처리 정책 문서 추가

* feat: 공통 API 에러 메시지 유틸 추가

* feat: 전역 mutation/query 에러 안전망 도입

* refactor: 비어있는 개별 onError 삭제 (전역 안전망 위임)

* refactor: 개별 훅 5xx 토스트 분기 제거 (이중 토스트 방지)

* PR 봇을 Slack 에서 Discord 로 이관 (#308)

* chore: PR 봇을 Slack 에서 Discord 로 이관

slack-pr-bot.yml 제거 + discord-pr-bot.yml 추가 (서버 PIKI-Server 검증본 기반).
리뷰어 멘션(initial_reviewers + requested_reviewers)·연관 이슈(close #N) 로직 동일.

클라 slack 커밋 이력(#14·#17·#18·#20)을 추적해 서버와 다른 클라 특화를 반영:
- 트리거·부모 메시지 조건: ready_for_review → reopened (#17, 기존 slack 봇과 동일).
- 요약 파싱 섹션명: Task → 작업 요약 (클라 PR 템플릿이 '## 작업 요약'). 클라 slack 은 두 요약 함수의
  섹션명이 '작업 내용'/'작업 요약' 으로 불일치(#20 이 한쪽만 수정)해 부모 메시지 요약이 항상 비던 버그가
  있었는데, 이관본은 둘 다 '작업 요약' 으로 통일해 함께 고친다.
- 요약에서 중첩 리스트('  -') skip (#18).

alert-direct-push job 제외(클라 범위 밖). 배포는 클라가 Vercel 이라 이 이관 범위 밖.
secret(DISCORD_BOT_TOKEN 공유·DISCORD_PR_CHANNEL_ID 전용·DISCORD_USER_MAP) 설정 완료.

* PR 봇 부모 메시지 라벨을 갱신 메시지와 같은 볼드·대문자 서식으로 통일

부모(최초) 메시지는 '🔥 연관 이슈'·'**branch**' 처럼 볼드 없는 소문자였고
갱신 메시지는 '🔥 **연관 이슈**'·'**Branch**' 로 달라, 첫 갱신 때 라벨 서식이
바뀌어 보였다. 부모 쪽을 갱신 쪽 서식에 맞춰 일치시킨다.

* synchronize 알림의 커밋 수·최신 커밋을 페이지네이션에 견고하게 계산

PR 커밋 API 는 30개/페이지(오래된→최신 순)라 첫 페이지만 받아 length 로 세면
31개 이상 PR 에서 커밋 수가 30 으로 잘리고, 첫 페이지 .[-1] 도 최신 커밋이 아니었다.
커밋 수는 이벤트 payload 의 .pull_request.commits 로, 최신 커밋은 마지막 페이지
(per_page=1 & page=총개수)로 집어 정확하게 만든다.

* PR 봇 서버 개선 반영 (상태 리액션·부모 고정·스레드 정리·라벨·헬퍼 공유) (#310)

* PR 봇에 상태 리액션·부모 고정·스레드 정리·라벨 표시·헬퍼 공유 반영

이관 이후 서버 봇에 쌓인 개선을 클라 봇에 맞춰 반영한다.

- 상태 리액션: 부모 메시지에 열림/작업중/머지/종료를 이모지로 전환 표시(429 rate limit 재시도 포함)
- 부모 고정: 열린(리뷰 대기) PR 부모를 채널 상단에 고정, 종료 시 해제
- 스레드 정리: 종료 시 스레드명에 결과 프리픽스(✅/🗑️)+archive+lock
- 부모 카드에 라벨 표시(build_label_text)
- find_meta 가 메타 주석을 JSON 마커로 정확히 매칭 — 파일명을 언급한 리뷰 코멘트를
  집어 THREAD_ID 를 못 읽고 이후 스텝이 전부 skip 되던 버그(머지 알림 누락) 해소
- 헬퍼 4개를 $RUNNER_TEMP 공유 스크립트로 추출해 스텝 간 중복 제거(checkout 불필요)
- 커밋 수는 .pull_request.commits 로 정확화

클라 적응: push 트리거·alert-direct-push 잡 제외, ready_for_review→reopened,
작업 요약 섹션 매칭+중첩 불릿 스킵, 부모 카드 라벨 서식을 갱신 카드와 통일.
최신 커밋 메시지는 contents:read 없이 동작하도록 PR commits 엔드포인트로 조회.

* 재오픈된 PR 의 부모 재고정·스레드 복구 (reopened 흐름 정상화)

reopened 는 메타 주석이 이미 있어 post_parent 스텝이 스킵되는데, 부모 고정·상태
복구가 그 스텝 출력에만 의존해 재오픈 시 깨졌다. reopened 는 서버 봇엔 없고 클라
트리거라, 이 흐름 버그는 클라 전용이다.

- 부모 재고정: pin 스텝의 부모 id 를 post_parent → find_meta 로 폴백하고 조건도
  find_meta.message_id 를 포함하도록 넓혀, 재오픈 시 상단 고정이 복구되게 한다.
- 스레드 복구: 종료 시 archived·locked 로 잠그고 이름에 🗑️ 프리픽스를 다는데,
  재오픈 시 되돌리는 경로가 없어 이후 synchronize 답글이 잠긴 스레드라 실패했다.
  reopened 에 unarchive·unlock + 이름 원복 스텝을 추가한다.

* fix: 게스트 인증 플로우 버그 2건 수정 + 관련 UX 개선 (#291)

* fix: 게스트 MEMBER_ONLY 접근 시 로그인 무한 루프 수정

회원(MEMBER) 토큰일 때만 로그인 페이지를 건너뛰도록 제한.
게스트는 로그인에 남아 archive↔login 무한 루프 방지.

* fix: 게스트 자동 로그인 시 현재 요청부터 token 적용되도록 수정

* refactor: 로그인 약관 안내 문구를 page로 분리

* feat: 게스트 세션 살아있는 경우 게스트 로그인 선택 시 리프레시 진행

* style: 토스트 위치 오류 수정

* feat: 게스트 로그인 redirect path가 /archive인 경우 /home으로 이동 및 안내 토스트 노출

* fix: 앱 부팅 시 refresh cookie 죽는 문제 해결

* fix: proxy에서 앱 auth token 도 처리 가능하도록 수정

* refactor: 앱 token refresh timeout 추가

* fix: 앱 토큰 만료(401) 시 WebView 쿠키도 정리

* fix: 앱 refresh 응답 snake_case 파싱 수정

* chore: proxy.ts refresh 401 임시 안전망 제거 (백엔드 rotation grace 적용) (#295)

* chore: proxy.ts refresh 401 임시 안전망 제거 (백엔드 rotation grace 적용) (#295)

* fix: iOS 26 Safari 노치 영역이 흰색으로 보이는 문제 수정 (#293)

Co-authored-by: Jung Sun A <amber0809@naver.com>

* refactor: 로그인 후 리다이렉트 로직 유틸로 추출

- 로그인 성공 후 경로 계산 중복 제거 (getPostLoginRedirectPath)

* fix: 공유 위시 등록 시 refresh 401이면 죽은 토큰 정리

Share Extension이 만료된 토큰으로 재시도를 반복하지 않도록 refresh 401 시 clearTokens 호출

---------

Co-authored-by: 조영찬 <tigerbone@naver.com>

* feat: Sentry 에러 모니터링 도입 (#296)

* feat: web Sentry 에러 모니터링 도입

* feat: app Sentry 에러 모니터링 도입

* feat: web/app sentry 에러 로깅 규약 추가

- app: @sentry/react-native 셋업(_layout init+wrap, metro, 플러그인, eas 환경별 주입)
- 공용 captureError 유틸(web/app) — 태그/컨텍스트 일관 부착
- API 5xx·네트워크 에러 중앙 수집(axios 인터셉터 / app fetch)
- 유저 식별 setUser(id), 세션 만료 시 해제
- error.tsx 캡처, ignoreErrors 노이즈 필터
- app WebView onError/onHttpError, 백그라운드 FCM 핸들러 수집

* test: 에러 검증용 테스트 페이지 생성

* fix: SENTRY_AUTH_TOKEN turbo passThroughEnv 추가 (소스맵 업로드)

* feat: Session Replay 마스킹 완화 (이메일만 마스킹, 나머지 노출)

* feat: API 에러 리포트 제목을 'API {status} {method} {path}' 형식으로 개선

* Revert "test: 에러 검증용 테스트 페이지 생성"

This reverts commit 87f9e53.

* fix: 소셜 로그인 5xx 응답 JSON 파싱 실패 시 Sentry 수집 누락 수정

* fix: 로그아웃 시 Sentry 유저 컨텍스트 해제

* fix: Session Replay 타이핑 입력창만 마스킹 (maskAllInputs)

* fix: 소셜 로그인 2xx 응답 본문 파싱 실패도 Sentry 수집

* feat: mutation 오류 발생 시 Sentry 로깅 추가

* docs: 역할정리 수정

* docs: 역할 관련 문서 업데이트

---------

Co-authored-by: sevineleven <117634128+sevineleven@users.noreply.github.com>
Co-authored-by: 조영찬 <tigerbone@naver.com>
iOdiO89 added a commit that referenced this pull request Jul 11, 2026
* docs: 역할 분배 문서 추가

* docs: 현재 api 에러 대응 현황 문서 추가

* docs: 에러 처리 정책 문서 추가

* feat: 공통 API 에러 메시지 유틸 추가

* feat: 전역 mutation/query 에러 안전망 도입

* refactor: 비어있는 개별 onError 삭제 (전역 안전망 위임)

* refactor: 개별 훅 5xx 토스트 분기 제거 (이중 토스트 방지)

* PR 봇을 Slack 에서 Discord 로 이관 (#308)

* chore: PR 봇을 Slack 에서 Discord 로 이관

slack-pr-bot.yml 제거 + discord-pr-bot.yml 추가 (서버 PIKI-Server 검증본 기반).
리뷰어 멘션(initial_reviewers + requested_reviewers)·연관 이슈(close #N) 로직 동일.

클라 slack 커밋 이력(#14·#17·#18·#20)을 추적해 서버와 다른 클라 특화를 반영:
- 트리거·부모 메시지 조건: ready_for_review → reopened (#17, 기존 slack 봇과 동일).
- 요약 파싱 섹션명: Task → 작업 요약 (클라 PR 템플릿이 '## 작업 요약'). 클라 slack 은 두 요약 함수의
  섹션명이 '작업 내용'/'작업 요약' 으로 불일치(#20 이 한쪽만 수정)해 부모 메시지 요약이 항상 비던 버그가
  있었는데, 이관본은 둘 다 '작업 요약' 으로 통일해 함께 고친다.
- 요약에서 중첩 리스트('  -') skip (#18).

alert-direct-push job 제외(클라 범위 밖). 배포는 클라가 Vercel 이라 이 이관 범위 밖.
secret(DISCORD_BOT_TOKEN 공유·DISCORD_PR_CHANNEL_ID 전용·DISCORD_USER_MAP) 설정 완료.

* PR 봇 부모 메시지 라벨을 갱신 메시지와 같은 볼드·대문자 서식으로 통일

부모(최초) 메시지는 '🔥 연관 이슈'·'**branch**' 처럼 볼드 없는 소문자였고
갱신 메시지는 '🔥 **연관 이슈**'·'**Branch**' 로 달라, 첫 갱신 때 라벨 서식이
바뀌어 보였다. 부모 쪽을 갱신 쪽 서식에 맞춰 일치시킨다.

* synchronize 알림의 커밋 수·최신 커밋을 페이지네이션에 견고하게 계산

PR 커밋 API 는 30개/페이지(오래된→최신 순)라 첫 페이지만 받아 length 로 세면
31개 이상 PR 에서 커밋 수가 30 으로 잘리고, 첫 페이지 .[-1] 도 최신 커밋이 아니었다.
커밋 수는 이벤트 payload 의 .pull_request.commits 로, 최신 커밋은 마지막 페이지
(per_page=1 & page=총개수)로 집어 정확하게 만든다.

* PR 봇 서버 개선 반영 (상태 리액션·부모 고정·스레드 정리·라벨·헬퍼 공유) (#310)

* PR 봇에 상태 리액션·부모 고정·스레드 정리·라벨 표시·헬퍼 공유 반영

이관 이후 서버 봇에 쌓인 개선을 클라 봇에 맞춰 반영한다.

- 상태 리액션: 부모 메시지에 열림/작업중/머지/종료를 이모지로 전환 표시(429 rate limit 재시도 포함)
- 부모 고정: 열린(리뷰 대기) PR 부모를 채널 상단에 고정, 종료 시 해제
- 스레드 정리: 종료 시 스레드명에 결과 프리픽스(✅/🗑️)+archive+lock
- 부모 카드에 라벨 표시(build_label_text)
- find_meta 가 메타 주석을 JSON 마커로 정확히 매칭 — 파일명을 언급한 리뷰 코멘트를
  집어 THREAD_ID 를 못 읽고 이후 스텝이 전부 skip 되던 버그(머지 알림 누락) 해소
- 헬퍼 4개를 $RUNNER_TEMP 공유 스크립트로 추출해 스텝 간 중복 제거(checkout 불필요)
- 커밋 수는 .pull_request.commits 로 정확화

클라 적응: push 트리거·alert-direct-push 잡 제외, ready_for_review→reopened,
작업 요약 섹션 매칭+중첩 불릿 스킵, 부모 카드 라벨 서식을 갱신 카드와 통일.
최신 커밋 메시지는 contents:read 없이 동작하도록 PR commits 엔드포인트로 조회.

* 재오픈된 PR 의 부모 재고정·스레드 복구 (reopened 흐름 정상화)

reopened 는 메타 주석이 이미 있어 post_parent 스텝이 스킵되는데, 부모 고정·상태
복구가 그 스텝 출력에만 의존해 재오픈 시 깨졌다. reopened 는 서버 봇엔 없고 클라
트리거라, 이 흐름 버그는 클라 전용이다.

- 부모 재고정: pin 스텝의 부모 id 를 post_parent → find_meta 로 폴백하고 조건도
  find_meta.message_id 를 포함하도록 넓혀, 재오픈 시 상단 고정이 복구되게 한다.
- 스레드 복구: 종료 시 archived·locked 로 잠그고 이름에 🗑️ 프리픽스를 다는데,
  재오픈 시 되돌리는 경로가 없어 이후 synchronize 답글이 잠긴 스레드라 실패했다.
  reopened 에 unarchive·unlock + 이름 원복 스텝을 추가한다.

* fix: 게스트 인증 플로우 버그 2건 수정 + 관련 UX 개선 (#291)

* fix: 게스트 MEMBER_ONLY 접근 시 로그인 무한 루프 수정

회원(MEMBER) 토큰일 때만 로그인 페이지를 건너뛰도록 제한.
게스트는 로그인에 남아 archive↔login 무한 루프 방지.

* fix: 게스트 자동 로그인 시 현재 요청부터 token 적용되도록 수정

* refactor: 로그인 약관 안내 문구를 page로 분리

* feat: 게스트 세션 살아있는 경우 게스트 로그인 선택 시 리프레시 진행

* style: 토스트 위치 오류 수정

* feat: 게스트 로그인 redirect path가 /archive인 경우 /home으로 이동 및 안내 토스트 노출

* fix: 앱 부팅 시 refresh cookie 죽는 문제 해결

* fix: proxy에서 앱 auth token 도 처리 가능하도록 수정

* refactor: 앱 token refresh timeout 추가

* fix: 앱 토큰 만료(401) 시 WebView 쿠키도 정리

* fix: 앱 refresh 응답 snake_case 파싱 수정

* chore: proxy.ts refresh 401 임시 안전망 제거 (백엔드 rotation grace 적용) (#295)

* chore: proxy.ts refresh 401 임시 안전망 제거 (백엔드 rotation grace 적용) (#295)

* fix: iOS 26 Safari 노치 영역이 흰색으로 보이는 문제 수정 (#293)

Co-authored-by: Jung Sun A <amber0809@naver.com>

* refactor: 로그인 후 리다이렉트 로직 유틸로 추출

- 로그인 성공 후 경로 계산 중복 제거 (getPostLoginRedirectPath)

* fix: 공유 위시 등록 시 refresh 401이면 죽은 토큰 정리

Share Extension이 만료된 토큰으로 재시도를 반복하지 않도록 refresh 401 시 clearTokens 호출

---------

Co-authored-by: 조영찬 <tigerbone@naver.com>

* feat: Sentry 에러 모니터링 도입 (#296)

* feat: web Sentry 에러 모니터링 도입

* feat: app Sentry 에러 모니터링 도입

* feat: web/app sentry 에러 로깅 규약 추가

- app: @sentry/react-native 셋업(_layout init+wrap, metro, 플러그인, eas 환경별 주입)
- 공용 captureError 유틸(web/app) — 태그/컨텍스트 일관 부착
- API 5xx·네트워크 에러 중앙 수집(axios 인터셉터 / app fetch)
- 유저 식별 setUser(id), 세션 만료 시 해제
- error.tsx 캡처, ignoreErrors 노이즈 필터
- app WebView onError/onHttpError, 백그라운드 FCM 핸들러 수집

* test: 에러 검증용 테스트 페이지 생성

* fix: SENTRY_AUTH_TOKEN turbo passThroughEnv 추가 (소스맵 업로드)

* feat: Session Replay 마스킹 완화 (이메일만 마스킹, 나머지 노출)

* feat: API 에러 리포트 제목을 'API {status} {method} {path}' 형식으로 개선

* Revert "test: 에러 검증용 테스트 페이지 생성"

This reverts commit 87f9e53.

* fix: 소셜 로그인 5xx 응답 JSON 파싱 실패 시 Sentry 수집 누락 수정

* fix: 로그아웃 시 Sentry 유저 컨텍스트 해제

* fix: Session Replay 타이핑 입력창만 마스킹 (maskAllInputs)

* fix: 소셜 로그인 2xx 응답 본문 파싱 실패도 Sentry 수집

* feat: mutation 오류 발생 시 Sentry 로깅 추가

* docs: 역할정리 수정

* docs: 역할 관련 문서 업데이트

---------

Co-authored-by: sevineleven <117634128+sevineleven@users.noreply.github.com>
Co-authored-by: 조영찬 <tigerbone@naver.com>
iOdiO89 added a commit that referenced this pull request Jul 11, 2026
* chore: iOS Smart Banner 설정

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat: iOS Universal Link 설정 및 딥링크 라우팅 확장

- AASA 파일 추가 (콜백/api 경로는 exclude)
- iOS associatedDomains 설정
- Universal Link/Smart Banner app-argument의 https URL을 WebView 경로로 라우팅

* feat: android app link 관련 config 추가

* chore: proxy.ts refresh 401 임시 안전망 제거 (백엔드 rotation grace 적용) (#295)

* fix: iOS 26 Safari 노치 영역이 흰색으로 보이는 문제 수정 (#293)

Co-authored-by: Jung Sun A <amber0809@naver.com>

* PR 봇을 Slack 에서 Discord 로 이관 (#308)

* chore: PR 봇을 Slack 에서 Discord 로 이관

slack-pr-bot.yml 제거 + discord-pr-bot.yml 추가 (서버 PIKI-Server 검증본 기반).
리뷰어 멘션(initial_reviewers + requested_reviewers)·연관 이슈(close #N) 로직 동일.

클라 slack 커밋 이력(#14·#17·#18·#20)을 추적해 서버와 다른 클라 특화를 반영:
- 트리거·부모 메시지 조건: ready_for_review → reopened (#17, 기존 slack 봇과 동일).
- 요약 파싱 섹션명: Task → 작업 요약 (클라 PR 템플릿이 '## 작업 요약'). 클라 slack 은 두 요약 함수의
  섹션명이 '작업 내용'/'작업 요약' 으로 불일치(#20 이 한쪽만 수정)해 부모 메시지 요약이 항상 비던 버그가
  있었는데, 이관본은 둘 다 '작업 요약' 으로 통일해 함께 고친다.
- 요약에서 중첩 리스트('  -') skip (#18).

alert-direct-push job 제외(클라 범위 밖). 배포는 클라가 Vercel 이라 이 이관 범위 밖.
secret(DISCORD_BOT_TOKEN 공유·DISCORD_PR_CHANNEL_ID 전용·DISCORD_USER_MAP) 설정 완료.

* PR 봇 부모 메시지 라벨을 갱신 메시지와 같은 볼드·대문자 서식으로 통일

부모(최초) 메시지는 '🔥 연관 이슈'·'**branch**' 처럼 볼드 없는 소문자였고
갱신 메시지는 '🔥 **연관 이슈**'·'**Branch**' 로 달라, 첫 갱신 때 라벨 서식이
바뀌어 보였다. 부모 쪽을 갱신 쪽 서식에 맞춰 일치시킨다.

* synchronize 알림의 커밋 수·최신 커밋을 페이지네이션에 견고하게 계산

PR 커밋 API 는 30개/페이지(오래된→최신 순)라 첫 페이지만 받아 length 로 세면
31개 이상 PR 에서 커밋 수가 30 으로 잘리고, 첫 페이지 .[-1] 도 최신 커밋이 아니었다.
커밋 수는 이벤트 payload 의 .pull_request.commits 로, 최신 커밋은 마지막 페이지
(per_page=1 & page=총개수)로 집어 정확하게 만든다.

* PR 봇 서버 개선 반영 (상태 리액션·부모 고정·스레드 정리·라벨·헬퍼 공유) (#310)

* PR 봇에 상태 리액션·부모 고정·스레드 정리·라벨 표시·헬퍼 공유 반영

이관 이후 서버 봇에 쌓인 개선을 클라 봇에 맞춰 반영한다.

- 상태 리액션: 부모 메시지에 열림/작업중/머지/종료를 이모지로 전환 표시(429 rate limit 재시도 포함)
- 부모 고정: 열린(리뷰 대기) PR 부모를 채널 상단에 고정, 종료 시 해제
- 스레드 정리: 종료 시 스레드명에 결과 프리픽스(✅/🗑️)+archive+lock
- 부모 카드에 라벨 표시(build_label_text)
- find_meta 가 메타 주석을 JSON 마커로 정확히 매칭 — 파일명을 언급한 리뷰 코멘트를
  집어 THREAD_ID 를 못 읽고 이후 스텝이 전부 skip 되던 버그(머지 알림 누락) 해소
- 헬퍼 4개를 $RUNNER_TEMP 공유 스크립트로 추출해 스텝 간 중복 제거(checkout 불필요)
- 커밋 수는 .pull_request.commits 로 정확화

클라 적응: push 트리거·alert-direct-push 잡 제외, ready_for_review→reopened,
작업 요약 섹션 매칭+중첩 불릿 스킵, 부모 카드 라벨 서식을 갱신 카드와 통일.
최신 커밋 메시지는 contents:read 없이 동작하도록 PR commits 엔드포인트로 조회.

* 재오픈된 PR 의 부모 재고정·스레드 복구 (reopened 흐름 정상화)

reopened 는 메타 주석이 이미 있어 post_parent 스텝이 스킵되는데, 부모 고정·상태
복구가 그 스텝 출력에만 의존해 재오픈 시 깨졌다. reopened 는 서버 봇엔 없고 클라
트리거라, 이 흐름 버그는 클라 전용이다.

- 부모 재고정: pin 스텝의 부모 id 를 post_parent → find_meta 로 폴백하고 조건도
  find_meta.message_id 를 포함하도록 넓혀, 재오픈 시 상단 고정이 복구되게 한다.
- 스레드 복구: 종료 시 archived·locked 로 잠그고 이름에 🗑️ 프리픽스를 다는데,
  재오픈 시 되돌리는 경로가 없어 이후 synchronize 답글이 잠긴 스레드라 실패했다.
  reopened 에 unarchive·unlock + 이름 원복 스텝을 추가한다.

* fix: 게스트 인증 플로우 버그 2건 수정 + 관련 UX 개선 (#291)

* fix: 게스트 MEMBER_ONLY 접근 시 로그인 무한 루프 수정

회원(MEMBER) 토큰일 때만 로그인 페이지를 건너뛰도록 제한.
게스트는 로그인에 남아 archive↔login 무한 루프 방지.

* fix: 게스트 자동 로그인 시 현재 요청부터 token 적용되도록 수정

* refactor: 로그인 약관 안내 문구를 page로 분리

* feat: 게스트 세션 살아있는 경우 게스트 로그인 선택 시 리프레시 진행

* style: 토스트 위치 오류 수정

* feat: 게스트 로그인 redirect path가 /archive인 경우 /home으로 이동 및 안내 토스트 노출

* fix: 앱 부팅 시 refresh cookie 죽는 문제 해결

* fix: proxy에서 앱 auth token 도 처리 가능하도록 수정

* refactor: 앱 token refresh timeout 추가

* fix: 앱 토큰 만료(401) 시 WebView 쿠키도 정리

* fix: 앱 refresh 응답 snake_case 파싱 수정

* chore: proxy.ts refresh 401 임시 안전망 제거 (백엔드 rotation grace 적용) (#295)

* chore: proxy.ts refresh 401 임시 안전망 제거 (백엔드 rotation grace 적용) (#295)

* fix: iOS 26 Safari 노치 영역이 흰색으로 보이는 문제 수정 (#293)

Co-authored-by: Jung Sun A <amber0809@naver.com>

* refactor: 로그인 후 리다이렉트 로직 유틸로 추출

- 로그인 성공 후 경로 계산 중복 제거 (getPostLoginRedirectPath)

* fix: 공유 위시 등록 시 refresh 401이면 죽은 토큰 정리

Share Extension이 만료된 토큰으로 재시도를 반복하지 않도록 refresh 401 시 clearTokens 호출

---------

Co-authored-by: 조영찬 <tigerbone@naver.com>

* feat: Sentry 에러 모니터링 도입 (#296)

* feat: web Sentry 에러 모니터링 도입

* feat: app Sentry 에러 모니터링 도입

* feat: web/app sentry 에러 로깅 규약 추가

- app: @sentry/react-native 셋업(_layout init+wrap, metro, 플러그인, eas 환경별 주입)
- 공용 captureError 유틸(web/app) — 태그/컨텍스트 일관 부착
- API 5xx·네트워크 에러 중앙 수집(axios 인터셉터 / app fetch)
- 유저 식별 setUser(id), 세션 만료 시 해제
- error.tsx 캡처, ignoreErrors 노이즈 필터
- app WebView onError/onHttpError, 백그라운드 FCM 핸들러 수집

* test: 에러 검증용 테스트 페이지 생성

* fix: SENTRY_AUTH_TOKEN turbo passThroughEnv 추가 (소스맵 업로드)

* feat: Session Replay 마스킹 완화 (이메일만 마스킹, 나머지 노출)

* feat: API 에러 리포트 제목을 'API {status} {method} {path}' 형식으로 개선

* Revert "test: 에러 검증용 테스트 페이지 생성"

This reverts commit 87f9e53.

* fix: 소셜 로그인 5xx 응답 JSON 파싱 실패 시 Sentry 수집 누락 수정

* fix: 로그아웃 시 Sentry 유저 컨텍스트 해제

* fix: Session Replay 타이핑 입력창만 마스킹 (maskAllInputs)

* fix: 소셜 로그인 2xx 응답 본문 파싱 실패도 Sentry 수집

* fix: 페이지별 토스트 위치 커스터마이즈 (탭바 페이지 토스트 겹침 수정) (#309)

* feat: 토스트 offset 페이지별 override 메커니즘 추가

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: 홈 탭바 위로 토스트 위치 조정

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: 보관 페이지 하단 바 위로 토스트 위치 조정

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* chore: 토스트 offset 수치 조정

* refactor: 토스트 offset zustand 스토어를 CSS :has() 마커 방식으로 대체

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

* feat: 딥링크 전환 로딩 오버레이 추가

* feat: 앱 링크 접속시 warm start 기능 추가

* PR 봇 스레드를 팀 전원이 볼 수 있게 (스레드 멤버 자동 추가) (#313)

* PR 봇 스레드에 팀원 자동 추가로 팀 전원 사이드바 노출

Discord 공개 스레드는 멤버(생성자·초대·멘션된 사람)만 사이드바에 뜬다. 부모 카드가
작성자만 @멘션해 작성자만 자기 PR 스레드가 보이고 남의 스레드는 안 떴다.

- 스레드 생성 직후 DISCORD_USER_MAP 의 팀원 전원을 thread-members 로 추가해 새 PR
  스레드가 팀 전원 사이드바에 뜨게 한다(멘션과 달리 조용히 목록에만 올림).
- 이 변경 이전 열린 PR 스레드용으로 backfill-thread-members 잡을 추가한다
  (workflow_dispatch 수동 실행). notify-discord 는 pull_request 로 가드해 dispatch 시엔 안 돈다.

* 연관 이슈 링크의 Discord 임베드 카드 억제

부모 카드의 연관 이슈 링크가 GitHub 임베드 카드로 커지게 떠서 본문(작업 요약 등)을
아래로 밀어냈다. 이슈 URL 을 <> 로 감싸 임베드만 억제하고 클릭 링크는 유지한다.
PR 타이틀 링크는 그대로 둬 PR 카드는 계속 뜬다.

* 작업 요약 추출이 STAR 의 Task 섹션도 인식

FE 팀 PR 은 ## 작업 요약, 서버 STAR 로 쓴 PR 은 ## Task 를 쓴다. build_summary 가
작업 요약만 찾아 STAR PR 은 '요약 없음'이 됐다. 두 섹션명을 모두 인식하게 해
어느 관례로 쓰든 요약이 채워지게 한다.

* 작업 요약의 Task 섹션 인식 제거

FE 팀은 ## 작업 요약을 쓰고 봇이 이미 이를 매칭하므로, STAR 의 ## Task 인식 추가는
불필요해 되돌린다. 요약은 PR 본문에 ## 작업 요약 을 두는 팀 관례로 채운다.

* PR 봇 재싱크: 머지 스레드 잠금 해제 + 종합 백필 (서버 #703 반영) (#315)

서버 봇(#703)과 갈라진 두 가지를 클라에도 반영해 동작을 일치시킨다.

- 머지 시 close 정리에서 locked 제거(archived 만) — 닫히되 글을 쓸 수 있게(archived 만이라
  글을 쓰면 다시 열림). 머지된 PR 스레드가 잠겨 글을 못 쓰던 문제 해소.
- 백필 잡을 종합형(backfill-threads)으로 교체: 열린 PR→팀원 추가+열림, 머지 PR→✅+닫힘,
  미머지 닫힘→🗑️+닫힘. 기존엔 열린 스레드 팀원 추가만 했다. 과거 find_meta 버그로 안 닫힌
  스레드까지 소급 정리(멱등).

* refactor: 링크 입력창 모바일 키보드를 일반 텍스트 키보드로 변경 (#325)

* feat: 전역 API 에러 안전망 도입 및 개별 훅 에러 처리 정리 (#311)

* docs: 역할 분배 문서 추가

* docs: 현재 api 에러 대응 현황 문서 추가

* docs: 에러 처리 정책 문서 추가

* feat: 공통 API 에러 메시지 유틸 추가

* feat: 전역 mutation/query 에러 안전망 도입

* refactor: 비어있는 개별 onError 삭제 (전역 안전망 위임)

* refactor: 개별 훅 5xx 토스트 분기 제거 (이중 토스트 방지)

* PR 봇을 Slack 에서 Discord 로 이관 (#308)

* chore: PR 봇을 Slack 에서 Discord 로 이관

slack-pr-bot.yml 제거 + discord-pr-bot.yml 추가 (서버 PIKI-Server 검증본 기반).
리뷰어 멘션(initial_reviewers + requested_reviewers)·연관 이슈(close #N) 로직 동일.

클라 slack 커밋 이력(#14·#17·#18·#20)을 추적해 서버와 다른 클라 특화를 반영:
- 트리거·부모 메시지 조건: ready_for_review → reopened (#17, 기존 slack 봇과 동일).
- 요약 파싱 섹션명: Task → 작업 요약 (클라 PR 템플릿이 '## 작업 요약'). 클라 slack 은 두 요약 함수의
  섹션명이 '작업 내용'/'작업 요약' 으로 불일치(#20 이 한쪽만 수정)해 부모 메시지 요약이 항상 비던 버그가
  있었는데, 이관본은 둘 다 '작업 요약' 으로 통일해 함께 고친다.
- 요약에서 중첩 리스트('  -') skip (#18).

alert-direct-push job 제외(클라 범위 밖). 배포는 클라가 Vercel 이라 이 이관 범위 밖.
secret(DISCORD_BOT_TOKEN 공유·DISCORD_PR_CHANNEL_ID 전용·DISCORD_USER_MAP) 설정 완료.

* PR 봇 부모 메시지 라벨을 갱신 메시지와 같은 볼드·대문자 서식으로 통일

부모(최초) 메시지는 '🔥 연관 이슈'·'**branch**' 처럼 볼드 없는 소문자였고
갱신 메시지는 '🔥 **연관 이슈**'·'**Branch**' 로 달라, 첫 갱신 때 라벨 서식이
바뀌어 보였다. 부모 쪽을 갱신 쪽 서식에 맞춰 일치시킨다.

* synchronize 알림의 커밋 수·최신 커밋을 페이지네이션에 견고하게 계산

PR 커밋 API 는 30개/페이지(오래된→최신 순)라 첫 페이지만 받아 length 로 세면
31개 이상 PR 에서 커밋 수가 30 으로 잘리고, 첫 페이지 .[-1] 도 최신 커밋이 아니었다.
커밋 수는 이벤트 payload 의 .pull_request.commits 로, 최신 커밋은 마지막 페이지
(per_page=1 & page=총개수)로 집어 정확하게 만든다.

* PR 봇 서버 개선 반영 (상태 리액션·부모 고정·스레드 정리·라벨·헬퍼 공유) (#310)

* PR 봇에 상태 리액션·부모 고정·스레드 정리·라벨 표시·헬퍼 공유 반영

이관 이후 서버 봇에 쌓인 개선을 클라 봇에 맞춰 반영한다.

- 상태 리액션: 부모 메시지에 열림/작업중/머지/종료를 이모지로 전환 표시(429 rate limit 재시도 포함)
- 부모 고정: 열린(리뷰 대기) PR 부모를 채널 상단에 고정, 종료 시 해제
- 스레드 정리: 종료 시 스레드명에 결과 프리픽스(✅/🗑️)+archive+lock
- 부모 카드에 라벨 표시(build_label_text)
- find_meta 가 메타 주석을 JSON 마커로 정확히 매칭 — 파일명을 언급한 리뷰 코멘트를
  집어 THREAD_ID 를 못 읽고 이후 스텝이 전부 skip 되던 버그(머지 알림 누락) 해소
- 헬퍼 4개를 $RUNNER_TEMP 공유 스크립트로 추출해 스텝 간 중복 제거(checkout 불필요)
- 커밋 수는 .pull_request.commits 로 정확화

클라 적응: push 트리거·alert-direct-push 잡 제외, ready_for_review→reopened,
작업 요약 섹션 매칭+중첩 불릿 스킵, 부모 카드 라벨 서식을 갱신 카드와 통일.
최신 커밋 메시지는 contents:read 없이 동작하도록 PR commits 엔드포인트로 조회.

* 재오픈된 PR 의 부모 재고정·스레드 복구 (reopened 흐름 정상화)

reopened 는 메타 주석이 이미 있어 post_parent 스텝이 스킵되는데, 부모 고정·상태
복구가 그 스텝 출력에만 의존해 재오픈 시 깨졌다. reopened 는 서버 봇엔 없고 클라
트리거라, 이 흐름 버그는 클라 전용이다.

- 부모 재고정: pin 스텝의 부모 id 를 post_parent → find_meta 로 폴백하고 조건도
  find_meta.message_id 를 포함하도록 넓혀, 재오픈 시 상단 고정이 복구되게 한다.
- 스레드 복구: 종료 시 archived·locked 로 잠그고 이름에 🗑️ 프리픽스를 다는데,
  재오픈 시 되돌리는 경로가 없어 이후 synchronize 답글이 잠긴 스레드라 실패했다.
  reopened 에 unarchive·unlock + 이름 원복 스텝을 추가한다.

* fix: 게스트 인증 플로우 버그 2건 수정 + 관련 UX 개선 (#291)

* fix: 게스트 MEMBER_ONLY 접근 시 로그인 무한 루프 수정

회원(MEMBER) 토큰일 때만 로그인 페이지를 건너뛰도록 제한.
게스트는 로그인에 남아 archive↔login 무한 루프 방지.

* fix: 게스트 자동 로그인 시 현재 요청부터 token 적용되도록 수정

* refactor: 로그인 약관 안내 문구를 page로 분리

* feat: 게스트 세션 살아있는 경우 게스트 로그인 선택 시 리프레시 진행

* style: 토스트 위치 오류 수정

* feat: 게스트 로그인 redirect path가 /archive인 경우 /home으로 이동 및 안내 토스트 노출

* fix: 앱 부팅 시 refresh cookie 죽는 문제 해결

* fix: proxy에서 앱 auth token 도 처리 가능하도록 수정

* refactor: 앱 token refresh timeout 추가

* fix: 앱 토큰 만료(401) 시 WebView 쿠키도 정리

* fix: 앱 refresh 응답 snake_case 파싱 수정

* chore: proxy.ts refresh 401 임시 안전망 제거 (백엔드 rotation grace 적용) (#295)

* chore: proxy.ts refresh 401 임시 안전망 제거 (백엔드 rotation grace 적용) (#295)

* fix: iOS 26 Safari 노치 영역이 흰색으로 보이는 문제 수정 (#293)

Co-authored-by: Jung Sun A <amber0809@naver.com>

* refactor: 로그인 후 리다이렉트 로직 유틸로 추출

- 로그인 성공 후 경로 계산 중복 제거 (getPostLoginRedirectPath)

* fix: 공유 위시 등록 시 refresh 401이면 죽은 토큰 정리

Share Extension이 만료된 토큰으로 재시도를 반복하지 않도록 refresh 401 시 clearTokens 호출

---------

Co-authored-by: 조영찬 <tigerbone@naver.com>

* feat: Sentry 에러 모니터링 도입 (#296)

* feat: web Sentry 에러 모니터링 도입

* feat: app Sentry 에러 모니터링 도입

* feat: web/app sentry 에러 로깅 규약 추가

- app: @sentry/react-native 셋업(_layout init+wrap, metro, 플러그인, eas 환경별 주입)
- 공용 captureError 유틸(web/app) — 태그/컨텍스트 일관 부착
- API 5xx·네트워크 에러 중앙 수집(axios 인터셉터 / app fetch)
- 유저 식별 setUser(id), 세션 만료 시 해제
- error.tsx 캡처, ignoreErrors 노이즈 필터
- app WebView onError/onHttpError, 백그라운드 FCM 핸들러 수집

* test: 에러 검증용 테스트 페이지 생성

* fix: SENTRY_AUTH_TOKEN turbo passThroughEnv 추가 (소스맵 업로드)

* feat: Session Replay 마스킹 완화 (이메일만 마스킹, 나머지 노출)

* feat: API 에러 리포트 제목을 'API {status} {method} {path}' 형식으로 개선

* Revert "test: 에러 검증용 테스트 페이지 생성"

This reverts commit 87f9e53.

* fix: 소셜 로그인 5xx 응답 JSON 파싱 실패 시 Sentry 수집 누락 수정

* fix: 로그아웃 시 Sentry 유저 컨텍스트 해제

* fix: Session Replay 타이핑 입력창만 마스킹 (maskAllInputs)

* fix: 소셜 로그인 2xx 응답 본문 파싱 실패도 Sentry 수집

* feat: mutation 오류 발생 시 Sentry 로깅 추가

* docs: 역할정리 수정

* docs: 역할 관련 문서 업데이트

---------

Co-authored-by: sevineleven <117634128+sevineleven@users.noreply.github.com>
Co-authored-by: 조영찬 <tigerbone@naver.com>

* refactor: 게스트 참여 dead code 제거 (#321)

* refactor: 게스트 참여 dead code 제거

* refactor: 게스트 참여 dead code 제거 2

---------

Co-authored-by: Jung Sun A <amber0809@naver.com>

* chore: update app version

* chore: eas config 삭제

* refactor: 링크 입력 시 텍스트에서 URL 자동 추출 (#323)

* refactor: 링크 입력 시 텍스트에서 URL 자동 추출

* fix: URL 패턴 anchor 추가로 트레일링 텍스트 제출 방지

* fix: warm start 딥링크 보류 처리

* fix: 앱 내비게이션 타이머 갱신

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: 조영찬 <tigerbone@naver.com>
Co-authored-by: sevineleven <117634128+sevineleven@users.noreply.github.com>
Co-authored-by: kanghaeun <145974230+kanghaeun@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fix Something isn't working WEB

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: 비회원(게스트) 인증 플로우 버그 - 게스트 진입 시 500 / archive↔login 무한 루프

2 participants