๊ฒ๋ํ์ด์ด ์ข ๋ฃ๋๋ค๋ ๋ง์ ๊ดํ ์์ฌ์ด ๋ง์์ด ๋ค๋๋ผ๊ณ ์. ๊ทธ๋์ โ์ด์ ์ด๋ ๊ฒ ๋ ๊ฑฐ, ์ฐ๋ฆฌ(๊ธ๋)์ ์์ ์์ฑยทํ ์คํธ ์ฑํ MVP๋ผ๋ ๋ง๋ค์ด๋ณผ๊น?โ ์ถ์ด์ ๊ฐ๋ณ๊ฒ ์์ํด๋ณธ ํ๋ก์ ํธ์ ๋๋ค!
ํ๋ก์ ํธ๋ฅผ ๋ก์ปฌ ํ๊ฒฝ์์ ์คํํ๋ ค๋ฉด ์๋ ๋จ๊ณ๋ฅผ ๋ฐ๋ฅด์ธ์.
npm installํ๋ก์ ํธ ๋ฃจํธ์ .env.local.ex ํ์ผ์ .env.local๋ก ๋ณต์ฌํ๊ณ ๋ค์ ๊ฐ๋ค์ ์ค์ ํ์ธ์:
# Supabase Configuration (ํ์)
NEXT_PUBLIC_SUPABASE_URL=https://your-project-ref.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key-here
# Cloudflare Configuration (์์ฑ ์ฑํ
์ฉ)
CLOUDFLARE_API_TOKEN=your-cloudflare-api-token
CLOUDFLARE_ACCOUNT_ID=your-account-id
CLOUDFLARE_CALLS_APP_ID=your-calls-app-id
# Development Configuration
NODE_ENV=development
npm run dev์ด์ ๋ธ๋ผ์ฐ์ ์์ http://localhost:3000์ผ๋ก ์ ์ํ์ฌ ํ๋ก์ ํธ๋ฅผ ํ์ธํ ์ ์์ต๋๋ค.
- P2P ๋ฐฉ์ ๋ถ๊ฐ: 40~50๋ช ๋์ ์ ์ ์ ๊ฐ์ 49๊ฐ ์ฐ๊ฒฐ ํ์ (์ด 1,225๊ฐ ์ฐ๊ฒฐ)
- SFU ํ์: ์๋ฒ ์ค๊ณ ๋ฐฉ์์ผ๋ก ํ์ฅ์ฑ ํ๋ณด
- Cloudflare Realtime ์ ํ: ๋น์ฉ๊ณผ ํธ์์ฑ ๊ณ ๋ ค
- ํ์๊ฐ์ ์์ด UUID ๊ธฐ๋ฐ ์ฌ์ฉ์ ์๋ณ
- ๋ก์ปฌ ์คํ ๋ฆฌ์ง๋ฅผ ํตํ ์ธ์ ์ ์ง
- ์์ ๋๋ค์ ์ ์ ๊ฐ ์์ฑ
- Supabase
user.id๋ฅผ ์ฐ์ ์ฌ์ฉํ๋, ์์ง ๊ฐ์ด ์์ ๋๋ ํด๋ผ์ด์ธํธ(user-storage์คํ ์ด)๊ฐuuid๋ก ์์userId๋ฅผ ์์ฑํด ๋์ผ ๋ธ๋ผ์ฐ์ /ํญ์์ ์ผ๊ด๋ ์๋ณ์๋ฅผ ์ ์งํฉ๋๋ค.
- ์ด ํ๋ก์ ํธ๋ ํ์๊ฐ์ ์์ด ์ต๋ช ์ผ๋ก ์๋น์ค๋ฅผ ์ด์ฉํ ์ ์์ต๋๋ค.
- ํ๋ก์ ํธ์์ ์ต๋ช
์ธ์ฆ์ ์ฌ์ฉํ๋ ค๋ฉด ๋ค์ ๋จ๊ณ๋ฅผ ๋ฐ๋ฅด์ธ์.
- Supabase ๋์๋ณด๋์ ๋ก๊ทธ์ธํ์ฌ ํ๋ก์ ํธ๋ฅผ ์ ํํฉ๋๋ค.
- ์ผ์ชฝ ์ฌ์ด๋๋ฐ์์ Authentication ๋ฉ๋ด๋ก ์ด๋ํฉ๋๋ค.
- Sign In / Providers ์น์ ์ ํด๋ฆญํฉ๋๋ค.
- Anonymous ์ต์ ์ ํ์ฑํ(enable)ํ๊ณ ์ ์ฅํฉ๋๋ค.
Supabase Anonymous ํ์ฑํ ์คํฌ๋ฆฐ์ท
์ค์: ์ต๋ช
์ฌ์ฉ์๋ authenticated ์ญํ ์ ๋ถ์ฌ๋ฐ์ต๋๋ค. ๋ฐ์ดํฐ๋ฒ ์ด์ค
์ ๊ทผ ์ ์ด๋ฅผ ์ํด RLS(Row-Level Security) ์ ์ฑ
์ ๋ฐ๋์ ๊ฒํ ํ๊ณ , ํ์ํ ๊ฒฝ์ฐ
is_anonymous ํ๋๋ฅผ ํ์ธํ์ฌ ์ต๋ช
์ฌ์ฉ์์ ์ผ๋ฐ ์ฌ์ฉ์๋ฅผ ๊ตฌ๋ถํ๋ ์ ์ฑ
์ ์ถ๊ฐํด์ผ ํฉ๋๋ค.
- Framework: Next.js 15.5.3 with Turbopack
- Language: TypeScript
- Styling: Tailwind CSS v4
- UI Components: shadcn/ui
- Icons: Lucide React
- Database: Supabase (PostgreSQL)
- Real-time: Supabase Realtime (์ฑํ , ์๊ทธ๋๋ง)
- Authentication: ์ต๋ช ์ ์ (ํ์๊ฐ์ ๋ถํ์)
- SFU Solution: Cloudflare Realtime + SFU
- User Identification: UUID ๊ธฐ๋ฐ ์ต๋ช ์ฌ์ฉ์
- 2D Game Engine: Phaser 3
- Canvas Rendering: WebGL/Canvas API
- Global State: Zustand
- Server State: TanStack React Query
- ๋ชจ๋ ๊ตฌํ์ SOLID ์์น์ ๋ฐ๋ฅด๋ฉฐ ์ฑ ์์ ๋ถ๋ฆฌํฉ๋๋ค.
- ํด๋ฆฐ ์ฝ๋ ๊ท์น์ ์ง์ผ ๋ช ํํ๊ณ ์ ์ง๋ณด์ ๊ฐ๋ฅํ ๊ตฌ์กฐ๋ฅผ ์ ์งํฉ๋๋ค.
- ๋น์ฆ๋์ค ๋ก์ง๊ณผ UI๋ฅผ ๋ถ๋ฆฌํ์ฌ ํ ์คํธ์ ํ์ฅ์ฑ์ ํ๋ณดํฉ๋๋ค.
- ๊ธฐ๋ฅ๋ณ๋ก FSD ๋ ์ด์ด(entities, features, widgets, shared)๋ก ๋๋์ด ์ฑ ์์ ๋ถ๋ฆฌํฉ๋๋ค.
- ์ค๊ณ ์์น์ ๋ฐ๋ผ ๋น์ฆ๋์ค ๋ก์ง๊ณผ UI๋ฅผ ๋ช ํํ ๊ตฌ๋ถํ๊ณ , ํ์ํ ๊ฒฝ์ฐ ๋ฐฐ๋ด(index.ts)์ ํ์ฉํด ๊ณต์ฉ ์ง์ ์ ์ ์ ๊ณตํฉ๋๋ค.
๐ ํ๋ก์ ํธ ํด๋ ๊ตฌ์กฐ ๋ณด๊ธฐ
๐ฆsrc
โฃ ๐app # Next.js App Router (ํ์ด์ง ๋ผ์ฐํ
๋ฐ ์ง์
์ )
โ โฃ ๐api # ์๋ฒ ์ฌ์ด๋ API ๋ผ์ฐํธ (์์ )
โ โฃ ๐providers # ์ ์ญ ์ปจํ
์คํธ ํ๋ก๋ฐ์ด๋
โ โ ๐town # ๋ฉ์ธ ๊ฒ์ ํ์ด ํ์ด์ง ๊ฒฝ๋ก
โฃ ๐entities # ๋น์ฆ๋์ค ์ํฐํฐ (์์ )
โ โฃ ๐player # ํ๋ ์ด์ด ๋ชจ๋ธ
โ โ ๐room # ๋ฐฉ(Room) ๋ชจ๋ธ
โฃ ๐features # ๊ธฐ๋ฅ ๋จ์ (๋น์ฆ๋์ค ๋ก์ง)
โ โฃ ๐auth # ์ธ์ฆ ๊ด๋ จ
โ โฃ ๐chat # ์ฑํ
๊ธฐ๋ฅ
โ โฃ ๐movement # ์ด๋ ๋ก์ง (์์ )
โ โฃ ๐panelToggle # ํจ๋ ํ ๊ธ
โ โฃ ๐presence # ์ ์ ์ํ
โ โฃ ๐room-switch # ๋ฐฉ ์ด๋ (์์ )
โ โ ๐voice # ์์ฑ ์ฑํ
(์์ )
โฃ ๐widgets # ๋
๋ฆฝ์ ์ธ UI ๋ธ๋ก
โ โฃ ๐chatPanel # ์ฑํ
ํจ๋
โ โฃ ๐gameCanvas # ๊ฒ์ ์บ๋ฒ์ค (์์ )
โ โฃ ๐roomLayout # ๋ฐฉ ๋ ์ด์์ (์์ )
โ โฃ ๐townToolbar # ํ๋จ ํด๋ฐ
โ โ ๐usersPanel # ์ ์์ ํจ๋
โ ๐shared # ๊ณต์ฉ ๋ชจ๋
โฃ ๐config # ํ๊ฒฝ ์ค์
โฃ ๐hooks # ๊ณต์ฉ ํ
โฃ ๐lib # ์ ํธ๋ฆฌํฐ
โฃ ๐store # ์ ์ญ ์ํ
โฃ ๐types # ๊ณต์ฉ ํ์
โ ๐ui # ๊ณต์ฉ UI ์ปดํฌ๋ํธ
.env.local.example์ ๋ณต์ฌํด.env.local์ ์์ฑํ๊ณ ์ค ์๋น์ค ํค๋ฅผ ์ ๋ ฅํฉ๋๋ค.- Supabase ์ต๋ช ์ ์, Cloudflare Realtime, Cloudflare Calls ์ค์ ์ ํ๊ฒฝ๋ณ์๋ก ๊ตฌ์ฑํฉ๋๋ค.
- React Query DevTools, Supabase Provider, Zustand ์คํ ์ด, Phaser ์์ง ๋ฑ์ ์ด๊ธฐํํ๋ Provider ๊ณ์ธต์
src/app/providers/์ ๋ฐฐ์นํฉ๋๋ค. - ์ํ ๊ด๋ฆฌ๋ React Query(@tanstack/react-query)๋ก ์๋ฒ ๋ฐ์ดํฐ, Zustand๋ก ํด๋ผ์ด์ธํธ ์ํ๋ฅผ ๊ด๋ฆฌํฉ๋๋ค.
์ ํ๋ฆฌ์ผ์ด์ ์ ์ฒด์์ ์ฌ์ฉํ๋ ํ๋ก๋ฐ์ด๋๋ค์ ๊ด๋ฆฌํฉ๋๋ค.
| ํ๋ก๋ฐ์ด๋ | ์ฉ๋ | ๋ผ์ด๋ธ๋ฌ๋ฆฌ | ํน์ง |
|---|---|---|---|
QueryProvider |
์๋ฒ ์ํ ๊ด๋ฆฌ ๋ฐ ์บ์ฑ | @tanstack/react-query | DevTools ํฌํจ |
SupabaseProvider |
๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ฐ ์ค์๊ฐ ๊ธฐ๋ฅ | @supabase/ssr | ์ต๋ช ์ ์, SSR ์ง์ |
AppProviders |
๋ชจ๋ ํ๋ก๋ฐ์ด๋ ํตํฉ | - | ๊ณ์ธต์ ๊ตฌ์กฐ |
| ํจํค์ง | ์ฉ๋ |
|---|---|
@supabase/ssr |
Supabase SSR ์ง์ |
@supabase/supabase-js |
Supabase ํด๋ผ์ด์ธํธ SDK |
zustand |
๊ฒฝ๋ ์ํ ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ |
@tanstack/react-query |
์๋ฒ ์ํ ๊ด๋ฆฌ ๋ฐ ์บ์ฑ |
@tanstack/react-query-devtools |
React Query ๊ฐ๋ฐ ๋๊ตฌ (DevDependency) |
phaser |
2D ๊ฒ์ ์์ง (WebGL/Canvas ๋ ๋๋ง) |
uuid |
์ต๋ช ์ฌ์ฉ์ ๊ณ ์ ์๋ณ์ ์์ฑ |
tailwind-merge |
Tailwind CSS ํด๋์ค ๋ณํฉ ์ ํธ๋ฆฌํฐ |
@slick-carousel |
๋ฐ์ํ ์บ๋ฌ์ ์ปดํฌ๋ํธ |
lucide-react |
์์ด์ฝ ๋ผ์ด๋ธ๋ฌ๋ฆฌ |
.env.local.ex๋ฅผ ๋ณต์ฌํ์ฌ.env.local์ ๋ง๋ค๊ณ Supabase, Cloudflare Realtime/Calls, NODE_ENV ๊ฐ์ ์ค์ ํค๋ก ์ค์ ํฉ๋๋ค.- React Query(
@tanstack/react-query), Supabase(@supabase/supabase-js,@supabase/ssr), Zustand, Phaser ๋ฑ ์ฃผ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐsrc/app/providers/๋ด๋ถ์์ ์ด๊ธฐํ๋ฉ๋๋ค. - ํ์ํ ํ๋ก๋ฐ์ด๋๋
QueryProvider,SupabaseProvider,AppProviders์ด๋ฉฐ, Supabase๋ ์ต๋ช ์ ์ยทSSRยทRealtime์ ์ง์ํ๊ณ AppProviders๊ฐ ์ ์ฒด ๊ณ์ธต์ ๊ฐ์๋๋ค. - ์ํ ๊ด๋ฆฌ๋ React Query๊ฐ ์๋ฒ ๋ฐ์ดํฐ๋ฅผ, Zustand๊ฐ ํด๋ผ์ด์ธํธ ์ํ๋ฅผ ๋ด๋นํ๋ฉฐ, ๊ด๋ จ ์คํ ์ด๋ FSD ๋ ์ด์ด๋ณ
model/store์ ๋ฐฐ์นํฉ๋๋ค. - Cloudflare Realtime + SFU, Phaser ๊ฒ์ ์์ง ์ค์ , Supabase Realtime ์ค์ ๋ฑ์ ์ ๊ตฌ์ฑ์ด ์ ์์ ์ผ๋ก ์๋ํ ์ ์๋๋ก ํ๊ฒฝ๋ณ์, provider hooks,
AppProviders๊ณ์ธต์์ ์ฐ๊ฒฐํฉ๋๋ค.