create-saas-starter-workspace 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/LICENSE +17 -0
  3. package/README.md +19 -0
  4. package/bin/index.mjs +201 -0
  5. package/package.json +25 -0
  6. package/src/scaffold.mjs +109 -0
  7. package/src/validate.mjs +22 -0
  8. package/templates/workspace/.claude/settings.json +44 -0
  9. package/templates/workspace/.claude/skills/bridge-guide/SKILL.md +71 -0
  10. package/templates/workspace/.claude/skills/eas-deploy-guide/SKILL.md +107 -0
  11. package/templates/workspace/.claude/skills/go-live/SKILL.md +66 -0
  12. package/templates/workspace/.claude/skills/kickoff/SKILL.md +72 -0
  13. package/templates/workspace/.claude/skills/launch/SKILL.md +69 -0
  14. package/templates/workspace/.claude/skills/native-app-guide/SKILL.md +102 -0
  15. package/templates/workspace/.claude/skills/preview/SKILL.md +43 -0
  16. package/templates/workspace/.claude/skills/probe/SKILL.md +17 -0
  17. package/templates/workspace/.claude/skills/release/SKILL.md +51 -0
  18. package/templates/workspace/.claude/skills/sketch/SKILL.md +19 -0
  19. package/templates/workspace/.claude/skills/store-release-guide/SKILL.md +239 -0
  20. package/templates/workspace/.claude/skills/vercel-cron/SKILL.md +17 -0
  21. package/templates/workspace/.claude/skills/warmup/SKILL.md +33 -0
  22. package/templates/workspace/AGENTS.md +39 -0
  23. package/templates/workspace/CLAUDE.md +2 -0
  24. package/templates/workspace/LICENSE +17 -0
  25. package/templates/workspace/README.md +20 -0
  26. package/templates/workspace/START-HERE.md +52 -0
  27. package/templates/workspace/gitignore +18 -0
  28. package/templates/workspace/mobile/.env.example +25 -0
  29. package/templates/workspace/mobile/AGENTS.md +69 -0
  30. package/templates/workspace/mobile/App.tsx +47 -0
  31. package/templates/workspace/mobile/CLAUDE.md +2 -0
  32. package/templates/workspace/mobile/LICENSE +17 -0
  33. package/templates/workspace/mobile/README.md +73 -0
  34. package/templates/workspace/mobile/app.config.ts +153 -0
  35. package/templates/workspace/mobile/assets/android-icon-background.png +0 -0
  36. package/templates/workspace/mobile/assets/android-icon-foreground.png +0 -0
  37. package/templates/workspace/mobile/assets/android-icon-monochrome.png +0 -0
  38. package/templates/workspace/mobile/assets/favicon.png +0 -0
  39. package/templates/workspace/mobile/assets/icon.png +0 -0
  40. package/templates/workspace/mobile/assets/splash-icon.png +0 -0
  41. package/templates/workspace/mobile/docs/web-adapter/README.md +130 -0
  42. package/templates/workspace/mobile/docs/web-adapter/route-app-bridge.ts +235 -0
  43. package/templates/workspace/mobile/eas.json +31 -0
  44. package/templates/workspace/mobile/gitignore +45 -0
  45. package/templates/workspace/mobile/index.ts +12 -0
  46. package/templates/workspace/mobile/package.json +38 -0
  47. package/templates/workspace/mobile/pnpm-lock.yaml +5201 -0
  48. package/templates/workspace/mobile/src/auth/LoginScreen.tsx +192 -0
  49. package/templates/workspace/mobile/src/bridge/capabilities.test.ts +44 -0
  50. package/templates/workspace/mobile/src/bridge/capabilities.ts +42 -0
  51. package/templates/workspace/mobile/src/bridge/contract.test.ts +49 -0
  52. package/templates/workspace/mobile/src/bridge/contract.ts +146 -0
  53. package/templates/workspace/mobile/src/bridge/messaging.test.ts +49 -0
  54. package/templates/workspace/mobile/src/bridge/messaging.ts +33 -0
  55. package/templates/workspace/mobile/src/bridge/reader.test.ts +52 -0
  56. package/templates/workspace/mobile/src/bridge/reader.ts +31 -0
  57. package/templates/workspace/mobile/src/bridge/router.test.ts +124 -0
  58. package/templates/workspace/mobile/src/bridge/router.ts +89 -0
  59. package/templates/workspace/mobile/src/config/env.ts +51 -0
  60. package/templates/workspace/mobile/src/i18n.ts +71 -0
  61. package/templates/workspace/mobile/src/session/secureSession.ts +63 -0
  62. package/templates/workspace/mobile/src/session/sessionHandoff.ts +151 -0
  63. package/templates/workspace/mobile/src/ui/ErrorView.tsx +75 -0
  64. package/templates/workspace/mobile/src/ui/LoadingView.tsx +38 -0
  65. package/templates/workspace/mobile/src/ui/OfflineView.tsx +73 -0
  66. package/templates/workspace/mobile/src/webview/Host.tsx +353 -0
  67. package/templates/workspace/mobile/src/webview/linkBoundary.test.ts +57 -0
  68. package/templates/workspace/mobile/src/webview/linkBoundary.ts +58 -0
  69. package/templates/workspace/mobile/tsconfig.json +8 -0
  70. package/templates/workspace/mobile/vitest.config.ts +14 -0
  71. package/templates/workspace/package.json +9 -0
  72. package/templates/workspace/scripts/doctor.mjs +291 -0
  73. package/templates/workspace/ssb/README.md +10 -0
  74. package/templates/workspace/ssb/contract.ts +146 -0
  75. package/templates/workspace/ssb/reader.ts +31 -0
  76. package/templates/workspace/web/.env.example +39 -0
  77. package/templates/workspace/web/.gitattributes +1 -0
  78. package/templates/workspace/web/.github/workflows/ci.yml +61 -0
  79. package/templates/workspace/web/.vscode/settings.json +8 -0
  80. package/templates/workspace/web/AGENTS.md +103 -0
  81. package/templates/workspace/web/CLAUDE.md +2 -0
  82. package/templates/workspace/web/DESIGN.md +18 -0
  83. package/templates/workspace/web/LICENSE +17 -0
  84. package/templates/workspace/web/README.md +48 -0
  85. package/templates/workspace/web/app/error.tsx +28 -0
  86. package/templates/workspace/web/app/favicon.ico +0 -0
  87. package/templates/workspace/web/app/global-error.tsx +19 -0
  88. package/templates/workspace/web/app/globals.css +130 -0
  89. package/templates/workspace/web/app/layout.tsx +33 -0
  90. package/templates/workspace/web/app/not-found.tsx +12 -0
  91. package/templates/workspace/web/app/page.tsx +11 -0
  92. package/templates/workspace/web/components/ui/button.tsx +58 -0
  93. package/templates/workspace/web/components.json +25 -0
  94. package/templates/workspace/web/docs/ENVIRONMENTS.md +102 -0
  95. package/templates/workspace/web/docs/LIMITS.md +54 -0
  96. package/templates/workspace/web/eslint.config.mjs +46 -0
  97. package/templates/workspace/web/features/.gitkeep +0 -0
  98. package/templates/workspace/web/gitignore +51 -0
  99. package/templates/workspace/web/instrumentation-client.ts +16 -0
  100. package/templates/workspace/web/instrumentation.ts +12 -0
  101. package/templates/workspace/web/lib/app-env.ts +12 -0
  102. package/templates/workspace/web/lib/bridge/contract.ts +146 -0
  103. package/templates/workspace/web/lib/bridge/reader.ts +31 -0
  104. package/templates/workspace/web/lib/env.server.ts +33 -0
  105. package/templates/workspace/web/lib/env.ts +21 -0
  106. package/templates/workspace/web/lib/logger.ts +32 -0
  107. package/templates/workspace/web/lib/supabase/admin.ts +14 -0
  108. package/templates/workspace/web/lib/supabase/client.ts +9 -0
  109. package/templates/workspace/web/lib/supabase/server.ts +24 -0
  110. package/templates/workspace/web/lib/utils.ts +6 -0
  111. package/templates/workspace/web/next.config.ts +16 -0
  112. package/templates/workspace/web/npmrc +14 -0
  113. package/templates/workspace/web/package.json +60 -0
  114. package/templates/workspace/web/pnpm-lock.yaml +9155 -0
  115. package/templates/workspace/web/postcss.config.mjs +7 -0
  116. package/templates/workspace/web/sentry.edge.config.ts +9 -0
  117. package/templates/workspace/web/sentry.server.config.ts +9 -0
  118. package/templates/workspace/web/supabase/migrations/.gitkeep +0 -0
  119. package/templates/workspace/web/tests/setup.ts +1 -0
  120. package/templates/workspace/web/tests/utils.test.ts +12 -0
  121. package/templates/workspace/web/tsconfig.json +35 -0
  122. package/templates/workspace/web/vercel.json +6 -0
  123. package/templates/workspace/web/vitest.config.ts +15 -0
@@ -0,0 +1,239 @@
1
+ ---
2
+ name: store-release-guide
3
+ description: ์Šคํ† ์–ด ์ถœ์‹œ ์ •์ฑ…ยท์ฝ˜์†”ยท์‹ฌ์‚ฌ. ๊ฐœ๋ฐœ์ž ๊ณ„์ •(Apple $99ยทGoogle $25) ๊ฐ€์ž…ยทApple 4.2/4.2.2 ์‹ฌ์‚ฌ ํ†ต๊ณผ ์ „๋žตยท์†Œ์…œ ๋กœ๊ทธ์ธ OAuth ์ฝ˜์†” ์…‹์—…ยทPlay ๋น„๊ณต๊ฐœ(closed) ํ…Œ์ŠคํŠธ 12๋ช…ยท14์ผ ๊ฒŒ์ดํŠธยทTestFlight ํ…Œ์Šคํ„ฐ ๊ด€๋ฆฌยทApp Store "Submit for Review"ยทApp Privacy/๋ฐ์ดํ„ฐ ์•ˆ์ „ ๋ผ๋ฒจยท๊ณ„์ • ์‚ญ์ œ ์ปดํ”Œ๋ผ์ด์–ธ์Šค ์ž‘์—… ์‹œ ์ž๋™ ๋กœ๋“œ๋ฉ๋‹ˆ๋‹ค. (EAS ๋นŒ๋“œยท์ œ์ถœ ๋ช…๋ นยทOTA๋Š” eas-deploy-guide.)
4
+ user-invocable: false
5
+ ---
6
+
7
+ # ์Šคํ† ์–ด ์…‹์—…ยท์ถœ์‹œ ๊ฐ€์ด๋“œ (์ถœ์‹œ ์ค€๋น„ + ์†Œ์…œ ๋กœ๊ทธ์ธ fast-follow)
8
+
9
+ > ์ด ๋ฌธ์„œ๋Š” ํ˜„์žฌ ํ…œํ”Œ๋ฆฟ์—์„œ ๋ฌด์—‡์ด ๋“ค์–ด๊ฐ€๊ณ  ๋ฌด์—‡์ด fast-follow์ธ์ง€ ์ •์งํ•˜๊ฒŒ ๊ตฌ๋ถ„ํ•œ๋‹ค.
10
+ > ์•ฑ ์ถœ์‹œ๋Š” AI๊ฐ€ ๋‹จ๊ณ„๋ณ„๋กœ ์•ˆ๋‚ดํ•œ๋‹ค. ๋‹จ, ๋ˆยท์‹ ์›ยท2FA๊ฐ€ ๊ฑธ๋ฆฐ ์ผ์€ Owner๊ฐ€ ์ง์ ‘ ํ•œ๋‹ค.
11
+
12
+ ## ๋ˆ„๊ฐ€ ๋ฌด์—‡์„ ํ•˜๋‚˜ (๊ฐ€์—ญ์„ฑ ๋ถ„๋ฅ˜)
13
+
14
+ | ํ‘œ์‹œ | ์˜๋ฏธ | ์˜ˆ |
15
+ |---|---|---|
16
+ | ๐ŸŸข | AI / CLI ์ž๋™ | EAS ๋นŒ๋“œยท์ œ์ถœ, ์ธ์ฆ์„œ ํŒŒ์ผ ์ž‘์—…, ์„ค์ • ํŒŒ์ผ |
17
+ | ๐ŸŸก | Owner๊ฐ€ ๋Œ€์‹œ๋ณด๋“œ์—์„œ (AI๊ฐ€ ์ •ํ™•ํžˆ ์•ˆ๋‚ด) | ์ฒซ Apple ๋กœ๊ทธ์ธ+2FA, ์Šคํฌ๋ฆฐ์ƒท, App Privacy ๋ผ๋ฒจ, Play SA JSON |
18
+ | ๐Ÿ”ด | Owner๊ฐ€ ์ง์ ‘ (๋Œ€๋ฆฌ ๋ถˆ๊ฐ€) | ์นด๋“œ ๊ฒฐ์ œ, ์‹ ์› ๊ฒ€์ฆ, ๋ฉค๋ฒ„์‹ญ ๊ฐ€์ž… |
19
+
20
+ ---
21
+
22
+ ## 1. ๊ฐœ๋ฐœ์ž ๊ณ„์ • (๐Ÿ”ด Owner โ€” ์œ ๋ฃŒยทํ™˜๋ถˆ ๋ถˆ๊ฐ€, ๊ฐ€์žฅ ๋จผ์ €)
23
+
24
+ | | Apple Developer Program | Google Play Console |
25
+ |---|---|---|
26
+ | ๋น„์šฉ | **$99 / ๋…„** (๊ฐฑ์‹ ํ˜•, ํ™˜๋ถˆ ๋ถˆ๊ฐ€) | **$25** (1ํšŒ, ํ™˜๋ถˆ ๋ถˆ๊ฐ€) |
27
+ | ๊ณ„์ • ์œ ํ˜• | Individual ๊ถŒ์žฅ (D-U-N-S ํšŒํ”ผ, ์‹ ์› ๊ฒ€์ฆ๋งŒ) | Personal ๊ถŒ์žฅ |
28
+ | ํŒ๋งค์ž๋ช… | ๊ฐœ์ธ ๋ฒ•์  ์ด๋ฆ„์ด **๊ณต๊ฐœ ํŒ๋งค์ž๋ช…**์ด ๋œ๋‹ค (ํ”„๋ผ์ด๋ฒ„์‹œ 1์ค„ confirm) | ๋™์ผ |
29
+ | ๋ฆฌ๋“œํƒ€์ž„ ํ•จ์ • | ์‹ ์› ๊ฒ€์ฆ ์ˆ˜ ์‹œ๊ฐ„~2์ผ | **์‹ ๊ทœ ๊ฐœ์ธ๊ณ„์ •์€ production ์ „ ๋น„๊ณต๊ฐœ(closed) ํ…Œ์ŠคํŠธ 12๋ช…ยท14์ผ ์—ฐ์† ๊ฐ•์ œ** (๋‚ด๋ถ€ ํ…Œ์ŠคํŠธ๋Š” ์นด์šดํŠธ Xยท์กฐ์ง๊ณ„์ • ๋ฉด์ œ) |
30
+
31
+ > ์ง€๋ฐฐ์  ์ง€์—ฐ์€ Apple ์‹ ์› ๊ฒ€์ฆ์ด ์•„๋‹ˆ๋ผ Google์˜ 12๋ช…ยท14์ผ ๊ฒŒ์ดํŠธ๋‹ค ([Play Console ์ •์ฑ…](https://support.google.com/googleplay/android-developer/answer/14151465)).
32
+ > production ์ถœ์‹œ๊นŒ์ง€ ์ตœ์†Œ 2์ฃผ๊ฐ€ ๋ง‰ํ˜€ ์žˆ๋‹ค. ๊ทธ๋ž˜์„œ **Google Play Console ๊ฐ€์ž…์„ ๊ฐ€์žฅ ๋จผ์ €** ํ•ด ๋‘๋ผ.
33
+ > Apple๋„ $99 ๊ฒฐ์ œ ํ›„ ๋ฉค๋ฒ„์‹ญ ํ™œ์„ฑํ™”์— ์‹œ๊ฐ„์ด ๊ฑธ๋ฆด ์ˆ˜ ์žˆ๋‹ค. ๋‘˜ ๋‹ค ์ฝ”๋“œ ์ž‘์—… ์ „์— ์‹œ์ž‘ํ•˜๋ผ.
34
+
35
+ ์ด ๋‘˜์€ AI๊ฐ€ ๋Œ€์‹  ๊ฐ€์ž…ํ•˜์ง€ ๋ชปํ•œ๋‹ค (์นด๋“œยท์‹ ์›ยท2FA). AI๋Š” ๊ฐ€์ž… ํ™”๋ฉด๊ณผ ์ž…๋ ฅ๊ฐ’์„ ์•ˆ๋‚ดํ•œ๋‹ค.
36
+
37
+ ---
38
+
39
+ ## 2. Apple Guideline 4.2 โ€” ์›น๋ทฐ ๋ž˜ํผ ์‹ฌ์‚ฌ ํ†ต๊ณผ (๊ฐ€์žฅ ์ค‘์š”)
40
+
41
+ ์›น์‚ฌ์ดํŠธ๋ฅผ ๊ทธ๋Œ€๋กœ ๋น„์ถ”๋Š” ์–‡์€ ์›น๋ทฐ๋Š” 4.2.2(์›น ํด๋ฆฌํ•‘ยท์• ๊ทธ๋ฆฌ๊ฒŒ์ดํ„ฐ) ์ •์„ ๊ฑฐ์ ˆ ์‚ฌ์œ ๋‹ค ([App Review Guidelines ยง4.2](https://developer.apple.com/app-store/review/guidelines/)). 2026 ๊ธฐ์ค€ ์‹ค์ธก์œผ๋กœ 4.2 / 4.2.2 ๊ฑฐ์ ˆ์ด ์›น๋ทฐ ์•ฑ์˜ 1์ˆœ์œ„ ์‚ฌ์œ ๋‹ค.
42
+ ํ†ต๊ณผ์˜ ํ•ต์‹ฌ์€ ํฐ์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ€๋Šฅํ•œ ์ง„์งœ ๋„ค์ดํ‹ฐ๋ธŒ ์ฐจ๋ณ„ ์š”์†Œ๊ฐ€ ํ•˜๋‚˜๋ผ๋„ ์žˆ์–ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.
43
+
44
+ ### ์…ธ์ด ์‹ค์ œ๋กœ ์ฑ„์šฐ๋Š” ๊ฒƒ (์ •์งํ•˜๊ฒŒ)
45
+
46
+ ์…ธ์€ ํ™”๋ฉด์„ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค. ์›น๋ทฐ๊ฐ€ ๋ง‰๊ฑฐ๋‚˜ ์—†๋Š” ๋„ค์ดํ‹ฐ๋ธŒ ๋นˆํ‹ˆ๋งŒ ๋ฉ”์šด๋‹ค. ๊ทธ๋ž˜์„œ ํ™•์‹คํžˆ ๋„ค์ดํ‹ฐ๋ธŒ ์ „์šฉ์ธ ํ‘œ๋ฉด์€ ์˜คํ”„๋ผ์ธ ํ™”๋ฉด๋ฟ์ด๊ณ , ๋กœ๋”ฉยท์—๋Ÿฌยท๋กœ๊ทธ์ธ์€ ์›น๊ณผ ๊ฒน์น˜๊ฑฐ๋‚˜ ์›น์˜ ๊ฒƒ์ด๋‹ค.
47
+
48
+ | ์š”์†Œ | v1 ์ƒํƒœ | ์„ค๋ช… |
49
+ |---|---|---|
50
+ | ์˜คํ”„๋ผ์ธ ํ™”๋ฉด | โœ… v1 (์œ ์ผํ•œ ๋„ค์ดํ‹ฐ๋ธŒ ์ „์šฉ ํ‘œ๋ฉด) | NetInfo๋กœ ๋ผ์ด๋ธŒ ์—ฐ๊ฒฐ ๋Š๊น€ ๊ฐ์ง€ โ†’ ๋„ค์ดํ‹ฐ๋ธŒ ์˜คํ”„๋ผ์ธ ํ™”๋ฉด + ๋‹ค์‹œ ์‹œ๋„. ๋„คํŠธ์›Œํฌ๊ฐ€ ์—†์œผ๋ฉด ์›น์€ ์•„์˜ˆ ๋ชป ๋œจ๋ฏ€๋กœ ์›น์— ๋Œ€์‘๋ฌผ์ด ์—†๋‹ค |
51
+ | ๋กœ๋”ฉยท์—๋Ÿฌ ์˜ค๋ฒ„๋ ˆ์ด | โœ… v1 (์ฒซ/ํ•˜๋“œ ๋กœ๋“œ + ํฌ๋ž˜์‹œ ํ•œ์ •) | ์ฒซ ๋กœ๋“œ(๋นˆ ์›น๋ทฐ)์™€ ํฌ๋ž˜์‹œ ์žฌ๋งˆ์šดํŠธ ๋•Œ๋งŒ ๋„ค์ดํ‹ฐ๋ธŒ๊ฐ€ ๋ณด์—ฌ์ค€๋‹ค. ์ธ์•ฑ(SPA) ํ™”๋ฉด ์ „ํ™˜๊ณผ ์ธํŽ˜์ด์ง€/๋ฐ์ดํ„ฐ ์˜ค๋ฅ˜๋Š” ์›น์ด ์ž๊ธฐ UI๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค (๋„ค์ดํ‹ฐ๋ธŒ๋Š” SPA ๋‚ด๋น„๋ฅผ ๋ชป ๋ณธ๋‹ค) |
52
+ | Android ํ•˜๋“œ์›จ์–ด ๋’ค๋กœ๊ฐ€๊ธฐ | โœ… v1 | ์›น๋ทฐ history ์šฐ์„ , ์—†์œผ๋ฉด OS ์œ„์ž„ |
53
+ | ์™ธ๋ถ€ ๋งํฌ ๋„ค์ดํ‹ฐ๋ธŒ ์ฒ˜๋ฆฌ | โœ… v1 | ์™ธ๋ถ€ originยท`mailto:`ยท`tel:`์€ ์‹œ์Šคํ…œ ๋ธŒ๋ผ์šฐ์ €/์•ฑ์œผ๋กœ (์•„์›ƒ๋ฐ”์šด๋“œ) |
54
+ | safe-area(๋…ธ์น˜) ์—ฌ๋ฐฑ | โœ… v1 | ๋„ค์ดํ‹ฐ๋ธŒ๊ฐ€ ์ธก์ •ํ•œ inset์„ CSS ๋ณ€์ˆ˜๋กœ ์›น์— ์ฃผ์ž… |
55
+ | ์นด๋ฉ”๋ผยท๋งˆ์ดํฌยทํŒŒ์ผ ์—…๋กœ๋“œ ๊ถŒํ•œ ์—ฐ๊ฒฐ | โœ… v1 (enablement) | ๊ธฐ๋Šฅ ์ž์ฒด๋Š” ์›น(`getUserMedia`)ยท๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(`<input type=file>` ํ”ผ์ปค)์˜ ๊ฒƒ. ์…ธ์€ ๋™์ž‘ํ•˜๋„๋ก ๊ถŒํ•œ ๋ฐฐ์„ ๋งŒ ๋”ํ•œ๋‹ค (ยง3ยท์•„๋ž˜) |
56
+ | ํ‘ธ์‹œ ์•Œ๋ฆผ | โŒ v1 ๋ถ€์žฌ | 4.2๋ฅผ ์œ„ํ•ด ๊ถŒ์žฅํ•˜๋Š” ๋„ค์ดํ‹ฐ๋ธŒ ์ฐจ๋ณ„ ์š”์†Œ. v1์—” ๋“ค์–ด ์žˆ์ง€ ์•Š๊ณ (์•ฑ ์˜์กด์„ฑยท๊ธฐ๋Šฅ ์—†์Œ), ์š”์ฒญ ์‹œ AI๊ฐ€ ๊ตฌํ˜„ํ•œ๋‹ค |
57
+ | ์ƒ์ฒด์ธ์ฆ (Face ID ๋“ฑ) | โŒ v1 ๋ถ€์žฌ | ์ง„์งœ ๋„ค์ดํ‹ฐ๋ธŒ ์ „์šฉ. v1 ์ดํ›„ |
58
+ | ๋„ค์ดํ‹ฐ๋ธŒ ์†Œ์…œ ๋กœ๊ทธ์ธ (GoogleยทApple ์›ํด๋ฆญ) | โŒ v1 ๋ถ€์žฌ | onPress ์—†๋Š” disabled ๋ฒ„ํŠผ๋งŒ ์กด์žฌ(Apple์€ iOS ํ•œ์ •). ์ผœ๋ ค๋ฉด OAuth ํด๋ผ์ด์–ธํŠธ ID ๋ฐœ๊ธ‰(ยง3) + ๋„ค์ดํ‹ฐ๋ธŒ SDKโ†’idTokenโ†’`requestSessionHandoff` ๋ฐฐ์„ ์ด ํ•„์š”ํ•˜๋‹ค. "์ค€๋น„ ์ค‘" ๋ผ๋ฒจ์€ ์ž๋™ ํ™œ์„ฑํ™”๊ฐ€ ์•„๋‹ˆ๋ผ ๋ฏธ๊ตฌํ˜„ ํ‘œ์‹œ๋‹ค |
59
+
60
+ > ์นด๋ฉ”๋ผยท๋งˆ์ดํฌยทํŒŒ์ผ ์—…๋กœ๋“œ๋Š” ์…ธ์ด ๊ตฌํ˜„ํ•œ ๊ธฐ๋Šฅ์ด ์•„๋‹ˆ๋‹ค. https + ๊ถŒํ•œ ๋ฌธ์ž์—ดยท`mediaCapturePermissionGrantType=grant`ยทAndroid CAMERA๋กœ ์›น์˜ ๊ธฐ๋Šฅ์ด ๋™์ž‘ํ•˜๊ฒŒ ํ•ด์ฃผ๋Š” enablement๋‹ค.
61
+
62
+ ### 4.2 ์ œ์ถœ ์ „ ์ฒดํฌ๋ฆฌ์ŠคํŠธ
63
+
64
+ - [ ] ์˜คํ”„๋ผ์ธ์—์„œ ๋นˆ ํฐ ํ™”๋ฉด์ด ์•„๋‹ˆ๋ผ **๋„ค์ดํ‹ฐ๋ธŒ ์˜คํ”„๋ผ์ธ ํ™”๋ฉด**์ด ๋œจ๋Š”๊ฐ€ (์‹ค๊ธฐ๊ธฐ์—์„œ ๋น„ํ–‰๊ธฐ ๋ชจ๋“œ๋กœ ํ™•์ธ)
65
+ - [ ] ์ฒซ ๋กœ๋“œ ์ค‘ ๋นˆ ํ™”๋ฉด์ด ์•„๋‹ˆ๋ผ **๋กœ๋”ฉ ์ธ๋””์ผ€์ดํ„ฐ**๊ฐ€ ๋œจ๋Š”๊ฐ€ (์ฒซ/ํ•˜๋“œ ๋กœ๋“œ ํ•œ์ •; SPA ์ „ํ™˜์€ ์›น์ด ์ฒ˜๋ฆฌ)
66
+ - [ ] ์ฒซ ๋กœ๋“œ ์‹คํŒจ/ํฌ๋ž˜์‹œ ์‹œ **์—๋Ÿฌ ํ™”๋ฉด + ๋‹ค์‹œ ์‹œ๋„**(ํ†ต์งธ ์žฌ๋งˆ์šดํŠธ)๊ฐ€ ์žˆ๋Š”๊ฐ€
67
+ - [ ] ์™ธ๋ถ€ ๋งํฌ๊ฐ€ ์•ฑ ์•ˆ์— ๊ฐ‡ํžˆ์ง€ ์•Š๊ณ  ์‹œ์Šคํ…œ ๋ธŒ๋ผ์šฐ์ €๋กœ ์—ด๋ฆฌ๋Š”๊ฐ€
68
+ - [ ] **๋„ค์ดํ‹ฐ๋ธŒ ์ฐจ๋ณ„ ์š”์†Œ๋ฅผ ํ•˜๋‚˜ ์ด์ƒ** ๋”ํ–ˆ๋Š”๊ฐ€ (๊ถŒ์žฅ: ํ‘ธ์‹œ) โ€” ์•ˆ ํ•˜๋ฉด 4.2 ์œ„ํ—˜์ด ๋†’๋‹ค
69
+ - [ ] (์†Œ์…œ ๋กœ๊ทธ์ธ์„ ์ผฐ๋‹ค๋ฉด) **Sign in with Apple**์ด ๋™๋“ฑํ•˜๊ฒŒ ์žˆ๋Š”๊ฐ€ (ยง3, ์—†์œผ๋ฉด 4.8 ๊ฑฐ์ ˆ โ€” ์†Œ์…œ์„ ์•ˆ ์ผฐ์œผ๋ฉด ๋ฉด์ œ)
70
+ - [ ] **๋ฐฐํฌ๋œ ์›น**์— (์›น๋ทฐ์—์„œ ๋„๋‹ฌ ๊ฐ€๋Šฅํ•œ) **๊ณ„์ • ์‚ญ์ œ** ๊ฒฝ๋กœ๊ฐ€ ์žˆ๋Š”๊ฐ€ (์›น๋ทฐ ๋ Œ๋” = ์ธ์•ฑ ์ธ์ •; 5.1.1(v), ยง6)
71
+ - [ ] ์ผœ์ง€ ์•Š์€ ๊ถŒํ•œ์ด `Info.plist`/๋งค๋‹ˆํŽ˜์ŠคํŠธ์— ๋‚จ์•„ ์žˆ์ง€ ์•Š์€๊ฐ€ (๋ฏธ์‚ฌ์šฉ ๊ถŒํ•œ = ๊ฑฐ์ ˆ ์‚ฌ์œ )
72
+ - [ ] (ํ‘ธ์‹œ๋ฅผ ๋”ํ–ˆ๋‹ค๋ฉด) ๊ทธ๊ฒŒ **๋„ค์ดํ‹ฐ๋ธŒ ์ฐจ๋ณ„ ์š”์†Œ**๋กœ ๋ฆฌ๋ทฐ ๋…ธํŠธ์— ์„ค๋ช…๋ผ ์žˆ๋Š”๊ฐ€
73
+
74
+ ---
75
+
76
+ ## 3. ์†Œ์…œ ๋กœ๊ทธ์ธ (๐ŸŸก fast-follow โ€” v1์€ ๋น„ํ™œ์„ฑ scaffold)
77
+
78
+ ๋กœ๊ทธ์ธ์€ ์›น์˜ ๊ฒƒ์ด๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ์•ฑ์€ ๋กœ๊ทธ์ธ์— ์•„๋ฌด๊ฒƒ๋„ ํ•˜์ง€ ์•Š๋Š”๋‹ค. ์›น์˜ ๋กœ๊ทธ์ธ UI(์ด๋ฉ”์ผ/๋น„๋ฐ€๋ฒˆํ˜ธ ํฌํ•จ)๊ฐ€ ์›น๋ทฐ ์•ˆ์—์„œ ๊ทธ๋Œ€๋กœ ๋œจ๊ณ , ์ฟ ํ‚คยทJSยท์Šคํ† ๋ฆฌ์ง€๊ฐ€ ์ผœ์ ธ ์žˆ์–ด `@supabase/ssr`์ด ๊ทธ๋Œ€๋กœ ๋™์ž‘ํ•œ๋‹ค.
79
+
80
+ - ๋„ค์ดํ‹ฐ๋ธŒ ๋กœ๊ทธ์ธ ๋ชจ๋‹ฌ์€ opt-in scaffold๋‹ค. ์›น์ด `REQUEST_SESSION_INSTALL`์„ ๋ณด๋‚ผ ๋•Œ๋งŒ ๋œจ๊ณ , ์œ ์ผํ•˜๊ฒŒ ํ™œ์„ฑ์ธ "์ด๋ฉ”์ผ๋กœ ๊ณ„์†ํ•˜๊ธฐ" ๋ฒ„ํŠผ์€ ์ธ์ฆ ์—†์ด ๋ชจ๋‹ฌ์„ ๋‹ซ์•„ ์›น ๋กœ๊ทธ์ธ์œผ๋กœ ๋˜๋Œ๋ ค๋ณด๋‚ผ ๋ฟ์ด๋‹ค(๋ฆฌ๋กœ๋“œยท๋‚ด๋น„๊ฒŒ์ด์…˜ ์—†์Œ).
81
+ - ๋„ค์ดํ‹ฐ๋ธŒ ์†Œ์…œ ๋ฒ„ํŠผ(GoogleยทApple ์›ํด๋ฆญ)์€ ๋น„ํ™œ์„ฑ "์ค€๋น„ ์ค‘" ์Šคํ…์ด๋‹ค (`login.socialComingSoon`, `onPress` ์—†์Œ; Apple ๋ฒ„ํŠผ์€ iOS์—์„œ๋งŒ ํ‘œ์‹œ). ์ผœ๋Š” ๊ฑด fast-follow์ด๊ณ  ์ฝ˜์†” ์…‹์—…์ด ๋”ฐ๋ผ์˜จ๋‹ค.
82
+
83
+ ### ์™œ ์†Œ์…œ์€ ๋„ค์ดํ‹ฐ๋ธŒ์—ฌ์•ผ ํ•˜๋‚˜ (in-webview OAuth๋Š” ๋™์ž‘ํ•˜์ง€ ์•Š๋Š”๋‹ค)
84
+
85
+ > ์ž„๋ฒ ๋””๋“œ ์›น๋ทฐ ์•ˆ์—์„œ๋Š” ์†Œ์…œ OAuth๊ฐ€ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š”๋‹ค. Google์€ ์ž„๋ฒ ๋””๋“œ ์›น๋ทฐ์˜ OAuth๋ฅผ ์ฐจ๋‹จํ•˜๊ณ ([`disallowed_useragent`, 2021/2023 ์‹œํ–‰](https://developers.googleblog.com/upcoming-security-changes-to-googles-oauth-20-authorization-endpoint-in-embedded-webviews/)), [RFC 8252](https://datatracker.ietf.org/doc/html/rfc8252)๋Š” ์ž„๋ฒ ๋””๋“œ user-agent๋ฅผ ๊ธˆ์ง€ํ•œ๋‹ค.
86
+ > ๊ทธ๋ž˜์„œ ์†Œ์…œ ๋กœ๊ทธ์ธ์€ ๋ฐ˜๋“œ์‹œ **๋„ค์ดํ‹ฐ๋ธŒ**(์‹œ์Šคํ…œ ๋ธŒ๋ผ์šฐ์ € / ๋„ค์ดํ‹ฐ๋ธŒ credential picker)์—ฌ์•ผ ํ•œ๋‹ค.
87
+
88
+ ### ๊ทœ์น™: ์†Œ์…œ์„ ์“ฐ๋ฉด Sign in with Apple ๊ฐ•์ œ (Apple 4.8 โ€” ์กฐ๊ฑด๋ถ€)
89
+
90
+ > 4.8์€ ์กฐ๊ฑด๋ถ€๋‹ค. Google์ด๋‚˜ ๋‹ค๋ฅธ ์„œ๋“œํŒŒํ‹ฐ ์†Œ์…œ ๋กœ๊ทธ์ธ์„ (์ฃผ ๊ณ„์ •์šฉ์œผ๋กœ) ํ•˜๋‚˜๋ผ๋„ ์ผœ๋ฉด, iOS์—์„œ๋Š” "Sign in with Apple"์„ ๋™๋“ฑํ•˜๊ฒŒ ๋„ฃ์–ด์•ผ ํ•œ๋‹ค.
91
+ > ์›น์ด Supabase ์ด๋ฉ”์ผ/๋น„๋ฐ€๋ฒˆํ˜ธ๋งŒ ์“ฐ๋ฉด 4.8์€ ์ ์šฉ๋˜์ง€ ์•Š๋Š”๋‹ค.
92
+ > ์†Œ์…œ์„ ์ผค ๊ฒฝ์šฐ, ์ด๊ฑด ๊ตฌ์กฐ์  ๋ถˆ๋ณ€์‹์ด์ž ๋ฐฑ์—”๋“œ(Supabase Apple provider) ์‹ค๋ฐฐ์„ ๊นŒ์ง€ ์ง„๋‹จ ๋Œ€์ƒ์ด๋‹ค. "Google๋งŒ ์ผœ๊ณ  Apple์€ ๋‚˜์ค‘์—"๋Š” **๋ถˆ๊ฐ€๋Šฅ**ํ•˜๋‹ค(๋‘˜์€ ๊ฐ™์ด ์ผœ์ง„๋‹ค).
93
+
94
+ ### Google OAuth ํด๋ผ์ด์–ธํŠธ ID (3์ข…)
95
+
96
+ Google์€ ํ”Œ๋žซํผ๋งˆ๋‹ค OAuth ํด๋ผ์ด์–ธํŠธ๊ฐ€ ํ•„์š”ํ•˜๋‹ค. ์ฝ”๋“œ์—๋Š” **webClientId(Web ํƒ€์ž…)๋งŒ** ๋„ฃ๋Š”๋‹ค.
97
+
98
+ | ํด๋ผ์ด์–ธํŠธ | ์–ด๋””์„œ | ์šฉ๋„ |
99
+ |---|---|---|
100
+ | Web | Google Cloud Console โ†’ Credentials | ์ฝ”๋“œ์˜ `webClientId` (idToken audience) |
101
+ | iOS | ๋™์ผ | iOS ๋„ค์ดํ‹ฐ๋ธŒ ๋กœ๊ทธ์ธ |
102
+ | Android | ๋™์ผ | Android ๋„ค์ดํ‹ฐ๋ธŒ ๋กœ๊ทธ์ธ |
103
+
104
+ ํ•จ์ •:
105
+ - iOS reversed URL scheme์€ ํ”Œ๋Ÿฌ๊ทธ์ธ์— ์ˆ˜๋™์œผ๋กœ ๋ถ™์—ฌ๋„ฃ๋Š”๋‹ค (์ž๋™ ๊ณ„์‚ฐ ์•„๋‹˜). ๋ˆ„๋ฝ ์‹œ iOS ์†Œ์…œ ๋กœ๊ทธ์ธ ๋ฌดํ•œ ๋กœ๋”ฉ.
106
+ - SHA-1 ์ง€๋ฌธ์€ ๋ชจ๋“  ์„œ๋ช… ํ‚ค๋ฅผ ๋“ฑ๋กํ•œ๋‹ค. Play ์•ฑ ์„œ๋ช… ํ‚ค + EAS ์—…๋กœ๋“œ ํ‚ค(internal/dev ๋นŒ๋“œ ํ‚ค ํฌํ•จ). ์ผ๋ถ€๋งŒ ๋“ฑ๋กํ•˜๋ฉด `DEVELOPER_ERROR`.
107
+ - Google SA(์„œ๋น„์Šค ๊ณ„์ •)๋Š” Cloud Console(์ƒ์„ฑ+API Enable)๊ณผ Play Console(SA ์ดˆ๋Œ€ยท๊ถŒํ•œ) ๋‘ ์ฝ˜์†”์„ ๊ฑฐ์นœ๋‹ค (๋…ธ์ถœ๊นŒ์ง€ ~24h ์ง€์—ฐ).
108
+
109
+ ### Apple Sign In
110
+
111
+ ๊ฒŒ์ดํŠธ๋กœ ๋‘ ๋ฐฉ์‹ ์ค‘ ํ•˜๋‚˜๋ฅผ ๊ณ ๋ฅธ๋‹ค:
112
+
113
+ | ๋ฐฉ์‹ | ํ•„์š”ํ•œ ๊ฒƒ | ๊ถŒ์žฅ |
114
+ |---|---|---|
115
+ | **๋„ค์ดํ‹ฐ๋ธŒ idToken** (๊ธฐ๋ณธ) | bundle ID๋งŒ | โœ… โ€” Services ID ํšŒํ”ผ |
116
+ | ์›น OAuth | Apple Services ID + `.p8` ํ‚ค + 6๊ฐœ์›”๋งˆ๋‹ค ์‹œํฌ๋ฆฟ ๊ฐฑ์‹  | ํ”ผํ•œ๋‹ค |
117
+
118
+ > **ํ•œ๊ตญ ๊ฐœ๋ฐœ์ž (2026-01-01~)**: Apple Services ID ๋“ฑ๋ก/๊ฐฑ์‹  ์‹œ server-to-server ์—”๋“œํฌ์ธํŠธ๊ฐ€ ํ•„์ˆ˜๊ฐ€ ๋๋‹ค ([Apple ๊ณต์ง€](https://developer.apple.com/news/?id=j9zukcr6)).
119
+ > ์ด๊ฑด ์›น OAuth ๋ฐฉ์‹์—๋งŒ ํ•ด๋‹นํ•œ๋‹ค. ๊ธฐ๋ณธ์ธ ๋„ค์ดํ‹ฐ๋ธŒ idToken ๋ฐฉ์‹์„ ์“ฐ๋ฉด Services ID ์ž์ฒด๊ฐ€ ์—†์–ด ์ด ์š”๊ตฌ๋ฅผ ํšŒํ”ผํ•œ๋‹ค.
120
+ > ๊ทธ๋ž˜์„œ ํ•œ๊ตญ Owner์—๊ฒŒ๋Š” ๋„ค์ดํ‹ฐ๋ธŒ idToken ๋ฐฉ์‹์„ ๊ฐ•๋ ฅ ๊ถŒ์žฅํ•œ๋‹ค.
121
+
122
+ ํ•ธ๋“œ์˜คํ”„ ํ•จ์ˆ˜(`requestSessionHandoff`)๋Š” ๊ตฌํ˜„ยทํ…Œ์ŠคํŠธ๋์œผ๋‚˜ ํ˜ธ์ถœ์ž๊ฐ€ ์—†๋‹ค. ์ผœ๋ ค๋ฉด ์ž…๋ ฅ์ธ ๋„ค์ดํ‹ฐ๋ธŒ idToken ํš๋“๋„ ๋ฏธ๋ฐฐ์„ ์ด๊ณ , ์ถœ๋ ฅ์„ ๋ฐ›๋Š” ์›น ๋ผ์šฐํŠธ(POST `/auth/app-bridge` + nonce consume)๋Š” ์ด ์•ฑ์ด ์•„๋‹ˆ๋ผ `docs/web-adapter`์—์„œ ์›น repo์— ์„ค์น˜ํ•ด์•ผ ํ•œ๋‹ค. `secureSession` get/set๋„ v1 ํ˜ธ์ถœ์ž ์—†์Œ. ๊ธฐ๋ณธ ๋กœ๊ทธ์ธ์€ ์›น์˜ ๊ฒƒ์ด๋‹ค. ์‹ค์ œ ์ผœ๊ธฐยท์ฝ˜์†” ์…‹์—…์€ fast-follow์ด๋ฉฐ ์ด ๋ฌธ์„œ๊ฐ€ ๋‹จ๊ณ„๋ณ„ ์ ˆ์ฐจ๋ฅผ ๋‹ด๋Š”๋‹ค(์ „์šฉ ์ถœ์‹œ ์Šคํ‚ฌ์€ v1 ์ดํ›„).
123
+
124
+ ---
125
+
126
+ ## 4. EAS Build + Submit ํ๋ฆ„ (๐ŸŸข ๋Œ€๋ถ€๋ถ„ ์ž๋™)
127
+
128
+ EAS๊ฐ€ ์„œ๋ช…์„ ๊ด€๋ฆฌํ•œ๋‹ค. Owner๊ฐ€ fastlane์„ ์ง์ ‘ ๊ตฌ์„ฑํ•  ์ผ์€ ์—†๋‹ค. `eas build`/`eas submit`์ด ๋นŒ๋“œ + ํ…Œ์ŠคํŠธ ์ฑ„๋„(TestFlight / Play Internal) ์—…๋กœ๋“œ๊นŒ์ง€ ํ•ด์ฃผ๊ณ , ๋‚˜๋จธ์ง€(์Šคํ† ์–ด ๋ฆฌ์ŠคํŒ…ยท์Šคํฌ๋ฆฐ์ƒทยทApp Privacyยท"Submit for Review"ยทPlay production ์Šน๊ธ‰ยทSA JSON)๋Š” GUI/์ˆ˜๋™์ด๋‹ค.
129
+
130
+ ```bash
131
+ # 1) ๋นŒ๋“œ (ํด๋ผ์šฐ๋“œ) โ€” production ๋นŒ๋“œ ํ•˜๋‚˜๋กœ ํ…Œ์ŠคํŠธ์™€ ์ถœ์‹œ๋ฅผ ๋ชจ๋‘ ์ถฉ๋‹น
132
+ npx eas-cli build --profile production --platform all # iOS IPA + Android AAB
133
+
134
+ # 2) ์ œ์ถœ (์Šคํ† ์–ด ํ…Œ์ŠคํŠธ ์ฑ„๋„๊นŒ์ง€ โ€” ๊ณต๊ฐœ ์‹ฌ์‚ฌ๋Š” ์•„๋‹˜, ยง5)
135
+ npx eas-cli submit --profile production --platform ios # โ†’ TestFlight
136
+ npx eas-cli submit --profile production --platform android # โ†’ Play ๋‚ด๋ถ€ ํ…Œ์ŠคํŠธ ํŠธ๋ž™
137
+ ```
138
+
139
+ > ์ฒซ ์ œ์ถœ์€ ๋‘ ์Šคํ† ์–ด๊ฐ€ ๋‹ค๋ฅด๋‹ค:
140
+ > - **iOS** โ€” EAS๊ฐ€ ASC ์•ฑ ๋ ˆ์ฝ”๋“œ๋ฅผ (์—†์œผ๋ฉด) ์ž๋™ ์ƒ์„ฑํ•œ๋‹ค โ†’ ์ฒซ `eas submit -p ios`๊ฐ€ ๊ทธ๋Œ€๋กœ TestFlight๊นŒ์ง€ ๊ฐ„๋‹ค ([Expo Submit iOS](https://docs.expo.dev/submit/ios/)).
141
+ > - **Android** โ€” Google Play API๋Š” ์ฒซ ๋ฆด๋ฆฌ์Šค๋ฅผ ๋งŒ๋“ค์ง€ ๋ชปํ•œ๋‹ค. Owner๊ฐ€ Play Console์—์„œ ์•ฑ์„ ๋งŒ๋“ค๊ณ  ์ฒซ AAB๋ฅผ ์ˆ˜๋™ ์—…๋กœ๋“œํ•ด์•ผ(์•„๋ฌด ํŠธ๋ž™์ด๋‚˜) ํ•˜๋ฉฐ, ๊ทธ ๋‹ค์Œ๋ถ€ํ„ฐ `eas submit -p android`๊ฐ€ ๋™์ž‘ํ•œ๋‹ค ([Expo: first Android submission](https://github.com/expo/fyi/blob/main/first-android-submission.md)).
142
+
143
+ ### EAS๊ฐ€ ์ž๋™ ์ƒ์„ฑยท๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ (๐ŸŸข โ€” .cer/.jks ์† ์•ˆ ๋Œ)
144
+
145
+ - iOS: ๋ฐฐํฌ ์ธ์ฆ์„œ, ํ”„๋กœ๋น„์ €๋‹ ํ”„๋กœํŒŒ์ผ, APNs ํ‚ค(ํ‘ธ์‹œ์šฉ)
146
+ - Android: ์—…๋กœ๋“œ ํ‚ค์Šคํ† ์–ด
147
+ - iOS ์ œ์ถœ์šฉ ASC API ํ‚ค: EAS ์ž๋™ ์ƒ์„ฑ (Account Holder๊ฐ€ 1ํšŒ 'Request Access' ์•ฝ๊ด€ ๋™์˜ ์„ ํ–‰) โ€” ๊ถŒ์žฅ. (`eas.json`์—” ๋Œ€์•ˆ์ธ `appleId` ๋ฐฉ์‹ placeholder๋„ ์žˆ์œผ๋‚˜ ๋‘˜ ์ค‘ ํ•˜๋‚˜๋งŒ.)
148
+
149
+ ### ์ˆ˜๋™์ธ ๊ฒƒ (๐ŸŸก)
150
+
151
+ - **Play ์„œ๋น„์Šค ๊ณ„์ • JSON** (Android ์ œ์ถœ ์ธ์ฆ): ํ•œ ๋ฒˆ๋งŒ ๋งŒ๋“ ๋‹ค. `eas.json`์—” ๊ฒฝ๋กœ๋ฅผ ๋„ฃ์ง€ ์•Š๋Š”๋‹ค(์‹œํฌ๋ฆฟ ์ปค๋ฐ‹ ์œ„ํ—˜). ์ฒซ `eas submit -p android`๊ฐ€ JSON ๊ฒฝ๋กœ๋ฅผ ๋ฌผ์œผ๋ฉด ๊ทธ๋•Œ ์ฃผ๊ณ , EAS๊ฐ€ ์„œ๋ฒ„์— ์ €์žฅํ•œ๋‹ค(`$ENV` ๋ณด๊ฐ„ ๋ฏธ์ง€์›). ๋งŒ๋“œ๋Š” ์ˆœ์„œ ([Expo ์ ˆ์ฐจ](https://github.com/expo/fyi/blob/main/creating-google-service-account.md)):
152
+ 1. Cloud Console โ†’ **Google Play Android Developer API**(`androidpublisher.googleapis.com`) **Enable**
153
+ 2. IAM & Admin โ†’ **์„œ๋น„์Šค ๊ณ„์ • ์ƒ์„ฑ** (์—ญํ•  ์ง€์ •์€ skip)
154
+ 3. ๊ทธ ๊ณ„์ • โ†’ ํ‚ค โ†’ **JSON ํ‚ค ์ƒ์„ฑยท๋‹ค์šด๋กœ๋“œ** (์‹œํฌ๋ฆฟ, ์ปค๋ฐ‹ ๊ธˆ์ง€)
155
+ 4. Play Console โ†’ **์‚ฌ์šฉ์ž ๋ฐ ๊ถŒํ•œ** โ†’ ๊ทธ SA ์ด๋ฉ”์ผ **์ดˆ๋Œ€** + ์•ฑ/๊ณ„์ • ๊ถŒํ•œ ๋ถ€์—ฌ (๊ถŒํ•œ ๋ฐ˜์˜ ์ง€์—ฐ ๊ฐ€๋Šฅ)
156
+ - **Android FCM v1 ์„œ๋น„์Šค ๊ณ„์ •**(ํ‘ธ์‹œ์šฉ): Firebase Console์—์„œ ์ˆ˜๋™ ์ƒ์„ฑ โ†’ EAS ์—…๋กœ๋“œ.
157
+
158
+ > `eas.json`์—” public ๊ฐ’๋งŒ ์ปค๋ฐ‹ํ•œ๋‹ค. ์‹œํฌ๋ฆฟ์€ EAS ์„œ๋ฒ„์— ๋‘”๋‹ค.
159
+ > `google-services.json`(publicยท์ปค๋ฐ‹) โ†” FCM SA JSON(์‹œํฌ๋ฆฟ) โ†” Play ์ œ์ถœ SA JSON. ์…‹์€ ๋ณ„๊ฐœ๋‹ค. ํ˜ผ๋™ํ•˜์ง€ ๋ง๋ผ.
160
+
161
+ ### EAS ๋ฌด๋ฃŒ ํ‹ฐ์–ด (์„ ๊ณ ์ง€)
162
+
163
+ - iOS 15ํšŒ + Android 15ํšŒ / ์›” ยท ๋™์‹œ์„ฑ 1 ยท Low ์šฐ์„ ์ˆœ์œ„ ยท ๋นŒ๋“œ๋‹น ~45๋ถ„ ([Expo ์š”๊ธˆ](https://expo.dev/pricing))
164
+ - ์ฒซ ๋นŒ๋“œ๋Š” 10โ€“20๋ถ„ + ํ ๋Œ€๊ธฐ๋‹ค. ๋ฉˆ์ถ˜ ๊ฒŒ ์•„๋‹ˆ๋‹ค.
165
+ - JS ๋ณ€๊ฒฝ์€ ๋นŒ๋“œ ํ’€์„ ์†Œ๋ชจํ•˜์ง€ ์•Š์ง€๋งŒ(OTA), ์ดˆ๊ธฐ ๋„ค์ดํ‹ฐ๋ธŒ ์…‹์—…์—” iOS ๋นŒ๋“œ ์ˆ˜ ๊ฐœ๋ฅผ ์†Œ๋ชจํ•  ์ˆ˜ ์žˆ๋‹ค.
166
+
167
+ ---
168
+
169
+ ## 5. TestFlight / Play Internal โ†’ ๊ณต๊ฐœ ์ถœ์‹œ (๐Ÿ”ด ํŠธ๋žฉ)
170
+
171
+ > `eas submit`์€ ๊ณต๊ฐœ ์‹ฌ์‚ฌ ์ œ์ถœ์„ ํ•˜์ง€ ์•Š๋Š”๋‹ค.
172
+ > iOS๋Š” TestFlight๊นŒ์ง€, Android๋Š” internal ํŠธ๋ž™๊นŒ์ง€๋งŒ ์˜ฌ๋ฆฐ๋‹ค.
173
+
174
+ ๊ณต๊ฐœ ์ถœ์‹œ๋Š” ๐ŸŸก ์ˆ˜๋™ + ๋ช…์‹œ์  confirm์ด๋‹ค:
175
+
176
+ | ํ”Œ๋žซํผ | ํ…Œ์ŠคํŠธ ์ฑ„๋„ (eas submit ๋„๋‹ฌ์ ) | ๊ณต๊ฐœ ์ถœ์‹œ (์ˆ˜๋™) |
177
+ |---|---|---|
178
+ | iOS | TestFlight | App Store Connect์—์„œ **"Submit for Review"** |
179
+ | Android | Internal ํŠธ๋ž™ | **๋น„๊ณต๊ฐœ(closed) ํ…Œ์ŠคํŠธ 12๋ช…ยท14์ผ ํ†ต๊ณผ ํ›„** production ์Šน๊ธ‰ |
180
+
181
+ - ๋‚ด๋ถ€(internal) ํ…Œ์ŠคํŠธ๋Š” 12ยท14 ๊ฒŒ์ดํŠธ์— ์นด์šดํŠธ๋˜์ง€ ์•Š๋Š”๋‹ค. `eas submit`์ด ์˜ฌ๋ฆฌ๋Š” ๋‚ด๋ถ€ ํŠธ๋ž™์€ Owner ๋ณธ์ธ ํ™•์ธ์šฉ์ด๊ณ , production ์ „์—” ๋น„๊ณต๊ฐœ(closed) ํŠธ๋ž™์— ํ…Œ์Šคํ„ฐ 12๋ช…ยท14์ผ ์—ฐ์†์„ ๋”ฐ๋กœ ์ฑ„์›Œ์•ผ ํ•œ๋‹ค(๊ตฌ๊ธ€์ด 14์ผ๊ฐ„ ํ…Œ์Šคํ„ฐ ์‹ค์‚ฌ์šฉ ์‹œ๊ฐ„๊นŒ์ง€ ์ธก์ •). ์กฐ์ง(D-U-N-S) ๊ณ„์ •์€ ์ด ๊ฒŒ์ดํŠธ๋ฅผ ๋ฉด์ œ๋ฐ›๋Š”๋‹ค.
182
+ - Android ์ฒซ AAB๋Š” Play Console์— ์ˆ˜๋™์œผ๋กœ 1ํšŒ ์—…๋กœ๋“œํ•ด์•ผ ํ•œ๋‹ค (Play API๋Š” ์ฒซ ๋ฆด๋ฆฌ์Šค๋ฅผ ๋ชป ๋งŒ๋“ ๋‹ค. ์ฒซ ์ž๋™ ์ œ์ถœ ์‹คํŒจ๋Š” ์ •์ƒ์ด๋‹ˆ ์„ ๊ณ ์ง€ํ•˜๋ผ).
183
+ - ์ดˆ๊ธฐ ํ™•์ธ๋„ production ๋นŒ๋“œ๋ฅผ TestFlightยทPlay ๋‚ด๋ถ€ ํ…Œ์ŠคํŠธ๋กœ ๋ณด๋‚ด ์‹ค๊ธฐ๊ธฐ์—์„œ ํ•œ๋‹ค. ๋ณ„๋„ preview/ad-hoc ๋นŒ๋“œ๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค(๊ฐ™์€ ๋นŒ๋“œ๋ฅผ ๊ทธ๋Œ€๋กœ ์ถœ์‹œ๋กœ ์Šน๊ธ‰ โ†’ EAS ๋นŒ๋“œ ์ˆ˜ ์ ˆ์•ฝ). ๋น ๋ฅธ ์‚ฌ์ด๋“œ๋กœ๋“œ๊ฐ€ ๊ผญ ํ•„์š”ํ•˜๋ฉด `distribution: "internal"` ํ”„๋กœํŒŒ์ผ์„ ๋”ฐ๋กœ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.
184
+
185
+ ---
186
+
187
+ ## 6. ์ปดํ”Œ๋ผ์ด์–ธ์Šค (๐ŸŸก ์ˆ˜๋™)
188
+
189
+ - **๊ณ„์ • ์‚ญ์ œ (5.1.1(v))** ([Apple ๊ฐ€์ด๋“œ](https://developer.apple.com/support/offering-account-deletion-in-your-app/)): ์ธ์•ฑ ์‚ญ์ œ ๊ฒฝ๋กœ๊ฐ€ ํ•„์ˆ˜๋‹ค (๋น„ํ™œ์„ฑํ™”๋กœ๋Š” ๋ถˆ์ถฉ๋ถ„). ์ด ์…ธ์€ ๊ณ„์ • UI๋ฅผ ์›น์— ์œ„์ž„ํ•˜๋ฏ€๋กœ,
190
+ ๋ฐฐํฌ๋œ ์›น์— ์‚ญ์ œ ํ™”๋ฉด์ด ์žˆ์–ด์•ผ ํ•œ๋‹ค. ์›น๋ทฐ ์•ˆ์—์„œ ๋„๋‹ฌ ๊ฐ€๋Šฅํ•˜๋ฉด "์ธ์•ฑ"์œผ๋กœ ์ธ์ •๋œ๋‹ค. ๋„ค์ดํ‹ฐ๋ธŒ ์†Œ์…œ ํฌํ•จ
191
+ ๋ชจ๋“  ๋กœ๊ทธ์ธ์—์„œ ๋„๋‹ฌ ๊ฐ€๋Šฅํ•ด์•ผ ํ•˜๊ณ , ์„œ๋ฒ„์—์„œ `auth.admin.deleteUser` (server-only)๋กœ ์‹ค์ œ ์‚ญ์ œํ•œ๋‹ค.
192
+ - **์„ธ ํ”„๋ผ์ด๋ฒ„์‹œ ์‚ฐ์ถœ๋ฌผ** โ€” App Privacy(iOS ๋ผ๋ฒจ) ยท Data Safety(Android) ยท `PrivacyInfo.xcprivacy` โ€” ๋Š” taxonomy๊ฐ€ ๋‹ฌ๋ผ
193
+ ๋ณต๋ถ™์ด ์•ˆ ๋œ๋‹ค. ๋‹จ์ผ ๋ฐ์ดํ„ฐ ์ธ๋ฒคํ† ๋ฆฌ์—์„œ ๊ฐ๊ฐ ๋งคํ•‘ํ•œ๋‹ค.
194
+ - **ATT**: ๊ธฐ๋ณธ No (SupabaseยทSentry๋Š” ๋น„์ถ”์ ). ๋‹จ ์›น๋ทฐ๊ฐ€ ๋กœ๋“œํ•˜๋Š” ์›น์˜ ํŠธ๋ž˜์ปค(GA4ยทPixel ๋“ฑ)๋Š” ๊ฐœ๋ฐœ์ž ์ฑ…์ž„์ด๋‹ค โ†’
195
+ ๋ฐฐํฌ๋œ ์›น์˜ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹ค์ ๊ฒ€ํ•˜๋ผ.
196
+ - ์Šคํฌ๋ฆฐ์ƒท ยท ์—ฐ๋ น๋“ฑ๊ธ‰(IARC) = ๐ŸŸก ์ˆ˜๋™.
197
+
198
+ ---
199
+
200
+ ## ํ•œ๋ˆˆ ์š”์•ฝ: v1 vs fast-follow
201
+
202
+ | | v1 (์ง€๊ธˆ ๋“ค์–ด๊ฐ) | fast-follow (v1 ๋ถ€์žฌ, ์ผœ๋Š” ์ ˆ์ฐจ๋Š” ์œ„์—) |
203
+ |---|---|---|
204
+ | ์…ธ์ด ์ฑ„์šฐ๋Š” ๊ฒƒ | ์˜คํ”„๋ผ์ธ ํ™”๋ฉด + (์ฒซ/ํ•˜๋“œ ๋กœ๋“œยทํฌ๋ž˜์‹œ ํ•œ์ •) ๋กœ๋”ฉยท์—๋Ÿฌ + ๋’ค๋กœ๊ฐ€๊ธฐ + ์™ธ๋ถ€ ๋งํฌ + safe-area + ์นด๋ฉ”๋ผยทํŒŒ์ผ ๊ถŒํ•œ ์—ฐ๊ฒฐ | โ€” |
205
+ | ๋กœ๊ทธ์ธ | **์›น์˜ ๊ฒƒ** (์›น ๋กœ๊ทธ์ธ UI๊ฐ€ ์›น๋ทฐ ์•ˆ์—์„œ ๊ทธ๋Œ€๋กœ). ๋„ค์ดํ‹ฐ๋ธŒ ๋ชจ๋‹ฌ์€ opt-in scaffold, ์†Œ์…œ ๋ฒ„ํŠผ์€ ๋น„ํ™œ์„ฑ "์ค€๋น„ ์ค‘" ์Šคํ… | ๋„ค์ดํ‹ฐ๋ธŒ Google/Apple ์›ํด๋ฆญ (์†Œ์…œ ์ผœ๋ฉด Sign in with Apple ๋™๋ฐ˜) |
206
+ | ํ‘ธ์‹œ | ๋ถ€์žฌ (forward-compat ๋ฉ”์‹œ์ง€ ํƒ€์ž…๋งŒ) | AI๊ฐ€ ์š”์ฒญ ์‹œ ๊ตฌํ˜„ (4.2์šฉ ๊ถŒ์žฅ ๋„ค์ดํ‹ฐ๋ธŒ ์ฐจ๋ณ„ ์š”์†Œ) |
207
+ | ์ƒ์ฒด์ธ์ฆ | ๋ถ€์žฌ | v1 ์ดํ›„ |
208
+ | ์ถœ์‹œ | EAS Build/Submit ํ๋ฆ„ ๋ฌธ์„œํ™” | ์ฒซ ๊ณต๊ฐœ ์‹ฌ์‚ฌ ์ œ์ถœ (ยง5 ์ ˆ์ฐจ๋กœ ์•ˆ๋‚ด) |
209
+
210
+ ---
211
+
212
+ ## ์ถœ์ฒ˜ (Sources)
213
+
214
+ ์™ธ๋ถ€ ์ •์ฑ…ยท๋™์ž‘ ์ฃผ์žฅ์˜ ๊ถŒ์œ„ ์žˆ๋Š” ์ถœ์ฒ˜. (์•ฑ ์ž์ฒด ๋™์ž‘์€ ์ฝ”๋“œยท๋‹ค๋ฅธ ๊ฐ€์ด๋“œ๊ฐ€ SSOT๋‹ค.)
215
+
216
+ **Apple**
217
+
218
+ - [App Store Review Guidelines](https://developer.apple.com/app-store/review/guidelines/) โ€” 4.2(์ตœ์†Œ ๊ธฐ๋Šฅ)ยท4.8(Sign in with Apple)ยท5.1.1(v)(๊ณ„์ • ์‚ญ์ œ)
219
+ - [๊ณ„์ • ์‚ญ์ œ ์š”๊ฑด ๊ฐ€์ด๋“œ](https://developer.apple.com/support/offering-account-deletion-in-your-app/) โ€” 5.1.1(v)
220
+ - [Sign in with Apple โ€” ํ•œ๊ตญ server-to-server ์š”๊ฑด(2026-01-01~)](https://developer.apple.com/news/?id=j9zukcr6) ยท [S2S ์•Œ๋ฆผ ์„ค์ • help](https://developer.apple.com/help/account/configure-app-capabilities/enabling-server-to-server-notifications/)
221
+ - [Apple Developer Program](https://developer.apple.com/programs/)
222
+
223
+ **Google Play**
224
+
225
+ - [์‹ ๊ทœ ๊ฐœ์ธ๊ณ„์ • ํ…Œ์ŠคํŠธ ์š”๊ฑด โ€” closed 12๋ช…ยท14์ผ](https://support.google.com/googleplay/android-developer/answer/14151465)
226
+ - [ํ…Œ์ŠคํŠธ ํŠธ๋ž™ ์„ค์ • โ€” internalยทclosedยทopen](https://support.google.com/googleplay/android-developer/answer/9845334)
227
+
228
+ **Expo / EAS**
229
+
230
+ - [EAS Submit ๊ฐœ์š”](https://docs.expo.dev/submit/introduction/) ยท [iOS](https://docs.expo.dev/submit/ios/) ยท [Android](https://docs.expo.dev/submit/android/)
231
+ - [์ฒซ Android ์ œ์ถœ์€ ์ˆ˜๋™ ์—…๋กœ๋“œ ํ•„์š”](https://github.com/expo/fyi/blob/main/first-android-submission.md)
232
+ - [Play ์„œ๋น„์Šค ๊ณ„์ • JSON ๋งŒ๋“ค๊ธฐ](https://github.com/expo/fyi/blob/main/creating-google-service-account.md) ยท [ASC API ํ‚ค ๋งŒ๋“ค๊ธฐ](https://github.com/expo/fyi/blob/main/creating-asc-api-key.md)
233
+ - [eas.json ์„ค์ •](https://docs.expo.dev/eas/json/) ยท [๋‚ด๋ถ€ ๋ฐฐํฌ(internal distribution)](https://docs.expo.dev/build/internal-distribution/) ยท [EAS Build์šฉ Apple Developer ์—ญํ• ](https://docs.expo.dev/app-signing/apple-developer-program-roles-and-permissions/)
234
+ - [์š”๊ธˆยท๋ฌด๋ฃŒ ํ‹ฐ์–ด ํ•œ๋„](https://expo.dev/pricing) ยท [ํ”Œ๋žœ](https://docs.expo.dev/billing/plans/)
235
+
236
+ **OAuth / ๋ณด์•ˆ**
237
+
238
+ - [Google: ์ž„๋ฒ ๋””๋“œ ์›น๋ทฐ OAuth ์ฐจ๋‹จ ๊ณต์ง€(`disallowed_useragent`)](https://developers.googleblog.com/upcoming-security-changes-to-googles-oauth-20-authorization-endpoint-in-embedded-webviews/)
239
+ - [RFC 8252 โ€” OAuth 2.0 for Native Apps](https://datatracker.ietf.org/doc/html/rfc8252)
@@ -0,0 +1,17 @@
1
+ ---
2
+ name: vercel-cron
3
+ description: Rules for adding Vercel Cron jobs in this template. Use when adding scheduled tasks or periodic jobs.
4
+ user-invocable: false
5
+ ---
6
+
7
+ # vercel-cron
8
+
9
+ Vercel Cron ์ถ”๊ฐ€ ์‹œ ๋ถ„๊ธฐยท๋กœ๊ทธยทํ…Œ์ŠคํŠธ ํ•จ์ •์„ ์งš๋Š”๋‹ค.
10
+
11
+ ์ฃผ๊ธฐ๋‚˜ ๋ถ€ํ•˜๊ฐ€ Hobby ํ•œ๋„์™€ ๋ถ€๋”ชํž ๊ฒƒ ๊ฐ™์œผ๋ฉด Owner์—๊ฒŒ ๋จผ์ € ์•Œ๋ฆฐ๋‹ค.
12
+
13
+ - **prod์—์„œ๋งŒ ์‹คํ–‰ํ•œ๋‹ค.** `env.APP_ENV !== "production"`์ด๋ฉด no-op์œผ๋กœ ๋‘”๋‹ค. preview์—์„œ dev DB์™€ ์™ธ๋ถ€ API๋ฅผ ๋‚ญ๋น„ํ•˜๋Š” ์ผ์„ ๋ง‰๋Š”๋‹ค.
14
+ - ์„ฑ๊ณต๊ณผ ์‹คํŒจ๋ฅผ ๋ชจ๋‘ logger๋กœ ๊ธฐ๋กํ•œ๋‹ค. ์„ฑ๊ณต์€ `audit`, ์‹คํŒจ๋Š” `error`๋กœ ๋‚จ๊ธด๋‹ค. Sentry์™€ logs ์†ก์ถœ์€ ์ž๋™์œผ๋กœ ์ด๋ค„์ง„๋‹ค.
15
+ - ํ…Œ์ŠคํŠธ ํ•จ์ •: `env`๋Š” ๋ชจ๋“ˆ ๋กœ๋“œ ์‹œ ํ•œ ๋ฒˆ๋งŒ parseํ•˜๋ฏ€๋กœ `vi.stubEnv`๊ฐ€ ๋“ฃ์ง€ ์•Š๋Š”๋‹ค. `vi.mock("@/lib/env.server")`๋กœ ํ†ต์งธ ๊ต์ฒดํ•œ๋‹ค.
16
+
17
+ ๊ทธ ์™ธ(ํ—ค๋” ๊ฒ€์ฆยทidempotentยท`CRON_SECRET`ยท`vercel.json`ยท`env.server.ts` ๋“ฑ)๋Š” Vercel docs์™€ ์ฝ”๋“œ ์ฃผ์„์„ ๋”ฐ๋ฅธ๋‹ค.
@@ -0,0 +1,33 @@
1
+ ---
2
+ name: warmup
3
+ description: Verify the AI agent's tools and environment (CLI installs, logins) and install/audit dependencies in web/ (and mobile/ when present), fixing issues where possible. Use when the Owner runs /warmup, just opened the workspace, or before tasks that depend on external CLIs working.
4
+ ---
5
+
6
+ # /warmup
7
+
8
+ AI(CLI agent)๊ฐ€ ์ด ์›Œํฌ์ŠคํŽ˜์ด์Šค์—์„œ ์ž‘์—…ํ•  ์ค€๋น„๊ฐ€ ๋๋Š”์ง€ ์ ๊ฒ€ํ•œ๋‹ค.
9
+ ๋„๊ตฌยท์ž๊ฒฉยทํ™˜๊ฒฝ๊ณผ ํ”„๋กœ์ ํŠธ์˜ ์‹คํ–‰ ํ™˜๊ฒฝ์„ ์ •์ƒํ™”ํ•œ๋‹ค.
10
+
11
+ ์Šค์Šค๋กœ ๋ฐ”๋กœ์žก์„ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ ์ž์œจ๋กœ ์„ค์ •ํ•œ๋‹ค.
12
+ Owner์˜ ํ–‰๋™์ด ํ•„์š”ํ•œ ๋ถ€๋ถ„์€ AskUserQuestion์œผ๋กœ ํ•ด๊ฒฐํ•œ๋‹ค.
13
+
14
+ ## CLI
15
+
16
+ - `node` โ€” ํ˜„ LTS
17
+ - `pnpm` โ€” latest (์›Œํฌ์ŠคํŽ˜์ด์Šค๋Š” pnpm ๊ธฐ์ค€ ยท ๊ฐ repo `package.json`์˜ `packageManager`๋กœ ๋ฒ„์ „ ๊ณ ์ •)
18
+ - `git`
19
+ - `gh` โ€” ๋กœ๊ทธ์ธ
20
+ - `vercel` โ€” ๋กœ๊ทธ์ธ
21
+ - `pnpm exec supabase` โ€” ๋กœ๊ทธ์ธ (CLI๋Š” `web/` devDependency๋กœ ๊ณ ์ •๋˜์–ด ์žˆ๋‹ค โ€” `web/`์—์„œ ์‹คํ–‰. `npx supabase`๋กœ ๋ณ„๋„ ์‚ฌ๋ณธ์„ ๋ฐ›์ง€ ์•Š๋Š”๋‹ค)
22
+ - `sentry-cli` โ€” ๋กœ๊ทธ์ธ
23
+
24
+ ์•ฑ(`mobile/`)๊นŒ์ง€ ๊ฐˆ ๋•Œ ํ•„์š”ํ•œ `eas-cli` ๋กœ๊ทธ์ธ์€ ์ฒซ ๋นŒ๋“œ ์‹œ์ ์— `/preview`๊ฐ€ ์•ˆ๋‚ดํ•œ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” ์ ๊ฒ€ํ•˜์ง€ ์•Š๋Š”๋‹ค.
25
+
26
+ ## ์˜์กด์„ฑ
27
+
28
+ ์›Œํฌ์ŠคํŽ˜์ด์Šค ๋ฃจํŠธ์˜ `package.json`์€ `pnpm doctor`(ํ™˜๊ฒฝ ์ ๊ฒ€) ์ง„์ž…์ ๋งŒ ๊ฐ€์ง„๋‹ค โ€” ๋ฃจํŠธ์— ์˜์กด์„ฑ์„ ์„ค์น˜ํ•˜์ง€ ์•Š๋Š”๋‹ค. `web/`๊ณผ `mobile/`์€ ๊ฐ์ž ๋…๋ฆฝ ํ”„๋กœ์ ํŠธ์ด๋ฏ€๋กœ ์˜์กด์„ฑ๋„ ๊ฐ์ž ์„ค์น˜ํ•œ๋‹ค.
29
+
30
+ - `web/`์—์„œ `pnpm install` ํ›„ `pnpm audit`.
31
+ - `mobile/`์ด ์žˆ์œผ๋ฉด(์•ฑ ๋‹จ๊ณ„ ์ดํ›„) `mobile/`์—์„œ๋„ ๋™์ผํ•˜๊ฒŒ ํ•œ๋‹ค.
32
+
33
+ ์„ธ๋ถ€ ์ •์ฑ…์€ ๊ฐ repo์˜ `.npmrc`์™€ CI ์„ค์ •์„ ๋”ฐ๋ฅธ๋‹ค. ๋ณด์•ˆ ๊ฒŒ์ดํŠธ(cooldown, audit level ๋“ฑ)๋Š” ์šฐํšŒํ•˜๊ฑฐ๋‚˜ ์ˆ˜์ •ํ•˜์ง€ ์•Š๋Š”๋‹ค.
@@ -0,0 +1,39 @@
1
+ # saas-starter-workspace
2
+
3
+ ์„œ๋น„์Šค๋“ค ์œ„์˜ ์ปจํ…์ŠคํŠธ ๋ ˆ์ด์–ด. ์ด repo์˜ git์€ ๊ณต์œ  ๋งฅ๋ฝ(์—์ด์ „ํŠธ ๋„๊ตฌยท๊ณ„์•ฝยท๋ฌธ์„œ)๋งŒ ์ถ”์ ํ•œ๋‹ค. `web/`์™€ `mobile/`์€ ๊ฐ์ž ์ž๊ธฐ gitยท๋ฐฐํฌ๋ฅผ ๊ฐ€์ง„ ๋…๋ฆฝ repo๋‹ค.
4
+
5
+ ์‚ฌ๋žŒ์šฉ ์‹œ์ž‘ ์•ˆ๋‚ด๋Š” `START-HERE.md`. ์ด ํŒŒ์ผ์€ ์—์ด์ „ํŠธ์˜ ์šด์˜ ์ปจํ…์ŠคํŠธ๋‹ค.
6
+
7
+ ## ๊ตฌ์„ฑ
8
+
9
+ - `web/` โ€” ์›น SaaS (Next.js + Supabase). ์ž๊ธฐ git โ†’ GitHub โ†’ Vercel๋กœ ๋ฐฐํฌํ•œ๋‹ค. ํ™”๋ฉดยท๊ธฐ๋Šฅยท๋ฐ์ดํ„ฐ์˜ ๋ณธ์ฒด์ด์ž SSOT.
10
+ - `mobile/` โ€” ๋ฐฐํฌ๋œ web์„ WebView๋กœ ๊ฐ์‹ธ๋Š” ๋„ค์ดํ‹ฐ๋ธŒ ์…ธ (Expo). ์ž๊ธฐ git โ†’ EAS โ†’ ์Šคํ† ์–ด๋กœ ๋ฐฐํฌํ•œ๋‹ค. ์›น๋ทฐ๊ฐ€ ๋ชป ๋ฉ”์šฐ๋Š” ๋„ค์ดํ‹ฐ๋ธŒ ๊ณต๋ฐฑ(ํ‘ธ์‹œยทํ™ˆ ํ™”๋ฉด ์•„์ด์ฝ˜ยท์˜คํ”„๋ผ์ธ ํ™”๋ฉด)๋งŒ ์ฑ„์šด๋‹ค.
11
+ - `ssb/` โ€” web โ†” mobile postMessage ๊ณ„์•ฝ์˜ SSOT. `web/lib/bridge/`์™€ `mobile/src/bridge/`์— ๋ฐ”์ดํŠธ ๋‹จ์œ„๋กœ ๋™์ผํ•˜๊ฒŒ ๋ณต์‚ฌ๋œ๋‹ค.
12
+ - `.claude/` โ€” ์—์ด์ „ํŠธ ๋„๊ตฌ(์Šคํ‚ฌยท์„ค์ •). ์›Œํฌ์ŠคํŽ˜์ด์Šค ๋ฃจํŠธ์—๋งŒ ๋‘”๋‹ค.
13
+ - `scripts/doctor.mjs` โ€” ํ™˜๊ฒฝยท๋กœ๊ทธ์ธ ์ ๊ฒ€(`pnpm doctor`). ์ง„๋‹จ๊ณผ ์•ˆ๋‚ด๊นŒ์ง€๋งŒ ํ•˜๊ณ  ์ž๋™ ์ˆ˜๋ฆฌ๋Š” ํ•˜์ง€ ์•Š๋Š”๋‹ค. Owner๊ฐ€ โœ— ํ•ด๊ฒฐ์„ ๋ถ€ํƒํ•˜๋ฉด doctor์˜ โ†’ ์•ˆ๋‚ด๋ฅผ ๋”ฐ๋ผ ์ˆ˜ํ–‰ํ•˜๊ณ  ๋‹ค์‹œ doctor๋กœ ๊ฒ€์ฆํ•œ๋‹ค.
14
+ - `workspace.json` โ€” ์ƒ์„ฑ๊ธฐ๊ฐ€ ๊ธฐ๋กํ•œ ๋ฉ”ํƒ€(ํ”„๋กœ์ ํŠธ๋ช…ยท์„ ํƒํ•œ ์ฝ”๋”ฉ ์—์ด์ „ํŠธ). doctor๊ฐ€ ์ฝ๋Š”๋‹ค.
15
+
16
+ ## ๋ถˆ๋ณ€์‹
17
+
18
+ - ๊ฐ ์„œ๋น„์Šค๋Š” ๋…๋ฆฝ repo๋‹ค. ์„œ๋กœ importํ•˜์ง€ ์•Š๊ณ , ๊ณต์œ ๋Š” ๋ณต์‚ฌ๋œ ๊ณ„์•ฝ(`ssb/`)์œผ๋กœ๋งŒ ํ•œ๋‹ค.
19
+ - web์€ ๋‹จ๋…์œผ๋กœ ์™„๊ฒฐ๋œ๋‹ค. mobile์€ ๊ทธ ์œ„์— ์–น๋Š” ์„ ํƒ์  ๋ ˆ์ด์–ด์ด๊ณ , web์€ mobile์— ์˜์กดํ•˜์ง€ ์•Š๋Š”๋‹ค.
20
+ - ํด๋ผ์šฐ๋“œ ํ”„๋กœ๋น„์ €๋‹ยทgitยท๋ฐฐํฌ ๋ช…๋ น์€ ํ•ด๋‹น ์„œ๋น„์Šค ํด๋” ์•ˆ์—์„œ ์‹คํ–‰ํ•œ๋‹ค. `/go-live`๋Š” `web/`์—์„œ(web์ด ๋ฐฐํฌ ๋‹จ์œ„), ์•ฑ ๋นŒ๋“œยท์ถœ์‹œ๋Š” `mobile/`์—์„œ. ์›Œํฌ์ŠคํŽ˜์ด์Šค ๋ฃจํŠธ๋ฅผ ํ•œ repo๋กœ ๋ฌถ๊ฑฐ๋‚˜ `web/`ยท`mobile/`์„ ๋ถ€๋ชจ git์— addํ•˜์ง€ ์•Š๋Š”๋‹ค.
21
+ - ์—์ด์ „ํŠธ ๋„๊ตฌ(์Šคํ‚ฌยท`.claude/` ์„ค์ •)๋Š” ์›Œํฌ์ŠคํŽ˜์ด์Šค ๋ฃจํŠธ์—๋งŒ ๋‘”๋‹ค. `web/`ยท`mobile/`์€ ๋„๊ตฌ๊ฐ€ ์—†๋Š” ์ˆœ์ˆ˜ ์ฝ”๋“œ์ด๊ณ , ๊ฐ์ž ์ž๊ธฐ `AGENTS.md`(๊ทธ repo๋ฅผ ์ง์ ‘ ์†๋ณด๋Š” ์‚ฌ๋žŒ์šฉ)๋งŒ ๋‘”๋‹ค.
22
+ - ํ•œ ์„œ๋น„์Šค์—๋งŒ ์†ํ•œ ์ง€์‹์€ ๊ทธ ์„œ๋น„์Šค repo๊ฐ€ ์ง„๋‹ค. ์„œ๋น„์Šค๋ฅผ ๊ฐ€๋กœ์ง€๋ฅด๋Š” ๋งฅ๋ฝ๋งŒ ์—ฌ๊ธฐ๊ฐ€ ์ง„๋‹ค.
23
+
24
+ ## ์ด ํ…œํ”Œ๋ฆฟ์˜ ์„ฑ๊ฒฉ
25
+
26
+ ๋นˆ ๊ณจ๊ฒฉ์ด๋‹ค. `web/features/`์™€ `web/supabase/migrations/`๋Š” ๋น„์–ด ์žˆ๊ณ , ๋กœ๊ทธ์ธยท๊ธ€ยทํ”ผ๋“œ ๊ฐ™์€ ์ œํ’ˆ ๊ธฐ๋Šฅ์€ ์‚ฌ์šฉ์ž ์ฃผ์ œ์— ๋งž์ถฐ ๋Œ€ํ™”๋กœ ๋งŒ๋“ ๋‹ค. ์ธํ”„๋ผ(๋ฐ์ดํ„ฐ ์ ‘๊ทผ seam, RLS ๊ธฐ๋ณธ ํ™œ์„ฑํ™”, ํ™˜๊ฒฝ ๋ถ„๋ฆฌ, ๋กœ๊น…ยทํ…Œ์ŠคํŠธ, ๋””์ž์ธ ์‹œ์Šคํ…œ, ์ฝ”๋“œ ์ปจ๋ฒค์…˜)๋Š” ๊ฐ–์ถฐ์ ธ ์žˆ๋‹ค.
27
+
28
+ ๊ธฐ๋Šฅ ์ œ์ž‘์€ `web/AGENTS.md`์˜ ๊ทœ์•ฝ์„ ๋”ฐ๋ฅธ๋‹ค(FSD-light, `features/<f>/repository.ts` ๋ฐ์ดํ„ฐ ์ ‘๊ทผ seam, RLS ๋™๋ด‰, schema 3์ธต). ์•ฑ ์ž‘์—…์€ `mobile/AGENTS.md`์™€ ์ž๋™ ๋กœ๋“œ๋˜๋Š” ๊ฐ€์ด๋“œ ์Šคํ‚ฌ(`native-app-guide`ยท`bridge-guide`ยท`eas-deploy-guide`ยท`store-release-guide`)์„ ๋”ฐ๋ฅธ๋‹ค.
29
+
30
+ ## ์šด์˜ ์›์น™
31
+
32
+ - ๋ณต์žก์„ฑ์„ ๋จผ์ € ์˜์‹ฌํ•œ๋‹ค. ๊ธฐ๋ณธ๊ฐ’์€ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด๋‹ค. ํŒŒ์ผยทํด๋”ยท์ถ”์ƒํ™”๋Š” ์ง€๊ธˆ ์ž๊ฒฉ์ด ์žˆ์„ ๋•Œ๋งŒ ๋งŒ๋“ ๋‹ค.
33
+ - ํ•œ ํŒŒ์ผยทํด๋”๋Š” ํ•˜๋‚˜์˜ ์ฑ…์ž„๋งŒ ์ง„๋‹ค. ๋ฒ”์šฉ ๋ฒ„ํ‚ท(`docs/`ยท`misc/` ๊ฐ™์€)์€ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค.
34
+ - ์˜๋„๋Š” ๋ฐฐ์น˜๋กœ ๋“œ๋Ÿฌ๋‚ธ๋‹ค. ์ฒ˜์Œ ๋ณธ ์‚ฌ๋žŒ์ด "์ด๊ฒŒ ์™œ ์—ฌ๊ธฐ ์žˆ์ง€"๋ฅผ ๋ฌป์ง€ ์•Š๋„๋ก, ์ด๋ฆ„์ด ๊ณง ๊ด€์‹ฌ์‚ฌ๊ฐ€ ๋˜๊ฒŒ ํ•œ๋‹ค.
35
+ - ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์“ด๋‹ค. ๊ทผ๊ฑฐ๋Š” ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€์— ๋‚จ๊ธฐ๊ณ , ๋ณธ๋ฌธ์€ ์•ฝ์–ด ๋‚˜์—ด์ด ์•„๋‹ˆ๋ผ ์™„์ „ํ•œ ๋ฌธ์žฅ์œผ๋กœ ์“ด๋‹ค.
36
+ - ๋น„๊ฐœ๋ฐœ์ž owner๋ผ๋„ best practice๋ฅผ ๊นŽ์ง€ ์•Š๋Š”๋‹ค.
37
+ - ์ ์ง„ ํ™•์žฅ์€ ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ ํ•œ๋‹ค. ์ถ”์ธก์œผ๋กœ ๋ฏธ๋ฆฌ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค.
38
+ - ์ง€์‹ ๋ฐฐ์น˜: ์ž‘์—… ์‹œ ์ž๋™์œผ๋กœ ๋– ์•ผ ํ•˜๋Š” ์ง€์‹์€ ์Šคํ‚ฌ(ํŠธ๋ฆฌ๊ฑฐ = `description`), ๋งค ์„ธ์…˜ ์ฐธ์ธ ์‚ฌ์‹ค์€ ์ด ํŒŒ์ผ๊ณผ ๊ฐ repo์˜ `AGENTS.md`, ์ž‘์ •ํ•˜๊ณ  ๋ณด๋Š” ๋ ˆํผ๋Ÿฐ์Šค๋Š” `docs/`.
39
+ - ์–ธ์–ด: ํ•œ๊ตญ์–ด๋กœ ์†Œํ†ตํ•˜๊ณ , ์ฝ”๋“œ ์‹๋ณ„์žยท๊ธฐ์ˆ  ์šฉ์–ด๋Š” ์›๋ฌธ์„ ์œ ์ง€ํ•œ๋‹ค. ์ปค๋ฐ‹์€ Conventional Commits(์˜์–ด).
@@ -0,0 +1,2 @@
1
+ <!-- AGENTS.md๋ฅผ ๊ทธ๋Œ€๋กœ ๋ถˆ๋Ÿฌ์˜ต๋‹ˆ๋‹ค. ์—์ด์ „ํŠธ ๊ทœ์น™์€ AGENTS.md์—์„œ ๋‹จ์ผ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค(์ค‘๋ณต ์‚ฌ๋ณธ์„ ๋‘์ง€ ์•Š์Œ). -->
2
+ @AGENTS.md
@@ -0,0 +1,17 @@
1
+ Copyright (c) 2026 ์‹œ์Šคํ…œ์„ค๊ณ„์ž
2
+
3
+ This template is distributed to students of the author's course
4
+ (brand: ์‹œ์Šคํ…œ์„ค๊ณ„์ž).
5
+
6
+ You may use it as the starting point for any of your own projects โ€”
7
+ personal or commercial. You may modify it freely, ship products built
8
+ with it, and you keep all rights to the work you create on top.
9
+
10
+ You may not redistribute the template itself, repackage it as a course
11
+ or book, or include it in any dataset used to train machine learning
12
+ models. Access is part of the course.
13
+
14
+ THE TEMPLATE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15
+ OR IMPLIED. THE AUTHOR SHALL NOT BE LIABLE FOR ANY CLAIM, DAMAGES, OR
16
+ OTHER LIABILITY ARISING FROM OR IN CONNECTION WITH THE TEMPLATE OR ITS
17
+ USE.
@@ -0,0 +1,20 @@
1
+ # saas-starter-workspace
2
+
3
+ ์›น SaaS๋ฅผ ๋งŒ๋“ค๊ณ , ์›ํ•˜๋ฉด ๊ทธ๋Œ€๋กœ ์Šคํ† ์–ด ์•ฑ์œผ๋กœ ๊ฐ์‹ธ๋Š” ์Šคํƒ€ํ„ฐ์ž…๋‹ˆ๋‹ค. ํ™”๋ฉดยท์ฝ”๋“œยท๋ฐฐํฌ๋Š” AI ์ฝ”๋”ฉ ์—์ด์ „ํŠธ๊ฐ€ ๋งก๊ณ , ๋‹น์‹ ์€ ๋ฌด์—‡์„ ๋งŒ๋“ค์ง€ ์ •ํ•ฉ๋‹ˆ๋‹ค.
4
+
5
+ ์ฒ˜์Œ์ด๋ผ๋ฉด [START-HERE.md](START-HERE.md)๋ถ€ํ„ฐ ์—ฌ์„ธ์š”. ์„ค์น˜, ๋ช…๋ น ์ˆœ์„œ, ํด๋” ๊ตฌ์กฐ๊ฐ€ ๊ฑฐ๊ธฐ ์žˆ์Šต๋‹ˆ๋‹ค.
6
+
7
+ ## ๊ตฌ์„ฑ
8
+
9
+ ```
10
+ (ํ”„๋กœ์ ํŠธ ํด๋”)/ ์—์ด์ „ํŠธ๋ฅผ ์—ฌ๋Š” ๋‹จ์ผ ์ง„์ž…์ 
11
+ โ”œโ”€โ”€ web/ ์›น SaaS (Next.js ยท Supabase ยท Vercel). ํ™”๋ฉดยท๊ธฐ๋Šฅยท๋ฐ์ดํ„ฐ์˜ ๋ณธ์ฒด.
12
+ โ”œโ”€โ”€ mobile/ ๊ทธ ์›น์„ ๊ฐ์‹ธ๋Š” ์Šคํ† ์–ด ์•ฑ (Expo ยท EAS).
13
+ โ”œโ”€โ”€ ssb/ web โ†” mobile ํ†ต์‹  ๊ณ„์•ฝ. ์†๋Œˆ ์ผ์€ ๊ฑฐ์˜ ์—†์Šต๋‹ˆ๋‹ค.
14
+ โ”œโ”€โ”€ scripts/ ํ™˜๊ฒฝ ์ ๊ฒ€ ๋„๊ตฌ(`pnpm doctor`).
15
+ โ””โ”€โ”€ .claude/ ์—์ด์ „ํŠธ ๋„๊ตฌ(์Šคํ‚ฌยท์„ค์ •).
16
+ ```
17
+
18
+ `web/`๊ณผ `mobile/`์€ ๊ฐ์ž ๋ฐฐํฌ๋˜๋Š” ๋…๋ฆฝ ํ”„๋กœ์ ํŠธ์ž…๋‹ˆ๋‹ค. ์ด ์›Œํฌ์ŠคํŽ˜์ด์Šค๋Š” ๋‘˜์„ ์ž‡๋Š” ๊ณต์œ  ๋งฅ๋ฝ(์—์ด์ „ํŠธ ๋„๊ตฌยท๊ณ„์•ฝ)๋งŒ ๋‘ก๋‹ˆ๋‹ค. ์—์ด์ „ํŠธ ์šด์˜ ๊ทœ์น™์€ [AGENTS.md](AGENTS.md)์— ์žˆ์Šต๋‹ˆ๋‹ค.
19
+
20
+ ์ˆ˜๊ฐ•์ƒ์—๊ฒŒ ๋ฐฐํฌ๋˜๋Š” ๊ฐ•์˜์šฉ ํ…œํ”Œ๋ฆฟ์ž…๋‹ˆ๋‹ค. [LICENSE](LICENSE).
@@ -0,0 +1,52 @@
1
+ # ์—ฌ๊ธฐ์„œ ์‹œ์ž‘ํ•˜์„ธ์š”
2
+
3
+ ๋‚˜๋งŒ์˜ ์›น ์„œ๋น„์Šค๋ฅผ ๋งŒ๋“ค๊ณ , ๊ทธ๊ฒƒ์„ ์Šคํ† ์–ด ์•ฑ์œผ๋กœ ๊ฐ์‹ธ ์šด์˜ํ•˜๊ธฐ ์œ„ํ•œ ์ถœ๋ฐœ์ ์ž…๋‹ˆ๋‹ค. ํ™”๋ฉดยท์ฝ”๋“œยท๋ฐฐํฌ๋Š” AI ์ฝ”๋”ฉ ์—์ด์ „ํŠธ๊ฐ€ ๋งก๊ณ , ๋‹น์‹ ์€ ๋ฌด์—‡์„ ๋งŒ๋“ค์ง€ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค.
4
+
5
+ ## 1. ์ค€๋น„ (ํ•œ ๋ฒˆ๋งŒ)
6
+
7
+ ์ด ํด๋”๋Š” ๊ฐ•์˜์˜ ์„ค์น˜ ๋ช…๋ น(ํ•œ ์ค„)์ด ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ ๋ช…๋ น์ด ํ•„์š”ํ•œ ๋„๊ตฌ ์„ค์น˜์™€ ๋กœ๊ทธ์ธ๊นŒ์ง€ ์•ˆ๋‚ดํ–ˆ์œผ๋‹ˆ, ๋‚จ์€ ์ค€๋น„๋Š” ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค:
8
+
9
+ 1. ํ„ฐ๋ฏธ๋„์—์„œ ์ด ํด๋”๋กœ ์ด๋™ํ•ด ์ฝ”๋”ฉ ์—์ด์ „ํŠธ๋ฅผ ์—ฝ๋‹ˆ๋‹ค โ€” ๊ธฐ๋ณธ์€ Claude Code(`claude` ์ž…๋ ฅ), CodexยทOpenCode๋„ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค. ์•ˆ์ชฝ์˜ `web/`ยท`mobile/`์ด ์•„๋‹ˆ๋ผ ๋ฃจํŠธ์—์„œ ์—ฝ๋‹ˆ๋‹ค. ๋ช…๋ น(์Šคํ‚ฌ)์€ ์—ฌ๊ธฐ์— ์žˆ์Šต๋‹ˆ๋‹ค.
10
+ 2. ์ฒ˜์Œ ์—ด๋ฉด ์—์ด์ „ํŠธ๊ฐ€ ๋กœ๊ทธ์ธ(๊ตฌ๋… ๊ณ„์ •)์„ ์•ˆ๋‚ดํ•ฉ๋‹ˆ๋‹ค. ํ•œ ๋ฒˆ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.
11
+ 3. ๊ทธ๋‹ค์Œ๋ถ€ํ„ฐ๋Š” ์•„๋ž˜ ๋ช…๋ น์„ ์ž…๋ ฅํ•˜๊ฑฐ๋‚˜, ํ‰์†Œ ๋ง๋กœ ๋ถ€ํƒํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.
12
+
13
+ > ํ™˜๊ฒฝ์ด ๋ฉ€์ฉกํ•œ์ง€ ๊ถ๊ธˆํ•  ๋• ์–ธ์ œ๋“  ํ„ฐ๋ฏธ๋„์—์„œ `pnpm doctor`๋ฅผ ์‹คํ–‰ํ•˜์„ธ์š”. ๋„๊ตฌยท๋กœ๊ทธ์ธ ์ƒํƒœ๋ฅผ โœ“/โœ—๋กœ ๋ณด์—ฌ์ฃผ๊ณ , โœ—๋งˆ๋‹ค ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ์•Œ๋ ค์ค๋‹ˆ๋‹ค.
14
+
15
+ ## 2. ๋ช…๋ น ์ˆœ์„œ
16
+
17
+ ์œ„์—์„œ ์•„๋ž˜๋กœ, ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์”ฉ. ๋ช…๋ น์€ `/`๋กœ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.
18
+
19
+ | ๋ช…๋ น | ๋ฌด์—‡์„ ํ•˜๋‚˜ | ๋‹น์‹ ์ด ํ•˜๋Š” ์ผ |
20
+ | --- | --- | --- |
21
+ | `/warmup` | ๋„๊ตฌยท๋กœ๊ทธ์ธ ์ ๊ฒ€, ์˜์กด์„ฑ ์„ค์น˜ | ๋ถ€์กฑํ•œ ๋กœ๊ทธ์ธ๋งŒ ๋”ฐ๋ผ ํ•˜๊ธฐ |
22
+ | `/go-live` | GitHubยทVercelยทSupabaseยทSentry๋ฅผ ๋งŒ๋“ค๊ณ  `web/`์„ ์‹ค์ œ ์ฃผ์†Œ๋กœ ์ฒซ ๋ฐฐํฌ | ๋น„๊ฐ€์—ญ ์ž‘์—…๋งŒ ํ™•์ธ |
23
+ | `/probe <์•„์ด๋””์–ด>` | ๋งŒ๋“ค ์„œ๋น„์Šค๋ฅผ ์ธํ„ฐ๋ทฐ๋กœ ๊ตฌ์ฒดํ™” | ์งˆ๋ฌธ์— ๋‹ตํ•˜๊ธฐ |
24
+ | `/sketch` | ํ™”๋ฉด ๋””์ž์ธ ์‹œ์•ˆ ๋ณด์—ฌ์ฃผ๊ธฐ | ๋งˆ์Œ์— ๋“œ๋Š” ์•ˆ ๊ณ ๋ฅด๊ธฐ |
25
+ | "OO ๊ธฐ๋Šฅ ๋งŒ๋“ค์–ด์ค˜" | ๋กœ๊ทธ์ธยท๊ธ€์“ฐ๊ธฐยทํ”ผ๋“œยท์Šน์ธ ๋“ฑ ๊ธฐ๋Šฅ์„ ๋Œ€ํ™”๋กœ ์ œ์ž‘ | ์›ํ•˜๋Š” ๋ฐ” ๋งํ•˜๊ธฐ |
26
+ | `git push` (AI๊ฐ€ ์‹คํ–‰) | ์ž๋™ ์žฌ๋ฐฐํฌ โ†’ ์ฆ‰์‹œ ๋ผ์ด๋ธŒ | ์ฃผ์†Œ ํ™•์ธ |
27
+ | `/kickoff` | ๋ฐฐํฌ๋œ ์›น์„ ์•ฑ(`mobile/`)์œผ๋กœ ๊ฐ์‹ธ๊ธฐ, 1ํšŒ ์…‹์—… | ๋น„์šฉ ํ™•์ธ ํ›„ ์ง„ํ–‰ |
28
+ | `/preview` | ์•ฑ์„ ํฐ์— ์„ค์น˜ํ•ด ๋ณด๊ธฐ(TestFlightยทPlay ๋‚ด๋ถ€ ํ…Œ์ŠคํŠธ) | ํฐ์—์„œ ํ™•์ธ |
29
+ | `/launch` ยท `/release` | ์Šคํ† ์–ด ์ฒซ ์ถœ์‹œ ยท ์ดํ›„ ์—…๋ฐ์ดํŠธ | ์ฝ˜์†”์—์„œ ๊ณต๊ฐœ ๋ฒ„ํŠผ |
30
+
31
+ `/go-live`๋กœ ๋นˆ ์„œ๋น„์Šค๋ฅผ ๋จผ์ € ๋„์šฐ๊ณ , ๊ทธ ์œ„์— ๊ธฐ๋Šฅ์„ ํ•˜๋‚˜์”ฉ ์–น์–ด `git push`๋กœ ๊ณ„์† ๋ฐฐํฌํ•ฉ๋‹ˆ๋‹ค. ์›น์— ์˜ฌ๋ฆฐ ๋ณ€ํ™”๋Š” ์•ฑ์—๋„ ์žฌ์‹ฌ์‚ฌ ์—†์ด ๊ทธ๋Œ€๋กœ ๋ฐ˜์˜๋ฉ๋‹ˆ๋‹ค.
32
+
33
+ ## 3. ์ด ์•ˆ์— ๋ญ๊ฐ€ ์žˆ๋‚˜
34
+
35
+ ```
36
+ (๋‚ด ํ”„๋กœ์ ํŠธ ํด๋”)/ ์ง€๊ธˆ ์ด ํด๋”. ์ฝ”๋”ฉ ์—์ด์ „ํŠธ๋ฅผ ์—ฌ๊ธฐ์„œ ์—ฝ๋‹ˆ๋‹ค.
37
+ โ”œโ”€โ”€ web/ ๋‹น์‹ ์˜ ์›น ์„œ๋น„์Šค (Next.js โ†’ Vercel). ๋ชจ๋“  ํ™”๋ฉดยท๊ธฐ๋Šฅยท๋ฐ์ดํ„ฐ์˜ ๋ณธ์ฒด.
38
+ โ”œโ”€โ”€ mobile/ ๊ทธ ์›น์„ ๊ฐ์‹ธ๋Š” ์Šคํ† ์–ด ์•ฑ (Expo โ†’ ์•ฑยทํ”Œ๋ ˆ์ด์Šคํ† ์–ด). ํ‘ธ์‹œยทํ™ˆ ํ™”๋ฉด ์•„์ด์ฝ˜์ฒ˜๋Ÿผ ์•ฑ๋งŒ์˜ ๊ฒƒ.
39
+ โ”œโ”€โ”€ ssb/ web โ†” mobile์ด ์ฃผ๊ณ ๋ฐ›๋Š” ํ†ต์‹  ๊ณ„์•ฝ. ์†๋Œ€์ง€ ์•Š์•„๋„ ๋ฉ๋‹ˆ๋‹ค.
40
+ โ”œโ”€โ”€ scripts/ ํ™˜๊ฒฝ ์ ๊ฒ€ ๋„๊ตฌ(`pnpm doctor`).
41
+ โ””โ”€โ”€ .claude/ ์œ„ ๋ช…๋ น(์Šคํ‚ฌ)์ด ์žˆ๋Š” ๊ณณ.
42
+ ```
43
+
44
+ ๋ณธ์ฒด๋Š” `web/`์ž…๋‹ˆ๋‹ค. ๊ฑฐ์˜ ๋ชจ๋“  ์ž‘์—…์ด ์›น์—์„œ ์ผ์–ด๋‚˜๊ณ , `mobile/`์€ ๊ทธ ์›น์„ ๋„์šฐ๋Š” ์–‡์€ ๊ป๋ฐ๊ธฐ(์…ธ)์ž…๋‹ˆ๋‹ค. ๋‘˜์€ ๊ฐ์ž ๋…๋ฆฝ๋œ ํ”„๋กœ์ ํŠธ๋ผ ๋”ฐ๋กœ ๋ฐฐํฌ๋ฉ๋‹ˆ๋‹ค(์›น์€ Vercel, ์•ฑ์€ ์Šคํ† ์–ด).
45
+
46
+ ## 4. ์•Œ์•„๋‘˜ ๊ฒƒ
47
+
48
+ - ์ด๊ฑด ๋นˆ ๊ณจ๊ฒฉ์ž…๋‹ˆ๋‹ค. ๋กœ๊ทธ์ธยท๊ธ€ยทํ”ผ๋“œ ๊ฐ™์€ ๊ธฐ๋Šฅ์€ ๋ฏธ๋ฆฌ ๋“ค์–ด ์žˆ์ง€ ์•Š๊ณ , ๋‹น์‹  ์ฃผ์ œ์— ๋งž๊ฒŒ AI์™€ ํ•จ๊ป˜ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ํ”„๋กœ์ ํŠธ ์ด๋ฆ„์€ ์ƒ์„ฑํ•  ๋•Œ ์ž…๋ ฅํ•œ ์ด๋ฆ„์ด ์ฝ”๋“œ ์ „์ฒด์— ๋“ค์–ด๊ฐ€ ์žˆ๊ณ , ๋ฐ”๊พธ๊ณ  ์‹ถ์œผ๋ฉด AI์—๊ฒŒ ๋ถ€ํƒํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.
49
+ - ๋ˆยท์‹ ์›์ด ๊ฑธ๋ฆฐ ์ผ์€ AI๊ฐ€ ๋Œ€์‹  ๋ชป ํ•ฉ๋‹ˆ๋‹ค. ์นด๋“œ ๊ฒฐ์ œ, ๋กœ๊ทธ์ธ 2FA, ์Šคํ† ์–ด ์ฝ˜์†”์˜ ๊ณต๊ฐœ ๋ฒ„ํŠผ์€ ๋‹น์‹ ์ด ์ง์ ‘ ๋ˆ„๋ฅด๊ณ , AI๊ฐ€ ๊ทธ ์ˆœ๊ฐ„์„ ์งš์–ด ์ค๋‹ˆ๋‹ค.
50
+ - ์•ฑ ์Šคํ† ์–ด๋Š” ์ผ์ฐ ์‹œ์ž‘ํ•˜์„ธ์š”. Apple Developer๋Š” ์—ฐ $99, Google Play๋Š” 1ํšŒ $25์ž…๋‹ˆ๋‹ค(๋‘˜ ๋‹ค ํ™˜๋ถˆ ๋ถˆ๊ฐ€). ํŠนํžˆ ์‹ ๊ทœ Google ๊ณ„์ •์€ ์ •์‹ ๊ณต๊ฐœ ์ „์— "๋น„๊ณต๊ฐœ ํ…Œ์ŠคํŠธ 12๋ช…ยท14์ผ ์—ฐ์†"์„ ํ†ต๊ณผํ•ด์•ผ ํ•ด์„œ ์ถœ์‹œ๊นŒ์ง€ 2์ฃผ ์ด์ƒ ๊ฑธ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•ฑ๊นŒ์ง€ ๊ฐˆ ๊ณ„ํš์ด๋ฉด ์ฝ”๋“œ ์ž‘์—…๊ณผ ๋ณ„๊ฐœ๋กœ ๊ฐ€์žฅ ๋จผ์ € ๊ณ„์ •์„ ๋งŒ๋“ค์–ด ๋‘์„ธ์š”.
51
+
52
+ ๋ง‰ํžˆ๋ฉด Claude Code์—๊ฒŒ ๋ฌผ์–ด๋ณด์„ธ์š”. ์ด ํด๋”์˜ ๋„๊ตฌ์™€ ๋ฌธ์„œ๋ฅผ ์•ˆ ์ฑ„๋กœ ๋‹ตํ•ฉ๋‹ˆ๋‹ค.
@@ -0,0 +1,18 @@
1
+ # OS / ๋กœ์ปฌ ์‚ฐ์ถœ๋ฌผ
2
+ .DS_Store
3
+ *.log
4
+
5
+ # ์ค‘์ฒฉ ์„œ๋น„์Šค(web/ยทmobile/)๋Š” ๊ฐ์ž ์ž๊ธฐ git์„ ๊ฐ€์ง„ ๋…๋ฆฝ repo๋‹ค.
6
+ # ์›Œํฌ์ŠคํŽ˜์ด์Šค ๋ฃจํŠธ๋Š” ๊ณต์œ  ๋งฅ๋ฝ ๋ ˆ์ด์–ด๋งŒ ์ถ”์ ํ•œ๋‹ค(web/ยทmobile/์€ ์—ฌ๊ธฐ์„œ ์ถ”์ ํ•˜์ง€ ์•Š๋Š”๋‹ค).
7
+ /*
8
+ !/.gitignore
9
+ !/README.md
10
+ !/START-HERE.md
11
+ !/AGENTS.md
12
+ !/CLAUDE.md
13
+ !/LICENSE
14
+ !/.claude/
15
+ !/ssb/
16
+ !/package.json
17
+ !/scripts/
18
+ !/workspace.json
@@ -0,0 +1,25 @@
1
+ # .env.example โ€” ์ด ํŒŒ์ผ์„ ๋ณต์‚ฌํ•ด `.env`๋กœ ์ €์žฅํ•œ ๋’ค ๊ฐ’์„ ์ฑ„์šฐ์„ธ์š”.
2
+ # cp .env.example .env
3
+ # .env ๋Š” .gitignore ๋กœ ์ปค๋ฐ‹์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. .env.example(์ด ํŒŒ์ผ)์€ ์ปค๋ฐ‹ํ•ฉ๋‹ˆ๋‹ค.
4
+ #
5
+ # EXPO_PUBLIC_* ์ ‘๋‘์‚ฌ๊ฐ€ ๋ถ™์€ ๊ฐ’๋งŒ ์•ฑ ๋ฒˆ๋“ค์— ์ธ๋ผ์ธ๋ฉ๋‹ˆ๋‹ค(๋นŒ๋“œ ์‹œ์  ๊ณ ์ • โ€” ๊ฐ’์„ ๋ฐ”๊พธ๋ฉด ์žฌ๋นŒ๋“œ ํ•„์š”).
6
+ # ๋น„๋ฐ€(ํ† ํฐยท์‹œํฌ๋ฆฟ)์€ ์ ˆ๋Œ€ EXPO_PUBLIC_* ๋กœ ๋„ฃ์ง€ ๋งˆ์„ธ์š”. ์•ฑ ์ฝ”๋“œ๋Š” src/config/env.ts ํ†ตํ•ด์„œ๋งŒ ์ฝ์Šต๋‹ˆ๋‹ค.
7
+
8
+ # ์•ฑ์ด ๋„์šธ ์‹ค์„œ๋น„์Šค ์›น ์ฃผ์†Œ. ํ•ญ์ƒ ๋ฐฐํฌ๋œ prod ์›น(https)์„ ๊ฐ€๋ฆฌํ‚ต๋‹ˆ๋‹ค.
9
+ # (์‹ค๊ธฐ๊ธฐ๋Š” localhost์— ๋ชป ๋‹ฟ๊ณ  http๋Š” ์นด๋ฉ”๋ผยท๋กœ๊ทธ์ธ ์ฟ ํ‚ค๊ฐ€ ์กฐ์šฉํžˆ ๊นจ์ง‘๋‹ˆ๋‹ค โ†’ ๋ฐ˜๋“œ์‹œ https.)
10
+ EXPO_PUBLIC_WEB_URL=http://localhost:3000
11
+
12
+ # ์Šคํ† ์–ด/ํ™ˆ ํ™”๋ฉด์— ํ‘œ์‹œ๋  ์•ฑ ์ด๋ฆ„.
13
+ EXPO_PUBLIC_APP_NAME=My App
14
+
15
+ # iOS ๋ฒˆ๋“ค ์‹๋ณ„์ž (Apple Developer ๋“ฑ๋ก๊ฐ’๊ณผ ๋™์ผ, ์—ญ๋„๋ฉ”์ธ ํ˜•์‹).
16
+ EXPO_PUBLIC_IOS_BUNDLE_ID=com.example.myapp
17
+
18
+ # Android ํŒจํ‚ค์ง€๋ช… (Play Console ๋“ฑ๋ก๊ฐ’๊ณผ ๋™์ผ, ์—ญ๋„๋ฉ”์ธ ํ˜•์‹).
19
+ EXPO_PUBLIC_ANDROID_PACKAGE=com.example.myapp
20
+
21
+ # ๋”ฅ๋งํฌ scheme (์†Œ๋ฌธ์ž, ๊ณต๋ฐฑ ์—†์Œ). ๋กœ๊ทธ์ธ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ๋“ฑ์— myapp:// ํ˜•ํƒœ๋กœ ์“ฐ์ž…๋‹ˆ๋‹ค.
22
+ EXPO_PUBLIC_SCHEME=myapp
23
+
24
+ # EAS ํ”„๋กœ์ ํŠธ ID. `eas init` ํ›„ ๋ฐœ๊ธ‰๋ฉ๋‹ˆ๋‹ค. ๋กœ์ปฌ์—์„œ๋Š” ๋น„์›Œ๋‘ฌ๋„ ๋นŒ๋“œ ์‹œ EAS๊ฐ€ ์ฑ„์›๋‹ˆ๋‹ค.
25
+ EXPO_PUBLIC_EAS_PROJECT_ID=
@@ -0,0 +1,69 @@
1
+ # my-space-app
2
+
3
+ ๋ฐฐํฌ๋œ prod ์›น์„ https๋กœ WebView์— ๋„์šฐ๋Š” ์–‡์€ ์…ธ์ด๋‹ค(React Native + Expo). ๋ชจ๋“  ํ™”๋ฉดยท๊ธฐ๋Šฅยท๋กœ๊ทธ์ธ์€ ์›น(Next.js)์˜ ๊ฒƒ์ด๊ณ , ์…ธ์€ ํ™”๋ฉด์„ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค. ์›น๋ทฐ๊ฐ€ ๋ง‰๊ฑฐ๋‚˜ ๋ชป ํ•˜๋Š” ๋„ค์ดํ‹ฐ๋ธŒ ๊ณต๋ฐฑ๋งŒ ๋ฉ”์šด๋‹ค: ์˜คํ”„๋ผ์ธ ํ™”๋ฉด, ์ฒซ ๋กœ๋“œ์™€ ํฌ๋ž˜์‹œ ์žฌ๋งˆ์šดํŠธ ํ•œ์ •์˜ ๋กœ๋”ฉยท์—๋Ÿฌ ์˜ค๋ฒ„๋ ˆ์ด, Android ํ•˜๋“œ์›จ์–ด ๋’ค๋กœ๊ฐ€๊ธฐ, ์™ธ๋ถ€ ๋งํฌ์˜ ์‹œ์Šคํ…œ ๋ธŒ๋ผ์šฐ์ € ๋ผ์šฐํŒ…, safe-area inset ์ฃผ์ž…, ์นด๋ฉ”๋ผยท๋งˆ์ดํฌยทํŒŒ์ผ ์—…๋กœ๋“œ ๊ถŒํ•œ ๋ฐฐ์„ . SSOT๋Š” ์–ธ์ œ๋‚˜ ์›น์ด๋‹ค.
4
+
5
+ > Owner๋Š” ์›ํ•˜๋Š” ๊ฒƒ์„ ๋งํ•˜๊ณ ("์•ฑ ์ด๋ฆ„ ์ •ํ•ด์ค˜", "๋ฏธ๋ฆฌ๋ณด๊ธฐ ๋ณด์—ฌ์ค˜"), AI๊ฐ€ CLIยท์ฝ”๋“œยท๋นŒ๋“œ๋ฅผ ๋งก๋Š”๋‹ค.
6
+
7
+ ## Expo: SDK 56 / RN 0.85 / React 19 โ€” ์ž‘์„ฑ ์ „ ํ™•์ธ
8
+
9
+ ์ฝ”๋“œ๋ฅผ ์“ฐ๊ธฐ ์ „ v56 ๋ฌธ์„œ(<https://docs.expo.dev/versions/v56.0.0/>)๋‚˜ ์„ค์น˜๋œ ํƒ€์ž…(`node_modules/<pkg>/`)์„ ์ฝ๋Š”๋‹ค. SDK 56ยทRN 0.85ยทReact 19๋Š” APIยท์ด๋ฒคํŠธ ๊ตฌ๋…ยทedge-to-edge ๊ธฐ๋ณธ๊ฐ’์ด ํ•™์Šต ๋ฐ์ดํ„ฐ์™€ ๋‹ค๋ฅด๋‹ค. ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋ฏฟ์ง€ ์•Š๋Š”๋‹ค.
10
+
11
+ ## ํด๋” ๊ตฌ์กฐ (FSD-light)
12
+
13
+ ```
14
+ App.tsx # ์ง„์ž…์  โ€” ์Šฌ๋ผ์ด์Šค ์กฐํ•ฉ๋งŒ, ๋กœ์ง ์—†์Œ (FIXED)
15
+ index.ts # URL polyfill + registerRootComponent (FIXED)
16
+ app.config.ts # Expo ์„ค์ •(์ด๋ฆ„ยท๋ฒˆ๋“คIDยท์Šคํ‚ดยทํ”Œ๋Ÿฌ๊ทธ์ธ)
17
+ eas.json # EAS ๋นŒ๋“œยท์ œ์ถœ ํ”„๋กœํŒŒ์ผ(devยทproduction)
18
+ src/
19
+ config/env.ts # EXPO_PUBLIC_WEB_URL ๊ฐ€๋“œยทWEB_ORIGINยทALLOWED_ORIGINS (FIXED)
20
+ i18n.ts # ๋„ค์ดํ‹ฐ๋ธŒ ๋ฌธ์ž์—ด๋งŒ(tยทgetLocale), ๊ทธ ์™ธ๋Š” ์›น ์นดํ”ผ (FIXED)
21
+ bridge/ # ์•ฑโ†”์›น ๊ณ„์•ฝ. contract.tsยทreader.ts๋Š” SSOT (FIXED)
22
+ webview/ # WebView ํ˜ธ์ŠคํŠธ + ์…ธ ๋ ˆ์‹œํ”ผ(๋กœ๋”ฉยท์—๋Ÿฌยท์˜คํ”„๋ผ์ธยท๋’ค๋กœ๊ฐ€๊ธฐยท๋งํฌยทsafe-areaยทํฌ๋ž˜์‹œ ๋ณต๊ตฌ)
23
+ session/ # ์„ธ์…˜ ํ•ธ๋“œ์˜คํ”„ (opt-in, v1 ๋ฏธ์‚ฌ์šฉ)
24
+ auth/ # ๋„ค์ดํ‹ฐ๋ธŒ ๋กœ๊ทธ์ธ ๋ชจ๋‹ฌ (opt-in ์Šค์บํด๋“œ, ์†Œ์…œ์€ ๋น„ํ™œ์„ฑ stub)
25
+ ui/ # ์…ธ ์ „์šฉ ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ(๋กœ๋”ฉยท์—๋Ÿฌยท์˜คํ”„๋ผ์ธ ํ™”๋ฉด ๋“ฑ)
26
+ docs/web-adapter/ # ์›น ์ธก ๋ธŒ๋ฆฟ์ง€ ์–ด๋Œ‘ํ„ฐ(/kickoff์ด ์›น repo์— ์„ค์น˜)
27
+ ```
28
+ ์—์ด์ „ํŠธ ์Šคํ‚ฌ์€ ์ด repo์— ๋‘์ง€ ์•Š๋Š”๋‹ค. ์›Œํฌ์ŠคํŽ˜์ด์Šค ๋ฃจํŠธ `.claude/`์—๋งŒ ๋‘”๋‹ค.
29
+
30
+ - `App.tsx`๋Š” ์–‡๋‹ค: ์Šฌ๋ผ์ด์Šค๋ฅผ ์กฐํ•ฉ๋งŒ ํ•˜๊ณ  ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ๋‘์ง€ ์•Š๋Š”๋‹ค.
31
+ - ์˜์กด์€ ๋‹จ๋ฐฉํ–ฅ์ด๋‹ค: `App โ†’ src/{webview,session,auth} โ†’ src/{bridge,config,ui}`. ์Šฌ๋ผ์ด์Šค๋ผ๋ฆฌ๋Š” ๊ณต๊ฐœ ํ‘œ๋ฉด๋งŒ ์“ด๋‹ค.
32
+
33
+ ## ๋ถˆ๋ณ€์‹
34
+
35
+ ์–ด๊ธฐ๋ฉด ๋นŒ๋“œยท์‹ฌ์‚ฌยท๋ณด์•ˆ์ด ๊นจ์ง„๋‹ค. ์ƒ์„ธ๋Š” ๊ฐ€์ด๋“œ ์Šคํ‚ฌ์— ์žˆ๊ณ , ์—ฌ๊ธฐ์—” ๊ทœ์น™๋งŒ ๋‘”๋‹ค.
36
+
37
+ 1. **ssb ๋ธŒ๋ฆฟ์ง€๊ฐ€ ๊ณ„์•ฝ์˜ SSOT๋‹ค.** `src/bridge/contract.ts`ยท`reader.ts`๋Š” ์›น๊ณผ ๋ฐ”์ดํŠธ ๋‹จ์œ„๋กœ ๋™์ผํ•˜๊ฒŒ ๋™๊ธฐํ™”๋˜๊ณ , CI checksum์ด ์–ด๊ธ‹๋‚จ์„ ๋ง‰๋Š”๋‹ค. ๊ณ„์•ฝ์€ ์ถ”๊ฐ€๋งŒ ํ—ˆ์šฉํ•œ๋‹ค(ํƒ€์ž…ยท์˜ต์…”๋„ ํ•„๋“œ๋งŒ ์ถ”๊ฐ€, ์ œ๊ฑฐยท์ด๋ฆ„๋ณ€๊ฒฝยทํ•„์ˆ˜ํ™” ๊ธˆ์ง€). reader๋Š” tolerantํ•˜๋‹ค(๋ชจ๋ฅด๋Š”ยท๊นจ์ง„ ๋ฉ”์‹œ์ง€๋Š” `UNKNOWN`, ์˜ˆ์™ธ๋ฅผ ๋˜์ง€์ง€ ์•Š์Œ). ํ† ํฐ์€ ๋ธŒ๋ฆฟ์ง€๋กœ ๋ณด๋‚ด์ง€ ์•Š๋Š”๋‹ค. โ†’ `bridge-guide`
38
+
39
+ 2. **์„ธ์…˜ ํ•ธ๋“œ์˜คํ”„๋Š” opt-in์ด๊ณ  v1์—” ํ˜ธ์ถœ์ž๊ฐ€ ์—†๋‹ค.** ๊ธฐ๋ณธ ๋กœ๊ทธ์ธ์€ ์›น์ด ์ง์ ‘ ์ฒ˜๋ฆฌํ•˜๊ณ  ์…ธ์€ ๊ด€์—ฌํ•˜์ง€ ์•Š๋Š”๋‹ค.
40
+ - ํ๋ฆ„: ๋„ค์ดํ‹ฐ๋ธŒ ๋กœ๊ทธ์ธ โ†’ POST `/auth/app-bridge` + short-TTL 1ํšŒ์šฉ nonce โ†’ Set-Cookie 303. URL์— `?token=`์„ ๋„ฃ์ง€ ์•Š๋Š”๋‹ค(์œ ์ถœ).
41
+ - ํ•ธ๋“œ์˜คํ”„ ๋’ค์—” ์›น์ด ์„ธ์…˜ ๊ฐฑ์‹ ์„ ๋‹จ๋…์œผ๋กœ ๋งก๋Š”๋‹ค. ๋„ค์ดํ‹ฐ๋ธŒ๋Š” `autoRefreshToken:false`๊ฐ€ ํ•„์ˆ˜๋‹ค. refresher๊ฐ€ ๋‘˜์ด๋ฉด Supabase refresh-token reuse-detection์ด ์„ธ์…˜ ์ „์ฒด๋ฅผ ํ๊ธฐํ•œ๋‹ค.
42
+ - ๋กœ๊ทธ์•„์›ƒ์€ ์›น signOut์„ ๊ฑฐ์ณ ์–‘๋ฐฉํ–ฅ์œผ๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค. โ†’ `bridge-guide`(๊ณ„์•ฝ) ยท `native-app-guide`(์…ธ ๋ฐฐ์„ )
43
+
44
+ 3. **`env.ts`๋Š” fail-loud๋‹ค.** `EXPO_PUBLIC_WEB_URL`์ด ์—†๊ฑฐ๋‚˜ ๋น„์—ˆ๊ฑฐ๋‚˜ ํŒŒ์‹ฑ ์‹คํŒจ๊ฑฐ๋‚˜ https๋„ localhost๋„ ์•„๋‹ˆ๋ฉด ์‹œ์ž‘ ์‹œ throwํ•œ๋‹ค(๋ฏธ๊ฐ€๋“œ fallback์€ release ํฐ ํ™”๋ฉด์„ ๋ถ€๋ฅธ๋‹ค). ๋‹จ ๊ฐ€๋“œ๋Š” protocolยทhostname๋งŒ ๋ณธ๋‹ค. ์‹ค๊ธฐ๊ธฐ์™€ ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ๋ฅผ ๊ตฌ๋ถ„ํ•˜์ง€ ๋ชปํ•˜๋ฏ€๋กœ localhost URL์€ ๊ฐ€๋“œ๋ฅผ ํ†ต๊ณผํ•˜๊ณ ๋„ ์‹คํฐ์—์„œ ๊นจ์ง„๋‹ค. `EXPO_PUBLIC_*`๋Š” ๋นŒ๋“œ ์‹œ์ ์— ์ธ๋ผ์ธ๋˜๋ฏ€๋กœ, URL์„ ๋ฐ”๊พธ๋ฉด ์žฌ๋นŒ๋“œํ•ด์•ผ ํ•œ๋‹ค. โ†’ `eas-deploy-guide`
45
+
46
+ 4. **ํ…Œ์ŠคํŠธ๋Š” production ๋นŒ๋“œ ํ•˜๋‚˜๋ฅผ ์Šคํ† ์–ด ํ…Œ์ŠคํŠธ ์ฑ„๋„๋กœ ๋ณด๋‚ด๋Š” ๊ฒƒ์ด๋‹ค.** ๋ฏธ๋ฆฌ๋ณด๊ธฐ์™€ ์ถœ์‹œ ๋ชจ๋‘ ๊ฐ™์€ production ๋นŒ๋“œ๋ฅผ TestFlight(iOS)ยทPlay ๋‚ด๋ถ€ ํ…Œ์ŠคํŠธ(Android)๋กœ ๋ณด๋‚ด ์‹คํฐ์—์„œ ํ™•์ธํ•˜๊ณ , ๊ทธ ๋นŒ๋“œ๋ฅผ ๊ทธ๋Œ€๋กœ ๊ณต๊ฐœ๋กœ ์Šน๊ธ‰ํ•œ๋‹ค. EAS ๋นŒ๋“œ ์ˆ˜๋ฅผ ์•„๋ผ๊ณ  ์‹ค์ œ ์ถœ์‹œ ์•„ํ‹ฐํŒฉํŠธ๋ฅผ ๊ฒ€์ฆํ•˜๊ธฐ ์œ„ํ•ด์„œ๋‹ค.
47
+ - ์Šน๊ธ‰ ์ž์ฒด๋Š” ์Šคํ† ์–ด ์ฝ˜์†”์—์„œ ์ˆ˜๋™์œผ๋กœ ํ•œ๋‹ค(fastlane ๋ฏธ์‚ฌ์šฉ, `eas submit`์€ ํ…Œ์ŠคํŠธ ์ฑ„๋„๊นŒ์ง€๋งŒ).
48
+ - Expo Go๋กœ๋Š” ๋œจ์ง€ ์•Š๋Š”๋‹ค(๋„ค์ดํ‹ฐ๋ธŒ ๋ชจ๋“ˆ). ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ๋„ ๊ฐ€์ •ํ•˜์ง€ ์•Š๋Š”๋‹ค.
49
+ - ์‹ค๊ธฐ๊ธฐ๋Š” prod ์›น์„ https๋กœ ๋กœ๋“œํ•œ๋‹ค. http๋Š” ์นด๋ฉ”๋ผยทWeb CryptoยทSecure ์ฟ ํ‚ค๊ฐ€ ์—๋Ÿฌ ์—†์ด ๋™์ž‘์„ ๋ฉˆ์ถ”๊ณ , ์‹ค๊ธฐ๊ธฐ๋Š” localhost์— ๋‹ฟ์ง€ ๋ชปํ•œ๋‹ค.
50
+ - localhost dev-loop์€ ์š”์ฒญ ์‹œ development ํ”„๋กœํŒŒ์ผ์—๋งŒ ๋ฐฐ์„ ํ•œ๋‹ค(production์—” ๋‘์ง€ ์•Š๋Š”๋‹ค). โ†’ `eas-deploy-guide`
51
+
52
+ 5. **๋„ค์ดํ‹ฐ๋ธŒ ์ฝ”๋“œ๋Š” ์ถ”์ธกํ•˜์ง€ ์•Š๋Š”๋‹ค.** ์ž‘์„ฑ ์ „ v56 ๋ฌธ์„œ๋‚˜ ์„ค์น˜๋œ ํƒ€์ž…์„ ์ฝ๋Š”๋‹ค(์ƒ๋‹จ Expo ์ ˆ ์ฐธ๊ณ ). ๊ตฌ์ฒด ๋ ˆ์‹œํ”ผ๋Š” โ†’ `native-app-guide`.
53
+
54
+ ## ์ฃผ์ œ โ†’ ๊ฐ€์ด๋“œ ์Šคํ‚ฌ
55
+
56
+ ์ž‘์—…์„ ์‹œ์ž‘ํ•˜๋ฉด ํ•ด๋‹น ๊ฐ€์ด๋“œ๊ฐ€ ์ž๋™ ๋กœ๋“œ๋œ๋‹ค. ์ƒ์„ธ ๊ทœ์•ฝ์€ ์—ฌ๊ธฐ ์ธ๋ผ์ธํ•˜์ง€ ์•Š๋Š”๋‹ค.
57
+
58
+ | ์ฃผ์ œ | ๊ฐ€์ด๋“œ |
59
+ |------|--------|
60
+ | ์•ฑ ๊ป๋ฐ๊ธฐ: WebView ํ˜ธ์ŠคํŠธยท๋กœ๋”ฉ/์—๋Ÿฌ/์˜คํ”„๋ผ์ธยทAndroid ๋’ค๋กœ๊ฐ€๊ธฐยท์™ธ๋ถ€ ๋งํฌยทsafe-areaยทํŒŒ์ผ ์—…๋กœ๋“œยท๋”ฅ๋งํฌยทํฌ๋ž˜์‹œ ๋ณต๊ตฌ | `native-app-guide` |
61
+ | ์•ฑโ†”์›น ๋ฉ”์‹œ์ง€ ๊ณ„์•ฝยท์ƒˆ ๋ฉ”์‹œ์ง€ ํƒ€์ž… ์ถ”๊ฐ€ยทtolerant readerยทํ† ํฐ ๋ฏธ๊ฒฝ์œ  | `bridge-guide` |
62
+ | ํ™˜๊ฒฝ ๋ชจ๋ธ(์•ฑ = prod ์›น ๋ž˜ํผ)ยทEAS ๋นŒ๋“œยท์ œ์ถœยทdev buildยท๋ฏธ๋ฆฌ๋ณด๊ธฐยทOTA vs ์žฌ๋นŒ๋“œยท๋ฌด๋ฃŒ ํ‹ฐ์–ด | `eas-deploy-guide` |
63
+ | ์Šคํ† ์–ด ์ถœ์‹œ: ๊ฐœ๋ฐœ์ž ๊ณ„์ •ยท4.2 ์‹ฌ์‚ฌยท์†Œ์…œ ์ฝ˜์†” ์…‹์—…ยท์ œ์ถœยทํ…Œ์ŠคํŠธ ํŠธ๋ž™ยท์ปดํ”Œ๋ผ์ด์–ธ์Šค | `store-release-guide` |
64
+
65
+ ## git ยท ์ปค๋ฐ‹ ยท ์–ธ์–ด
66
+
67
+ - ํ•œ๊ตญ์–ด๋กœ ์†Œํ†ตํ•˜๊ณ , ์ฝ”๋“œ ์‹๋ณ„์žยท๊ธฐ์ˆ  ์šฉ์–ด๋Š” ์›๋ฌธ์„ ์œ ์ง€ํ•œ๋‹ค. ์ฃผ์„์€ ํ•œ๊ตญ์–ดยท์˜์–ด ๋ชจ๋‘ ๊ฐ€๋Šฅํ•˜๋˜, ์Šคํƒ€ํ„ฐ ํ’ˆ์งˆ๋กœ ์œ ์šฉํ•˜๊ฒŒ ์“ด๋‹ค.
68
+ - ์ปค๋ฐ‹์€ Conventional Commits(์˜์–ด): `feat:`ยท`fix:`ยท`docs:`ยท`refactor:`ยท`chore:`. ์˜ˆ: `feat: add android back handler to webview host`.
69
+ - ์‚ฌ์šฉ์ž ๋ฌธ์ž์—ด์€ ๋ฐ˜๋“œ์‹œ `src/i18n.ts`์˜ `t()`๋ฅผ ๊ฑฐ์นœ๋‹ค.
@@ -0,0 +1,47 @@
1
+ import React from "react";
2
+ import { SystemBars } from "react-native-edge-to-edge";
3
+ import { SafeAreaProvider, initialWindowMetrics } from "react-native-safe-area-context";
4
+
5
+ import { WEB_URL } from "./src/config/env";
6
+ import { WebViewHost } from "./src/webview/Host";
7
+ import { LoginScreen } from "./src/auth/LoginScreen";
8
+ import { requestNativeLogout } from "./src/session/sessionHandoff";
9
+
10
+ /**
11
+ * ์•ฑ ๋ฃจํŠธ โ€” ์–‡์€ ํ†ตํ•ฉ ๋ ˆ์ด์–ด.
12
+ *
13
+ * SafeAreaProvider(์ฒซ ํ”„๋ ˆ์ž„ flash ๋ฐฉ์ง€์šฉ initialWindowMetrics) ์•ˆ์—์„œ ์›น๋ทฐ ์…ธ(WebViewHost)์„
14
+ * ๋„์šฐ๊ณ , ๋กœ๊ทธ์ธ ์‹œํŠธ(LoginScreen ์Šค์บํด๋“œ)๋ฅผ ์–น๋Š”๋‹ค. ์‹ค์ œ ๋™์ž‘ยท๋ ˆ์‹œํ”ผ๋Š” ๊ฐ ๋ชจ๋“ˆ์ด ์ฑ…์ž„์ง€๊ณ ,
15
+ * ์—ฌ๊ธฐ์„œ๋Š” ๋ธŒ๋ฆฟ์ง€ ์ฝœ๋ฐฑ๋งŒ ๋ฐฐ์„ ํ•œ๋‹ค.
16
+ *
17
+ * - ์›น์ด "์„ธ์…˜ ์—†์Œ"์„ ์•Œ๋ฆฌ๋ฉด(REQUEST_SESSION_INSTALL โ†’ onNeedLogin) ๋กœ๊ทธ์ธ ์‹œํŠธ๋ฅผ ๋„์šด๋‹ค.
18
+ * v1์€ ๋„ค์ดํ‹ฐ๋ธŒ ์†Œ์…œ ๋กœ๊ทธ์ธ์ด fast-follow๋ผ, ์‹œํŠธ์˜ ์ฃผ ๋™์ž‘์€ ์›น ์ž์ฒด ์ด๋ฉ”์ผ ๋กœ๊ทธ์ธ์œผ๋กœ
19
+ * ๋ณด๋‚ด๋Š” ๊ฒƒ์ด๋‹ค(์›น์ด auth UI์˜ ์ฃผ์ธ).
20
+ * - ์›น ๋กœ๊ทธ์•„์›ƒ(LOGOUT โ†’ onLoggedOut) ์‹œ ๋„ค์ดํ‹ฐ๋ธŒ ๋กœ์ปฌ ์„ธ์…˜ ์‚ฌ๋ณธ๋งŒ ์ •๋ฆฌํ•œ๋‹ค(์›น ์ฟ ํ‚ค๋Š” ์›น์ด ์ •๋ฆฌ).
21
+ */
22
+ export default function App(): React.JSX.Element {
23
+ const [showLogin, setShowLogin] = React.useState(false);
24
+
25
+ const handleNeedLogin = React.useCallback((_redirectPath?: string) => {
26
+ setShowLogin(true);
27
+ }, []);
28
+
29
+ const handleLoggedOut = React.useCallback(() => {
30
+ // ๋„ค์ดํ‹ฐ๋ธŒ ๋กœ์ปฌ ์‚ฌ๋ณธ ์ •๋ฆฌ(๋น„๋™๊ธฐ, fire-and-forget). LOGOUT_DONE์€ ๋ผ์šฐํ„ฐ๊ฐ€ ์›น์— ํ†ต์ง€ํ•œ๋‹ค.
31
+ void requestNativeLogout();
32
+ }, []);
33
+
34
+ return (
35
+ <SafeAreaProvider initialMetrics={initialWindowMetrics}>
36
+ {/* SDK 56๋Š” Android edge-to-edge๊ฐ€ ๊ฐ•์ œ ๊ธฐ๋ณธ โ€” SystemBars(react-native-edge-to-edge)๊ฐ€
37
+ ์ƒํƒœ๋ฐ”ยท๋‚ด๋น„๋ฐ” ์•„์ด์ฝ˜ ์Šคํƒ€์ผ์„ ํ•œ ์ปดํฌ๋„ŒํŠธ๋กœ ์ œ์–ดํ•œ๋‹ค. light ์•ฑ์ด๋ผ ๋‘˜ ๋‹ค ์–ด๋‘์šด ์•„์ด์ฝ˜. */}
38
+ <SystemBars style="dark" />
39
+ <WebViewHost url={WEB_URL} onNeedLogin={handleNeedLogin} onLoggedOut={handleLoggedOut} />
40
+ <LoginScreen
41
+ visible={showLogin}
42
+ onClose={() => setShowLogin(false)}
43
+ onContinueInWebView={() => setShowLogin(false)}
44
+ />
45
+ </SafeAreaProvider>
46
+ );
47
+ }
@@ -0,0 +1,2 @@
1
+ <!-- AGENTS.md๋ฅผ ๊ทธ๋Œ€๋กœ ๋ถˆ๋Ÿฌ์˜ต๋‹ˆ๋‹ค. ์ด repo์˜ ์—์ด์ „ํŠธ ๊ทœ์น™์€ AGENTS.md์—์„œ ๋‹จ์ผ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. -->
2
+ @AGENTS.md
@@ -0,0 +1,17 @@
1
+ Copyright (c) 2026 ์‹œ์Šคํ…œ์„ค๊ณ„์ž
2
+
3
+ This template is distributed to students of the author's course
4
+ (brand: ์‹œ์Šคํ…œ์„ค๊ณ„์ž).
5
+
6
+ You may use it as the starting point for any of your own projects โ€”
7
+ personal or commercial. You may modify it freely, ship products built
8
+ with it, and you keep all rights to the work you create on top.
9
+
10
+ You may not redistribute the template itself, repackage it as a course
11
+ or book, or include it in any dataset used to train machine learning
12
+ models. Access is part of the course.
13
+
14
+ THE TEMPLATE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15
+ OR IMPLIED. THE AUTHOR SHALL NOT BE LIABLE FOR ANY CLAIM, DAMAGES, OR
16
+ OTHER LIABILITY ARISING FROM OR IN CONNECTION WITH THE TEMPLATE OR ITS
17
+ USE.