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.
- package/CHANGELOG.md +7 -0
- package/LICENSE +17 -0
- package/README.md +19 -0
- package/bin/index.mjs +201 -0
- package/package.json +25 -0
- package/src/scaffold.mjs +109 -0
- package/src/validate.mjs +22 -0
- package/templates/workspace/.claude/settings.json +44 -0
- package/templates/workspace/.claude/skills/bridge-guide/SKILL.md +71 -0
- package/templates/workspace/.claude/skills/eas-deploy-guide/SKILL.md +107 -0
- package/templates/workspace/.claude/skills/go-live/SKILL.md +66 -0
- package/templates/workspace/.claude/skills/kickoff/SKILL.md +72 -0
- package/templates/workspace/.claude/skills/launch/SKILL.md +69 -0
- package/templates/workspace/.claude/skills/native-app-guide/SKILL.md +102 -0
- package/templates/workspace/.claude/skills/preview/SKILL.md +43 -0
- package/templates/workspace/.claude/skills/probe/SKILL.md +17 -0
- package/templates/workspace/.claude/skills/release/SKILL.md +51 -0
- package/templates/workspace/.claude/skills/sketch/SKILL.md +19 -0
- package/templates/workspace/.claude/skills/store-release-guide/SKILL.md +239 -0
- package/templates/workspace/.claude/skills/vercel-cron/SKILL.md +17 -0
- package/templates/workspace/.claude/skills/warmup/SKILL.md +33 -0
- package/templates/workspace/AGENTS.md +39 -0
- package/templates/workspace/CLAUDE.md +2 -0
- package/templates/workspace/LICENSE +17 -0
- package/templates/workspace/README.md +20 -0
- package/templates/workspace/START-HERE.md +52 -0
- package/templates/workspace/gitignore +18 -0
- package/templates/workspace/mobile/.env.example +25 -0
- package/templates/workspace/mobile/AGENTS.md +69 -0
- package/templates/workspace/mobile/App.tsx +47 -0
- package/templates/workspace/mobile/CLAUDE.md +2 -0
- package/templates/workspace/mobile/LICENSE +17 -0
- package/templates/workspace/mobile/README.md +73 -0
- package/templates/workspace/mobile/app.config.ts +153 -0
- package/templates/workspace/mobile/assets/android-icon-background.png +0 -0
- package/templates/workspace/mobile/assets/android-icon-foreground.png +0 -0
- package/templates/workspace/mobile/assets/android-icon-monochrome.png +0 -0
- package/templates/workspace/mobile/assets/favicon.png +0 -0
- package/templates/workspace/mobile/assets/icon.png +0 -0
- package/templates/workspace/mobile/assets/splash-icon.png +0 -0
- package/templates/workspace/mobile/docs/web-adapter/README.md +130 -0
- package/templates/workspace/mobile/docs/web-adapter/route-app-bridge.ts +235 -0
- package/templates/workspace/mobile/eas.json +31 -0
- package/templates/workspace/mobile/gitignore +45 -0
- package/templates/workspace/mobile/index.ts +12 -0
- package/templates/workspace/mobile/package.json +38 -0
- package/templates/workspace/mobile/pnpm-lock.yaml +5201 -0
- package/templates/workspace/mobile/src/auth/LoginScreen.tsx +192 -0
- package/templates/workspace/mobile/src/bridge/capabilities.test.ts +44 -0
- package/templates/workspace/mobile/src/bridge/capabilities.ts +42 -0
- package/templates/workspace/mobile/src/bridge/contract.test.ts +49 -0
- package/templates/workspace/mobile/src/bridge/contract.ts +146 -0
- package/templates/workspace/mobile/src/bridge/messaging.test.ts +49 -0
- package/templates/workspace/mobile/src/bridge/messaging.ts +33 -0
- package/templates/workspace/mobile/src/bridge/reader.test.ts +52 -0
- package/templates/workspace/mobile/src/bridge/reader.ts +31 -0
- package/templates/workspace/mobile/src/bridge/router.test.ts +124 -0
- package/templates/workspace/mobile/src/bridge/router.ts +89 -0
- package/templates/workspace/mobile/src/config/env.ts +51 -0
- package/templates/workspace/mobile/src/i18n.ts +71 -0
- package/templates/workspace/mobile/src/session/secureSession.ts +63 -0
- package/templates/workspace/mobile/src/session/sessionHandoff.ts +151 -0
- package/templates/workspace/mobile/src/ui/ErrorView.tsx +75 -0
- package/templates/workspace/mobile/src/ui/LoadingView.tsx +38 -0
- package/templates/workspace/mobile/src/ui/OfflineView.tsx +73 -0
- package/templates/workspace/mobile/src/webview/Host.tsx +353 -0
- package/templates/workspace/mobile/src/webview/linkBoundary.test.ts +57 -0
- package/templates/workspace/mobile/src/webview/linkBoundary.ts +58 -0
- package/templates/workspace/mobile/tsconfig.json +8 -0
- package/templates/workspace/mobile/vitest.config.ts +14 -0
- package/templates/workspace/package.json +9 -0
- package/templates/workspace/scripts/doctor.mjs +291 -0
- package/templates/workspace/ssb/README.md +10 -0
- package/templates/workspace/ssb/contract.ts +146 -0
- package/templates/workspace/ssb/reader.ts +31 -0
- package/templates/workspace/web/.env.example +39 -0
- package/templates/workspace/web/.gitattributes +1 -0
- package/templates/workspace/web/.github/workflows/ci.yml +61 -0
- package/templates/workspace/web/.vscode/settings.json +8 -0
- package/templates/workspace/web/AGENTS.md +103 -0
- package/templates/workspace/web/CLAUDE.md +2 -0
- package/templates/workspace/web/DESIGN.md +18 -0
- package/templates/workspace/web/LICENSE +17 -0
- package/templates/workspace/web/README.md +48 -0
- package/templates/workspace/web/app/error.tsx +28 -0
- package/templates/workspace/web/app/favicon.ico +0 -0
- package/templates/workspace/web/app/global-error.tsx +19 -0
- package/templates/workspace/web/app/globals.css +130 -0
- package/templates/workspace/web/app/layout.tsx +33 -0
- package/templates/workspace/web/app/not-found.tsx +12 -0
- package/templates/workspace/web/app/page.tsx +11 -0
- package/templates/workspace/web/components/ui/button.tsx +58 -0
- package/templates/workspace/web/components.json +25 -0
- package/templates/workspace/web/docs/ENVIRONMENTS.md +102 -0
- package/templates/workspace/web/docs/LIMITS.md +54 -0
- package/templates/workspace/web/eslint.config.mjs +46 -0
- package/templates/workspace/web/features/.gitkeep +0 -0
- package/templates/workspace/web/gitignore +51 -0
- package/templates/workspace/web/instrumentation-client.ts +16 -0
- package/templates/workspace/web/instrumentation.ts +12 -0
- package/templates/workspace/web/lib/app-env.ts +12 -0
- package/templates/workspace/web/lib/bridge/contract.ts +146 -0
- package/templates/workspace/web/lib/bridge/reader.ts +31 -0
- package/templates/workspace/web/lib/env.server.ts +33 -0
- package/templates/workspace/web/lib/env.ts +21 -0
- package/templates/workspace/web/lib/logger.ts +32 -0
- package/templates/workspace/web/lib/supabase/admin.ts +14 -0
- package/templates/workspace/web/lib/supabase/client.ts +9 -0
- package/templates/workspace/web/lib/supabase/server.ts +24 -0
- package/templates/workspace/web/lib/utils.ts +6 -0
- package/templates/workspace/web/next.config.ts +16 -0
- package/templates/workspace/web/npmrc +14 -0
- package/templates/workspace/web/package.json +60 -0
- package/templates/workspace/web/pnpm-lock.yaml +9155 -0
- package/templates/workspace/web/postcss.config.mjs +7 -0
- package/templates/workspace/web/sentry.edge.config.ts +9 -0
- package/templates/workspace/web/sentry.server.config.ts +9 -0
- package/templates/workspace/web/supabase/migrations/.gitkeep +0 -0
- package/templates/workspace/web/tests/setup.ts +1 -0
- package/templates/workspace/web/tests/utils.test.ts +12 -0
- package/templates/workspace/web/tsconfig.json +35 -0
- package/templates/workspace/web/vercel.json +6 -0
- 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,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,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.
|