[FEAT] WTH-377: capacitor 앱 초기세팅#123
Conversation
|
Warning Review limit reached
More reviews will be available in 48 minutes and 1 second. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the 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 include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 Walkthrough전체 요약이 PR은 Capacitor 프레임워크를 사용하여 웹 기반 Next.js 프로젝트를 iOS 및 Android 네이티브 앱으로 변환하기 위한 전체 플랫폼 설정을 추가합니다. Android Gradle 빌드 시스템, iOS Xcode 프로젝트 구조, 공유 Capacitor 설정, 그리고 개발 환경용 토큰 기반 로그인 페이지를 포함합니다. 변경 사항Capacitor 모바일 플랫폼 및 개발 기능
예상 코드 리뷰 노력🎯 4 (Complex) | ⏱️ ~60 분 제안 라벨
제안 리뷰어
시 (한 마리 토끼의 축하시)
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 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 |
PR 테스트 결과✅ Jest: 통과 🎉 모든 테스트를 통과했습니다! |
PR 검증 결과✅ TypeScript: 통과 |
|
구현한 기능 Preview: https://weeth-a7rbs7heb-weethsite-4975s-projects.vercel.app |
PR 테스트 결과✅ Jest: 통과 🎉 모든 테스트를 통과했습니다! |
PR 검증 결과✅ TypeScript: 통과 🎉 모든 검증을 통과했습니다! |
|
구현한 기능 Preview: https://weeth-8jcge4h6w-weethsite-4975s-projects.vercel.app |
There was a problem hiding this comment.
Actionable comments posted: 8
🤖 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
`@android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java`:
- Line 24: The test assertion in ExampleInstrumentedTest (assertEquals call)
uses the old expected package string "com.getcapacitor.app" and should be
updated to match the current app ID; change the expected value in the
assertEquals inside the test method (the assertEquals("com.getcapacitor.app",
appContext.getPackageName()) call) to "kr.weeth.client" so the assertion
compares the correct package name.
In `@android/app/src/main/AndroidManifest.xml`:
- Line 5: AndroidManifest.xml currently enables app data backup via the
manifest's android:allowBackup="true"; change this attribute in the <manifest>
element to android:allowBackup="false" (or remove it to rely on platform
default) so the app does not allow automatic backup/restore of sensitive data in
production; locate the android:allowBackup attribute in the manifest tag and
update its value accordingly.
In `@android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml`:
- Line 4: ic_launcher_round.xml의 foreground 속성이 현재
`@mipmap/ic_launcher_foreground로` 되어 있어 벡터/foreground 리소스 타입과 불일치할 수 있으니
ic_launcher_round.xml의 foreground android:drawable 참조를
`@drawable/ic_launcher_foreground로` 변경해 동일한 drawable 리소스 타입을 사용하도록 수정하세요.
In `@android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml`:
- Line 4: The foreground element currently references the mipmap resource
"`@mipmap/ic_launcher_foreground`", but this PR uses a drawable-based foreground
which causes resource resolution failures; update the foreground's
android:drawable reference from "`@mipmap/ic_launcher_foreground`" to
"`@drawable/ic_launcher_foreground`" in the ic_launcher XML (look for the
foreground element and its android:drawable attribute) so the launcher XML
points to the drawable resource type used by the project.
In `@android/app/src/main/res/xml/file_paths.xml`:
- Line 3: The FileProvider config currently exposes the whole external storage
via the external-path entry (external-path name="my_images" path="."), which is
too broad; change that entry to use external-files-path (keep the same name
"my_images") and narrow the path to the app-specific directory (e.g., remove "."
and rely on external-files-path default or specify a subfolder) so FileProvider
only grants access to app external files rather than all external storage.
In `@android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java`:
- Around line 1-18: The test file's package declaration does not match the app's
actual package (class ExampleUnitTest / method addition_isCorrect), causing
package mismatch errors; fix by either changing the package declaration at the
top of this file from com.getcapacitor.myapp to kr.weeth.client so the test
class resides in the correct package, or if the template test is not needed,
remove the ExampleUnitTest.java file entirely to avoid the mismatch.
In `@src/app/dev-login/page.tsx`:
- Around line 14-25: The current isDevLoginEnabled() uses
NEXT_PUBLIC_ENABLE_DEV_LOGIN which can enable dev-login in production; change it
to only allow development or a server-only flag by replacing
NEXT_PUBLIC_ENABLE_DEV_LOGIN with process.env.ENABLE_DEV_LOGIN and keep the
NODE_ENV==='development' check, i.e., update isDevLoginEnabled() to check
process.env.NODE_ENV === 'development' || process.env.ENABLE_DEV_LOGIN ===
'true'; remove any usage of NEXT_PUBLIC_ENABLE_DEV_LOGIN so the flag is not
exposed to the client and ensure devLoginAction still calls isDevLoginEnabled()
to gate the server action.
- Around line 68-136: The form controls in the Dev Login form (the <form
action={devLoginAction}>, the textarea elements named "accessToken" and
"refreshToken", the input elements "clubId", "clubName", "redirectPath", and the
submit <button>) use hardcoded Tailwind classes and nonstandard typography
tokens (e.g., typo-heading1) and must be refactored to use cva-based shared
variants and design tokens; extract a shared cva factory (e.g., createInputClass
/ createTextareaClass / createButtonClass or a single formControl cva) that
exposes variants for size/state and apply design token classes (typo-h*,
bg-button-primary, p-100~500, gap-100~400, etc.) instead of inline classes, then
replace the className strings on those controls with the cva-generated
classNames and update any spacing/typography tokens in the surrounding elements
to the prescribed token names.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 88b43cd2-a106-41aa-9297-ca0115e17863
⛔ Files ignored due to path filters (32)
android/app/src/main/res/drawable-land-hdpi/splash.pngis excluded by!**/*.pngandroid/app/src/main/res/drawable-land-mdpi/splash.pngis excluded by!**/*.pngandroid/app/src/main/res/drawable-land-xhdpi/splash.pngis excluded by!**/*.pngandroid/app/src/main/res/drawable-land-xxhdpi/splash.pngis excluded by!**/*.pngandroid/app/src/main/res/drawable-land-xxxhdpi/splash.pngis excluded by!**/*.pngandroid/app/src/main/res/drawable-port-hdpi/splash.pngis excluded by!**/*.pngandroid/app/src/main/res/drawable-port-mdpi/splash.pngis excluded by!**/*.pngandroid/app/src/main/res/drawable-port-xhdpi/splash.pngis excluded by!**/*.pngandroid/app/src/main/res/drawable-port-xxhdpi/splash.pngis excluded by!**/*.pngandroid/app/src/main/res/drawable-port-xxxhdpi/splash.pngis excluded by!**/*.pngandroid/app/src/main/res/drawable/splash.pngis excluded by!**/*.pngandroid/app/src/main/res/mipmap-hdpi/ic_launcher.pngis excluded by!**/*.pngandroid/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.pngis excluded by!**/*.pngandroid/app/src/main/res/mipmap-hdpi/ic_launcher_round.pngis excluded by!**/*.pngandroid/app/src/main/res/mipmap-mdpi/ic_launcher.pngis excluded by!**/*.pngandroid/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.pngis excluded by!**/*.pngandroid/app/src/main/res/mipmap-mdpi/ic_launcher_round.pngis excluded by!**/*.pngandroid/app/src/main/res/mipmap-xhdpi/ic_launcher.pngis excluded by!**/*.pngandroid/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.pngis excluded by!**/*.pngandroid/app/src/main/res/mipmap-xhdpi/ic_launcher_round.pngis excluded by!**/*.pngandroid/app/src/main/res/mipmap-xxhdpi/ic_launcher.pngis excluded by!**/*.pngandroid/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.pngis excluded by!**/*.pngandroid/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.pngis excluded by!**/*.pngandroid/app/src/main/res/mipmap-xxxhdpi/ic_launcher.pngis excluded by!**/*.pngandroid/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.pngis excluded by!**/*.pngandroid/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.pngis excluded by!**/*.pngandroid/gradle/wrapper/gradle-wrapper.jaris excluded by!**/*.jarios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.pngis excluded by!**/*.pngios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-1.pngis excluded by!**/*.pngios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-2.pngis excluded by!**/*.pngios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732.pngis excluded by!**/*.pngpnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (45)
README.mdandroid/.gitignoreandroid/app/.gitignoreandroid/app/build.gradleandroid/app/capacitor.build.gradleandroid/app/proguard-rules.proandroid/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.javaandroid/app/src/main/AndroidManifest.xmlandroid/app/src/main/java/kr/weeth/client/MainActivity.javaandroid/app/src/main/res/drawable-v24/ic_launcher_foreground.xmlandroid/app/src/main/res/drawable/ic_launcher_background.xmlandroid/app/src/main/res/layout/activity_main.xmlandroid/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xmlandroid/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xmlandroid/app/src/main/res/values/ic_launcher_background.xmlandroid/app/src/main/res/values/strings.xmlandroid/app/src/main/res/values/styles.xmlandroid/app/src/main/res/xml/file_paths.xmlandroid/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.javaandroid/build.gradleandroid/capacitor.settings.gradleandroid/gradle.propertiesandroid/gradle/wrapper/gradle-wrapper.propertiesandroid/gradlewandroid/gradlew.batandroid/settings.gradleandroid/variables.gradlecapacitor.config.tsios/.gitignoreios/App/App.xcodeproj/project.pbxprojios/App/App.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plistios/App/App/AppDelegate.swiftios/App/App/Assets.xcassets/AppIcon.appiconset/Contents.jsonios/App/App/Assets.xcassets/Contents.jsonios/App/App/Assets.xcassets/Splash.imageset/Contents.jsonios/App/App/Base.lproj/LaunchScreen.storyboardios/App/App/Base.lproj/Main.storyboardios/App/App/Info.plistios/App/CapApp-SPM/.gitignoreios/App/CapApp-SPM/Package.swiftios/App/CapApp-SPM/README.mdios/App/CapApp-SPM/Sources/CapApp-SPM/CapApp-SPM.swiftios/debug.xcconfigpackage.jsonsrc/app/dev-login/page.tsx
| // Context of the app under test. | ||
| Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); | ||
|
|
||
| assertEquals("com.getcapacitor.app", appContext.getPackageName()); |
There was a problem hiding this comment.
패키지명 assertion 값을 현재 앱 식별자와 맞춰주세요.
Line 24의 기대값(com.getcapacitor.app)이 현재 설정된 앱 식별자(kr.weeth.client)와 달라 테스트가 실패합니다.
수정 제안
- assertEquals("com.getcapacitor.app", appContext.getPackageName());
+ assertEquals("kr.weeth.client", appContext.getPackageName());📝 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.
| assertEquals("com.getcapacitor.app", appContext.getPackageName()); | |
| assertEquals("kr.weeth.client", appContext.getPackageName()); |
🤖 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
`@android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java`
at line 24, The test assertion in ExampleInstrumentedTest (assertEquals call)
uses the old expected package string "com.getcapacitor.app" and should be
updated to match the current app ID; change the expected value in the
assertEquals inside the test method (the assertEquals("com.getcapacitor.app",
appContext.getPackageName()) call) to "kr.weeth.client" so the assertion
compares the correct package name.
| <manifest xmlns:android="http://schemas.android.com/apk/res/android"> | ||
|
|
||
| <application | ||
| android:allowBackup="true" |
There was a problem hiding this comment.
인증 데이터 앱에서 자동 백업 허용 설정은 재검토가 필요합니다.
android:allowBackup="true"는 앱 데이터(예: WebView 저장 데이터)의 백업/복원 경로를 열 수 있어 보안/프라이버시 위험을 키울 수 있습니다. 프로덕션 기본값을 false로 두는 쪽이 안전합니다.
🔧 제안 수정안
- android:allowBackup="true"
+ android:allowBackup="false"📝 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.
| android:allowBackup="true" | |
| android:allowBackup="false" |
🤖 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 `@android/app/src/main/AndroidManifest.xml` at line 5, AndroidManifest.xml
currently enables app data backup via the manifest's android:allowBackup="true";
change this attribute in the <manifest> element to android:allowBackup="false"
(or remove it to rely on platform default) so the app does not allow automatic
backup/restore of sensitive data in production; locate the android:allowBackup
attribute in the manifest tag and update its value accordingly.
| <?xml version="1.0" encoding="utf-8"?> | ||
| <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> | ||
| <background android:drawable="@color/ic_launcher_background"/> | ||
| <foreground android:drawable="@mipmap/ic_launcher_foreground"/> |
There was a problem hiding this comment.
라운드 아이콘도 foreground 리소스 타입을 맞춰주세요.
Line 4의 @mipmap/ic_launcher_foreground는 foreground 벡터 리소스 타입과 불일치할 가능성이 큽니다. @drawable 참조로 통일하는 게 안전합니다.
수정 제안
- <foreground android:drawable="`@mipmap/ic_launcher_foreground`"/>
+ <foreground android:drawable="`@drawable/ic_launcher_foreground`"/>📝 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.
| <foreground android:drawable="@mipmap/ic_launcher_foreground"/> | |
| <foreground android:drawable="`@drawable/ic_launcher_foreground`"/> |
🤖 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 `@android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml` at line 4,
ic_launcher_round.xml의 foreground 속성이 현재 `@mipmap/ic_launcher_foreground로` 되어 있어
벡터/foreground 리소스 타입과 불일치할 수 있으니 ic_launcher_round.xml의 foreground
android:drawable 참조를 `@drawable/ic_launcher_foreground로` 변경해 동일한 drawable 리소스 타입을
사용하도록 수정하세요.
| <?xml version="1.0" encoding="utf-8"?> | ||
| <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> | ||
| <background android:drawable="@color/ic_launcher_background"/> | ||
| <foreground android:drawable="@mipmap/ic_launcher_foreground"/> |
There was a problem hiding this comment.
ic_launcher_foreground 리소스 타입 참조를 수정해주세요.
Line 4에서 @mipmap/ic_launcher_foreground를 참조하고 있는데, 이 PR의 리소스 구성은 drawable 기반 foreground를 사용합니다. 빌드 시 리소스 해석 실패로 이어질 수 있습니다.
수정 제안
- <foreground android:drawable="`@mipmap/ic_launcher_foreground`"/>
+ <foreground android:drawable="`@drawable/ic_launcher_foreground`"/>🤖 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 `@android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml` at line 4, The
foreground element currently references the mipmap resource
"`@mipmap/ic_launcher_foreground`", but this PR uses a drawable-based foreground
which causes resource resolution failures; update the foreground's
android:drawable reference from "`@mipmap/ic_launcher_foreground`" to
"`@drawable/ic_launcher_foreground`" in the ic_launcher XML (look for the
foreground element and its android:drawable attribute) so the launcher XML
points to the drawable resource type used by the project.
| @@ -0,0 +1,5 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | |||
| <paths xmlns:android="http://schemas.android.com/apk/res/android"> | |||
| <external-path name="my_images" path="." /> | |||
There was a problem hiding this comment.
FileProvider 외부 경로 범위를 축소해주세요.
Line 3의 external-path path="."는 외부 저장소 전체를 포괄할 수 있어 권한 위임 시 노출 범위가 과도합니다. 앱 전용 경로(external-files-path)로 제한하는 구성이 더 안전합니다.
수정 예시
- <external-path name="my_images" path="." />
+ <external-files-path name="my_images" path="Pictures/" />📝 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.
| <external-path name="my_images" path="." /> | |
| <external-files-path name="my_images" path="Pictures/" /> |
🤖 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 `@android/app/src/main/res/xml/file_paths.xml` at line 3, The FileProvider
config currently exposes the whole external storage via the external-path entry
(external-path name="my_images" path="."), which is too broad; change that entry
to use external-files-path (keep the same name "my_images") and narrow the path
to the app-specific directory (e.g., remove "." and rely on external-files-path
default or specify a subfolder) so FileProvider only grants access to app
external files rather than all external storage.
| package com.getcapacitor.myapp; | ||
|
|
||
| import static org.junit.Assert.*; | ||
|
|
||
| import org.junit.Test; | ||
|
|
||
| /** | ||
| * Example local unit test, which will execute on the development machine (host). | ||
| * | ||
| * @see <a href="http://d.android.com/tools/testing">Testing documentation</a> | ||
| */ | ||
| public class ExampleUnitTest { | ||
|
|
||
| @Test | ||
| public void addition_isCorrect() throws Exception { | ||
| assertEquals(4, 2 + 2); | ||
| } | ||
| } |
There was a problem hiding this comment.
패키지 이름이 실제 앱 패키지와 불일치합니다.
테스트 파일의 패키지 이름이 com.getcapacitor.myapp로 되어 있으나, 실제 앱의 패키지는 kr.weeth.client입니다 (capacitor.config.ts의 appId 참조). 이는 Capacitor 템플릿 기본 코드가 업데이트되지 않은 것으로 보입니다.
다음 중 하나를 선택해주세요:
- 실제 앱 코드를 테스트할 예정이라면 패키지 이름을
kr.weeth.client로 수정 - 템플릿 예제가 필요 없다면 이 파일 삭제
🔧 제안: 패키지 이름 수정
-package com.getcapacitor.myapp;
+package kr.weeth.client;📝 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.
| package com.getcapacitor.myapp; | |
| import static org.junit.Assert.*; | |
| import org.junit.Test; | |
| /** | |
| * Example local unit test, which will execute on the development machine (host). | |
| * | |
| * @see <a href="http://d.android.com/tools/testing">Testing documentation</a> | |
| */ | |
| public class ExampleUnitTest { | |
| @Test | |
| public void addition_isCorrect() throws Exception { | |
| assertEquals(4, 2 + 2); | |
| } | |
| } | |
| package kr.weeth.client; | |
| import static org.junit.Assert.*; | |
| import org.junit.Test; | |
| /** | |
| * Example local unit test, which will execute on the development machine (host). | |
| * | |
| * `@see` <a href="http://d.android.com/tools/testing">Testing documentation</a> | |
| */ | |
| public class ExampleUnitTest { | |
| `@Test` | |
| public void addition_isCorrect() throws Exception { | |
| assertEquals(4, 2 + 2); | |
| } | |
| } |
🤖 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 `@android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java` around
lines 1 - 18, The test file's package declaration does not match the app's
actual package (class ExampleUnitTest / method addition_isCorrect), causing
package mismatch errors; fix by either changing the package declaration at the
top of this file from com.getcapacitor.myapp to kr.weeth.client so the test
class resides in the correct package, or if the template test is not needed,
remove the ExampleUnitTest.java file entirely to avoid the mismatch.
| function isDevLoginEnabled() { | ||
| return ( | ||
| process.env.NODE_ENV === 'development' || process.env.NEXT_PUBLIC_ENABLE_DEV_LOGIN === 'true' | ||
| ); | ||
| } | ||
|
|
||
| async function devLoginAction(formData: FormData) { | ||
| 'use server'; | ||
|
|
||
| if (!isDevLoginEnabled()) { | ||
| notFound(); | ||
| } |
There was a problem hiding this comment.
운영 환경에서 dev-login이 활성화될 수 있는 조건을 제거하세요.
Line 16 조건 때문에 NEXT_PUBLIC_ENABLE_DEV_LOGIN=true 오설정 시 production에서도 토큰 주입 페이지/액션이 열립니다. 운영에서는 무조건 비활성화하고, 필요 시 서버 전용 env(ENABLE_DEV_LOGIN)만 허용하는 게 안전합니다.
🔧 제안 수정안
function isDevLoginEnabled() {
- return (
- process.env.NODE_ENV === 'development' || process.env.NEXT_PUBLIC_ENABLE_DEV_LOGIN === 'true'
- );
+ if (process.env.NODE_ENV === 'production') return false;
+ return (
+ process.env.NODE_ENV === 'development' ||
+ process.env.ENABLE_DEV_LOGIN === 'true'
+ );
}📝 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.
| function isDevLoginEnabled() { | |
| return ( | |
| process.env.NODE_ENV === 'development' || process.env.NEXT_PUBLIC_ENABLE_DEV_LOGIN === 'true' | |
| ); | |
| } | |
| async function devLoginAction(formData: FormData) { | |
| 'use server'; | |
| if (!isDevLoginEnabled()) { | |
| notFound(); | |
| } | |
| function isDevLoginEnabled() { | |
| if (process.env.NODE_ENV === 'production') return false; | |
| return ( | |
| process.env.NODE_ENV === 'development' || | |
| process.env.ENABLE_DEV_LOGIN === 'true' | |
| ); | |
| } | |
| async function devLoginAction(formData: FormData) { | |
| 'use server'; | |
| if (!isDevLoginEnabled()) { | |
| notFound(); | |
| } |
🤖 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 `@src/app/dev-login/page.tsx` around lines 14 - 25, The current
isDevLoginEnabled() uses NEXT_PUBLIC_ENABLE_DEV_LOGIN which can enable dev-login
in production; change it to only allow development or a server-only flag by
replacing NEXT_PUBLIC_ENABLE_DEV_LOGIN with process.env.ENABLE_DEV_LOGIN and
keep the NODE_ENV==='development' check, i.e., update isDevLoginEnabled() to
check process.env.NODE_ENV === 'development' || process.env.ENABLE_DEV_LOGIN ===
'true'; remove any usage of NEXT_PUBLIC_ENABLE_DEV_LOGIN so the flag is not
exposed to the client and ensure devLoginAction still calls isDevLoginEnabled()
to gate the server action.
| <main className="mx-auto flex min-h-dvh w-full max-w-[520px] flex-col justify-center px-6 py-10"> | ||
| <div className="space-y-3"> | ||
| <p className="typo-body2 text-text-alternative">Local app development</p> | ||
| <h1 className="typo-heading1 text-text-normal">Dev Login</h1> | ||
| <p className="typo-body2 text-text-alternative"> | ||
| 카카오 로그인을 우회해서 로컬 WebView에 개발용 토큰을 심습니다. | ||
| </p> | ||
| </div> | ||
|
|
||
| <form action={devLoginAction} className="mt-8 space-y-5"> | ||
| <label className="block space-y-2"> | ||
| <span className="typo-body2 text-text-normal">Access token</span> | ||
| <textarea | ||
| name="accessToken" | ||
| required | ||
| rows={4} | ||
| className="border-line-normal bg-background-normal text-text-normal focus:border-primary-normal w-full resize-y rounded-lg border px-4 py-3 text-sm outline-none" | ||
| placeholder="accessToken" | ||
| /> | ||
| </label> | ||
|
|
||
| <label className="block space-y-2"> | ||
| <span className="typo-body2 text-text-normal">Refresh token</span> | ||
| <textarea | ||
| name="refreshToken" | ||
| required | ||
| rows={4} | ||
| className="border-line-normal bg-background-normal text-text-normal focus:border-primary-normal w-full resize-y rounded-lg border px-4 py-3 text-sm outline-none" | ||
| placeholder="refreshToken" | ||
| /> | ||
| </label> | ||
|
|
||
| <label className="block space-y-2"> | ||
| <span className="typo-body2 text-text-normal">Club ID</span> | ||
| <input | ||
| name="clubId" | ||
| className="border-line-normal bg-background-normal text-text-normal focus:border-primary-normal w-full rounded-lg border px-4 py-3 text-sm outline-none" | ||
| placeholder="예: club id" | ||
| /> | ||
| </label> | ||
|
|
||
| <label className="block space-y-2"> | ||
| <span className="typo-body2 text-text-normal">Club name</span> | ||
| <input | ||
| name="clubName" | ||
| className="border-line-normal bg-background-normal text-text-normal focus:border-primary-normal w-full rounded-lg border px-4 py-3 text-sm outline-none" | ||
| placeholder="예: Weeth" | ||
| /> | ||
| </label> | ||
|
|
||
| <label className="block space-y-2"> | ||
| <span className="typo-body2 text-text-normal">Redirect path</span> | ||
| <input | ||
| name="redirectPath" | ||
| className="border-line-normal bg-background-normal text-text-normal focus:border-primary-normal w-full rounded-lg border px-4 py-3 text-sm outline-none" | ||
| placeholder="비워두면 /{clubId}/home 또는 /hub" | ||
| /> | ||
| </label> | ||
|
|
||
| {error === 'missing-token' && ( | ||
| <p className="typo-caption1 text-status-negative"> | ||
| access token과 refresh token을 모두 입력해야 합니다. | ||
| </p> | ||
| )} | ||
|
|
||
| <button | ||
| type="submit" | ||
| className="bg-primary-normal text-static-white h-12 w-full rounded-lg text-base font-semibold" | ||
| > |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win
폼 스타일을 토큰 기반 + cva로 정리해 주세요.
현재 구간은 하드코딩 유틸/비표준 타이포 토큰(typo-heading1)과 중복 class가 섞여 있어 가이드와 어긋납니다. input/textarea/button 공통 스타일을 cva로 추출하고, typo-h*, bg-button-primary, p-100~500, gap-100~400 등 지정 토큰으로 맞춰주세요.
♻️ 적용 예시(요지)
+import { cva } from 'class-variance-authority';
+import { cn } from '`@/lib/cn`';
+
+const fieldClass = cva(
+ 'w-full rounded-lg border border-line-normal bg-container-neutral text-text-normal p-300 typo-body2 outline-hidden focus:border-primary-normal'
+);
+
+const submitButtonClass = cva(
+ 'w-full bg-button-primary text-text-inverse typo-button1 p-300'
+);
-<h1 className="typo-heading1 text-text-normal">Dev Login</h1>
+<h1 className="typo-h1 text-text-strong">Dev Login</h1>
-<input className="border-line-normal bg-background-normal ... px-4 py-3 text-sm ..."/>
+<input className={cn(fieldClass())} />
-<button className="bg-primary-normal text-static-white h-12 w-full rounded-lg text-base font-semibold">
+<button className={cn(submitButtonClass())}>As per coding guidelines **/*.{ts,tsx,css}: Use Tailwind CSS v4 with class-variance-authority (cva) for styling, Always use design token classes first; no hardcoded values, Use typography token classes: typo-h1~h3 ..., Use spacing token classes: p-100~500, gap-100~400.
🤖 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 `@src/app/dev-login/page.tsx` around lines 68 - 136, The form controls in the
Dev Login form (the <form action={devLoginAction}>, the textarea elements named
"accessToken" and "refreshToken", the input elements "clubId", "clubName",
"redirectPath", and the submit <button>) use hardcoded Tailwind classes and
nonstandard typography tokens (e.g., typo-heading1) and must be refactored to
use cva-based shared variants and design tokens; extract a shared cva factory
(e.g., createInputClass / createTextareaClass / createButtonClass or a single
formControl cva) that exposes variants for size/state and apply design token
classes (typo-h*, bg-button-primary, p-100~500, gap-100~400, etc.) instead of
inline classes, then replace the className strings on those controls with the
cva-generated classNames and update any spacing/typography tokens in the
surrounding elements to the prescribed token names.
✅ PR 유형
어떤 변경 사항이 있었나요?
📌 관련 이슈번호
✅ Key Changes
Capacitor 앱 초기 세팅
@capacitor/core,@capacitor/cli,@capacitor/android,@capacitor/iosv8 설치capacitor.config.ts추가:appId: 'kr.weeth.client',appName: 'Weeth'https://weeth.kr(production hosted 방식)CAP_SERVER_URL환경변수로 서버 URL 오버라이드 가능cleartext: true자동 적용pnpm 스크립트 추가 (
package.json)pnpm cap:syncpnpm cap:open:iospnpm cap:open:androidpnpm cap:dev:iospnpm cap:dev:androidpnpm cap:prod:sync개발용 로그인 페이지 (
/dev-login)NODE_ENV === 'development'또는NEXT_PUBLIC_ENABLE_DEV_LOGIN=true일 때만 활성화notFound()반환 (production 노출 없음)README 업데이트
📸 스크린샷 or 실행영상
2026-05-27.9.31.04.mov
🎸 기타 사항 or 추가 코멘트
로컬 3000으로 개발하려면 토큰이랑 clubid, clubName이 필요한데 시뮬레이터에서는 넣을 수 없어서 따로
dev-login.page를 만들었습니당!! 그래서 실행하시면 위 화면이 뜨고 거기에 쿠키에서 가져와서 복붙하면 바로 넘어가집니당Summary by CodeRabbit
릴리스 노트
새로운 기능
개선사항