Skip to content

Comments

feat: 멤버 리스트 메이커스 기수 표기 #2190

Closed
ljh0608 wants to merge 9 commits intodevelopfrom
feat/#2174
Closed

feat: 멤버 리스트 메이커스 기수 표기 #2190
ljh0608 wants to merge 9 commits intodevelopfrom
feat/#2174

Conversation

@ljh0608
Copy link
Contributor

@ljh0608 ljh0608 commented Feb 9, 2026

🤫 쉿, 나한테만 말해줘요. 이슈넘버

🧐 어떤 것을 변경했어요~?

🤔 그렇다면, 어떻게 구현했어요~?

❤️‍🔥 당신이 생각하는 PR포인트, 내겐 매력포인트.

📸 스크린샷, 없으면 이것 참,, 섭섭한데요?

@ljh0608 ljh0608 requested review from imddoy and seong-hui February 9, 2026 14:52
@ljh0608 ljh0608 self-assigned this Feb 9, 2026
@coderabbitai
Copy link

coderabbitai bot commented Feb 9, 2026

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • Apple App Site Association 지원 추가
    • Android App Links 지원 추가
    • 멤버 목록의 배지가 팀 정보를 표시하도록 업데이트
  • 버그 수정

    • 딥 링크 접근 시 인증 오류 처리 개선
  • 설정

    • Dev Crew API 엔드포인트 업데이트
    • 배포 워크플로우 개선으로 서버리스 함수 포함

Walkthrough

앱 딥링크 지원, 배포 패키지 구성 개선, 멤버 페이지 UI 업데이트를 추가합니다. Crew API 엔드포인트를 수정하고, 토큰 에러 처리 로직을 변경하며, 서버리스 함수로 AASA 및 Android App Links 설정을 제공합니다.

Changes

Cohort / File(s) Summary
API 설정 및 환경
.env.development, src/api/index.ts
Crew API 엔드포인트 URL 경로 변경 (https://crew.api.dev.sopt.orghttps://crew-api-dev.sopt.org/) 및 토큰 에러 처리에 경로 기반 조기 반환 조건 추가
배포 및 빌드
.github/workflows/build.yml
배포 디렉토리 준비 단계 추가: 빌드 출력물(out/*)과 functions 디렉토리를 deploy/ 로 복사하고, 아티팩트 업로드 경로 변경
Well-Known 라우트
functions/.well-known/apple-app-site-association.ts, functions/.well-known/assetlinks.json.ts, public/.well-known/apple-app-site-association
Apple App Site Association 및 Android App Links 설정을 서버리스 함수로 제공. public의 AASA 파일을 RTF에서 JSON 형식으로 변경 (appID 값도 업데이트)
UI 컴포넌트
src/components/members/main/MemberList/index.tsx
Spacing 임포트 추가 및 배지 콘텐츠에 activity.team 우선 표시 (없으면 activity.part 폴백)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

✨ Feature, size/XL

Suggested reviewers

  • seong-hui
  • imddoy

Poem

🐰 새로운 경로들이 자라나고,
딥링크 마법이 피어오른다네.
Well-Known 함수들 반짝반짝,
배지엔 기수가 춤을 춘다. ✨
배포도 싱글벙글, 준비 완벽! 📦

🚥 Pre-merge checks | ✅ 3 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning PR에는 환경변수 업데이트, 워크플로우 수정, Apple/Android 앱 링크 설정, 토큰 에러 처리 수정 등 멤버 기수 표기와 무관한 변경사항들이 포함되어 있습니다. 멤버 기수 표기와 무관한 변경사항(환경변수, CI/CD 워크플로우, 앱 링크 설정, 토큰 처리)들을 별도 PR로 분리해주세요.
Description check ❓ Inconclusive 설명은 PR 템플릿만 포함하고 있으며 실제 변경사항, 구현 방식, 논의 사항에 대한 구체적인 내용이 작성되지 않았습니다. PR 설명에 실제 변경사항, 구현 방식, 검토 포인트 등을 구체적으로 작성해주세요.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed 제목은 멤버 리스트의 메이커스 기수 표기에 대한 변경을 명확하게 설명하며 주요 변경사항을 잘 반영하고 있습니다.
Linked Issues check ✅ Passed 연결된 이슈 #2174는 멤버 페이지에 메이커스 기수 표기를 추가하는 것이며, 변경사항에서 MemberList의 Badge 콘텐츠가 activity.team을 사용하도록 수정된 것이 해당 요구사항을 충족합니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/#2174

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 Feb 9, 2026

✨✨ 스토리북으로 확인하기 ✨✨

@github-actions
Copy link

github-actions bot commented Feb 9, 2026

🚀 프리뷰 배포 확인하기 🚀

https://820d29e1.sopt-internal-dev.pages.dev

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: 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
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

rg -n "CREW_API_URL" --type=ts -C3

Repository: sopt-makers/sopt-playground-frontend

Length of output: 1589


🏁 Script executed:

rg -n "crew-api" --type=ts -C3

Repository: 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 -20

Repository: 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
fi

Repository: sopt-makers/sopt-playground-frontend

Length of output: 350


🏁 Script executed:

# Find axios configuration and baseURL setup
rg -n "axiosCrewInstance|baseURL" --type=ts -C2

Repository: sopt-makers/sopt-playground-frontend

Length of output: 4614


🏁 Script executed:

# Check other API URLs for consistency
cat .env.development

Repository: 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 -30

Repository: 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.ts

Repository: 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.

Comment on lines +1 to +13
{
"applinks": {
"apps": [],
"details": [
{
"appID": "95YWTT5L8K.com.sopt-stamp-iOS.release",
"paths": [
"*"
]
}
]
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Check if both files exist in the codebase
fd "apple-app-site-association" -t f

Repository: 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 -20

Repository: 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 /functions file-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 Functions
  • exclude: paths that should not invoke Functions (exclude always wins over include) [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 f

Repository: 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.

Comment on lines +98 to +101
// 에스크 문자를 통한 딥링크 접근을 위해 허용
if (window.location.pathname === '/.well-known/apple-app-site-association' || '/.well-known/assetlinks.json') {
return Promise.reject(error);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

크리티컬 버그: 조건문이 항상 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.

Suggested change
// 에스크 문자를 통한 딥링크 접근을 위해 허용
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).

@ljh0608 ljh0608 closed this Feb 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: 멤버 페이지 메이커스 기수 표기

3 participants