Conversation
dev to main
dev to main
fix: 딥링크 접근 권한 허용 [To Main]
dev to main
fix: ask 전용 딥링크 파일 cloudflare 배포 설정 변경
Summary by CodeRabbit릴리스 노트
Walkthrough앱 딥링크 지원, 배포 패키지 구성 개선, 멤버 페이지 UI 업데이트를 추가합니다. Crew API 엔드포인트를 수정하고, 토큰 에러 처리 로직을 변경하며, 서버리스 함수로 AASA 및 Android App Links 설정을 제공합니다. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
|
🚀 프리뷰 배포 확인하기 🚀 |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In @.env.development:
- Line 14: Remove the trailing slash from NEXT_PUBLIC_CREW_API_URL so it matches
the other env vars (NEXT_PUBLIC_API_URL, NEXT_PUBLIC_AUTH_API_URL,
NEXT_PUBLIC_OPERATION_API_URL) and avoid double slashes when concatenating
endpoints; update the value for NEXT_PUBLIC_CREW_API_URL to not end with "/" and
ensure the file ends with a single newline (EOF newline) after the change.
In `@public/.well-known/apple-app-site-association`:
- Around line 1-13: Remove the dead static apple-app-site-association JSON file
and keep the dynamic handler instead: delete the static
apple-app-site-association file under your public assets so Cloudflare Pages
will route to the existing apple-app-site-association server function (the
function handler in apple-app-site-association.ts). Ensure the function remains
and explicitly sets the Content-Type header to "application/json" in its
response so clients receive the correct MIME type.
In `@src/api/index.ts`:
- Around line 98-101: The if condition incorrectly uses "if
(window.location.pathname === '/.well-known/apple-app-site-association' ||
'/.well-known/assetlinks.json')" which always evaluates true because the second
operand is a non-empty string; change the boolean check so both paths are
compared against window.location.pathname (i.e., window.location.pathname ===
'/.well-known/apple-app-site-association' || window.location.pathname ===
'/.well-known/assetlinks.json') so that Promise.reject(error) only runs when the
request path exactly matches one of those two well-known endpoints (affecting
the 401 handling logic that triggers token refresh).
🧹 Nitpick comments (1)
src/api/index.ts (1)
89-101: 딥링크 경로 허용 로직이 반복적입니다 — 배열 기반으로 리팩터링을 고려해 주세요.
/makers,/policy/person, 딥링크 경로 등 로그인 불필요 경로가 개별if문으로 나열되어 있습니다. 향후 경로 추가 시 실수(위의 버그처럼)가 발생하기 쉽습니다.♻️ 리팩터링 제안
if (status === 401) { - if (window.location.pathname === '/makers') { - // 메이커스 페이지는 로그인 필요 없음 - return Promise.reject(error); - } - if (window.location.pathname === '/policy/person') { - // 개인정보 처리방침 페이지는 로그인 필요 없음, 구글 정책상 오픈 - return Promise.reject(error); - } - // 에스크 문자를 통한 딥링크 접근을 위해 허용 - if (window.location.pathname === '/.well-known/apple-app-site-association' || window.location.pathname === '/.well-known/assetlinks.json') { - return Promise.reject(error); - } + const PUBLIC_PATHS = [ + '/makers', + '/policy/person', + '/.well-known/apple-app-site-association', + '/.well-known/assetlinks.json', + ]; + if (PUBLIC_PATHS.includes(window.location.pathname)) { + return Promise.reject(error); + }
| NEXT_PUBLIC_OPERATION_API_URL=https://operation.api.dev.sopt.org | ||
| NEXT_PUBLIC_AUTH_API_URL=https://auth.api.dev.sopt.org | ||
| NEXT_PUBLIC_CREW_API_URL=https://crew.api.dev.sopt.org No newline at end of file | ||
| NEXT_PUBLIC_CREW_API_URL=https://crew-api-dev.sopt.org/ No newline at end of file |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
rg -n "CREW_API_URL" --type=ts -C3Repository: sopt-makers/sopt-playground-frontend
Length of output: 1589
🏁 Script executed:
rg -n "crew-api" --type=ts -C3Repository: sopt-makers/sopt-playground-frontend
Length of output: 62
🏁 Script executed:
fd -type f -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" | head -20Repository: sopt-makers/sopt-playground-frontend
Length of output: 250
🏁 Script executed:
# Check .env.development file for EOF newline
if [ -f .env.development ]; then
echo "=== File content with cat -A (to show whitespace) ==="
cat -A .env.development | tail -3
echo ""
echo "=== Line count ==="
wc -l .env.development
fiRepository: sopt-makers/sopt-playground-frontend
Length of output: 350
🏁 Script executed:
# Find axios configuration and baseURL setup
rg -n "axiosCrewInstance|baseURL" --type=ts -C2Repository: sopt-makers/sopt-playground-frontend
Length of output: 4614
🏁 Script executed:
# Check other API URLs for consistency
cat .env.developmentRepository: sopt-makers/sopt-playground-frontend
Length of output: 746
🏁 Script executed:
# Search for how other endpoints use baseURL with paths
rg -n "axiosInstance\.(get|post|put|delete)" --type=ts -A1 | head -30Repository: sopt-makers/sopt-playground-frontend
Length of output: 2017
🏁 Script executed:
# Check if there's any axios configuration that normalizes URLs
rg -n "normalize|url|slash" src/api/index.tsRepository: sopt-makers/sopt-playground-frontend
Length of output: 62
Trailing slash를 제거하여 다른 API URL과 일관성을 맞추세요.
NEXT_PUBLIC_CREW_API_URL의 trailing slash는 API 엔드포인트(/internal/meeting/stats/likes 등)와 결합될 때 이중 슬래시(//)를 유발합니다. 다른 API URL들(NEXT_PUBLIC_API_URL, NEXT_PUBLIC_AUTH_API_URL, NEXT_PUBLIC_OPERATION_API_URL)은 모두 trailing slash가 없으므로 제거가 필요합니다.
🔧 수정 제안
-NEXT_PUBLIC_CREW_API_URL=https://crew-api-dev.sopt.org/
+NEXT_PUBLIC_CREW_API_URL=https://crew-api-dev.sopt.org파일 끝에 빈 줄을 추가하세요(EOF newline 규칙).
🧰 Tools
🪛 dotenv-linter (4.0.0)
[warning] 14-14: [EndingBlankLine] No blank line at the end of the file
(EndingBlankLine)
[warning] 14-14: [UnorderedKey] The NEXT_PUBLIC_CREW_API_URL key should go before the NEXT_PUBLIC_DEBUG key
(UnorderedKey)
🤖 Prompt for AI Agents
In @.env.development at line 14, Remove the trailing slash from
NEXT_PUBLIC_CREW_API_URL so it matches the other env vars (NEXT_PUBLIC_API_URL,
NEXT_PUBLIC_AUTH_API_URL, NEXT_PUBLIC_OPERATION_API_URL) and avoid double
slashes when concatenating endpoints; update the value for
NEXT_PUBLIC_CREW_API_URL to not end with "/" and ensure the file ends with a
single newline (EOF newline) after the change.
| { | ||
| "applinks": { | ||
| "apps": [], | ||
| "details": [ | ||
| { | ||
| "appID": "95YWTT5L8K.com.sopt-stamp-iOS.release", | ||
| "paths": [ | ||
| "*" | ||
| ] | ||
| } | ||
| ] | ||
| } | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Check if both files exist in the codebase
fd "apple-app-site-association" -t fRepository: sopt-makers/sopt-playground-frontend
Length of output: 62
🏁 Script executed:
# List files in the functions and public directories to understand structure
git ls-files | grep -E "(functions|public)" | grep -E "\.well-known|apple" | head -20Repository: sopt-makers/sopt-playground-frontend
Length of output: 253
🌐 Web query:
Cloudflare Pages functions routing priority static assets
💡 Result:
On Cloudflare Pages (Functions mode), routing generally works like this:
- Functions are checked first (based on your
/functionsfile-based routes). If a Function route matches the request, it runs; if no Function matches, Pages falls back to a static asset (if one exists); otherwise it uses the normal Pages static routing behavior (e.g., SPA/404 behavior depending on your setup). [1] - Route specificity matters for Functions: more specific routes win over less specific/wildcard (dynamic) routes. [1]
The key control: _routes.json (Function invocation vs static)
If your project has a functions/ directory, Pages will (by default) invoke Functions on requests unless you restrict invocation using _routes.json. To “prioritize static assets” (avoid invoking Functions for static paths), configure _routes.json:
include: paths that should invoke Functionsexclude: paths that should not invoke Functions (excludealways wins overinclude) [1]
So, to ensure static assets win for things like /assets/*, put them in exclude. [1]
If you’re using Advanced Mode (_worker.js)
In Advanced Mode, you must explicitly serve static assets from your Worker (typically by calling env.ASSETS.fetch(request) for non-dynamic paths), otherwise your static files won’t be returned. [2]
Related note (Pages vs Workers static assets defaults)
Cloudflare’s docs also highlight a conceptual difference when moving to Workers: Pages defaults to running Functions ahead of static assets (customizable via _routes.json), whereas Workers + static assets default to serving assets first unless configured otherwise. [3]
Sources: Cloudflare Pages routing + _routes.json docs [1], Advanced Mode docs [2], Workers static-assets compatibility notes re: Pages _routes.json behavior [3].
🏁 Script executed:
# Check if _routes.json exists
fd "_routes.json" -t fRepository: sopt-makers/sopt-playground-frontend
Length of output: 62
🏁 Script executed:
# Read both files to compare content
cat -n "public/.well-known/apple-app-site-association"Repository: sopt-makers/sopt-playground-frontend
Length of output: 350
🏁 Script executed:
# Read the TypeScript function
cat -n "functions/.well-known/apple-app-site-association.ts"Repository: sopt-makers/sopt-playground-frontend
Length of output: 584
정적 파일 public/.well-known/apple-app-site-association 제거 필요
functions/.well-known/apple-app-site-association.ts 함수가 존재하면, Cloudflare Pages는 기본적으로 함수를 먼저 실행하므로 정적 파일은 도달 불가능한 죽은 코드입니다. 두 파일의 내용이 동일하므로 정적 파일을 제거하고 함수만 유지하세요. (함수는 명시적 Content-Type 헤더 설정으로 더 안전합니다.)
🤖 Prompt for AI Agents
In `@public/.well-known/apple-app-site-association` around lines 1 - 13, Remove
the dead static apple-app-site-association JSON file and keep the dynamic
handler instead: delete the static apple-app-site-association file under your
public assets so Cloudflare Pages will route to the existing
apple-app-site-association server function (the function handler in
apple-app-site-association.ts). Ensure the function remains and explicitly sets
the Content-Type header to "application/json" in its response so clients receive
the correct MIME type.
| // 에스크 문자를 통한 딥링크 접근을 위해 허용 | ||
| if (window.location.pathname === '/.well-known/apple-app-site-association' || '/.well-known/assetlinks.json') { | ||
| return Promise.reject(error); | ||
| } |
There was a problem hiding this comment.
크리티컬 버그: 조건문이 항상 true로 평가되어 모든 401 응답에서 토큰 갱신이 실행되지 않습니다.
'/.well-known/assetlinks.json'은 비어있지 않은 문자열이므로 항상 truthy입니다. 즉, 이 if 블록은 모든 401 에러에 대해 실행되어 토큰 리프레시 로직을 완전히 우회합니다.
🐛 수정 제안
- if (window.location.pathname === '/.well-known/apple-app-site-association' || '/.well-known/assetlinks.json') {
+ if (window.location.pathname === '/.well-known/apple-app-site-association' || window.location.pathname === '/.well-known/assetlinks.json') {
return Promise.reject(error);
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // 에스크 문자를 통한 딥링크 접근을 위해 허용 | |
| if (window.location.pathname === '/.well-known/apple-app-site-association' || '/.well-known/assetlinks.json') { | |
| return Promise.reject(error); | |
| } | |
| // 에스크 문자를 통한 딥링크 접근을 위해 허용 | |
| if (window.location.pathname === '/.well-known/apple-app-site-association' || window.location.pathname === '/.well-known/assetlinks.json') { | |
| return Promise.reject(error); | |
| } |
🤖 Prompt for AI Agents
In `@src/api/index.ts` around lines 98 - 101, The if condition incorrectly uses
"if (window.location.pathname === '/.well-known/apple-app-site-association' ||
'/.well-known/assetlinks.json')" which always evaluates true because the second
operand is a non-empty string; change the boolean check so both paths are
compared against window.location.pathname (i.e., window.location.pathname ===
'/.well-known/apple-app-site-association' || window.location.pathname ===
'/.well-known/assetlinks.json') so that Promise.reject(error) only runs when the
request path exactly matches one of those two well-known endpoints (affecting
the 401 handling logic that triggers token refresh).
🤫 쉿, 나한테만 말해줘요. 이슈넘버
🧐 어떤 것을 변경했어요~?
🤔 그렇다면, 어떻게 구현했어요~?
❤️🔥 당신이 생각하는 PR포인트, 내겐 매력포인트.
📸 스크린샷, 없으면 이것 참,, 섭섭한데요?