Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

457 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐ŸŒ LogLife โ€” ๋ฒ„ํ‚ท๋ฆฌ์ŠคํŠธ๋ฅผ ์ง€๊ตฌ๋ณธ ์œ„์— ๊ธฐ๋กํ•˜๋Š” ์„œ๋น„์Šค

LogLife ํ‘œ์ง€

ํ”„๋กœ์ ํŠธ ์†Œ๊ฐœ

LogLife๋Š” "์ฃฝ๊ธฐ ์ „์— ํ•˜๊ณ  ์‹ถ์€ ๊ฒƒ๋“ค"์„ ๋ฒ„ํ‚ท๋ฆฌ์ŠคํŠธ๋กœ ๋“ฑ๋กํ•˜๊ณ  ๋‹ฌ์„ฑํ•ด๋‚˜๊ฐ€๋Š” ์ธ์ƒ ๊ฒฝํ—˜ ์•„์นด์ด๋ธŒ ์„œ๋น„์Šค์ž…๋‹ˆ๋‹ค.
๋‹จ์ˆœํ•œ ํ•  ์ผ ์•ฑ์ด๋‚˜ ์—ฌํ–‰ ์•ฑ์ด ์•„๋‹Œ, ๋ฒ„ํ‚ท๋ฆฌ์ŠคํŠธ๋ฅผ ์ง€๊ตฌ๋ณธ ์œ„์— ํ•€์œผ๋กœ ์‹œ๊ฐํ™”ํ•˜๊ณ  ์นœ๊ตฌ๋“ค๊ณผ ๊ณต์œ ํ•˜๋Š” ๊ฒฝํ—˜ ๊ธฐ๋ก ๊ณต๊ฐ„์ž…๋‹ˆ๋‹ค.
Google Places API์™€ Globe.gl์„ ํ™œ์šฉํ•ด ๋ฒ„ํ‚ท๋ฆฌ์ŠคํŠธ ํ•ญ๋ชฉ์„ ์ง€๊ตฌ๋ณธ ์œ„์— ํ‘œํ˜„ํ•˜๋ฉฐ, PWA๋กœ ๋ชจ๋ฐ”์ผ์—์„œ๋„ ์„ค์น˜ํ•ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


1. ๊ฐœ๋ฐœ ์Šคํƒ

ํ”„๋ก ํŠธ์—”๋“œ

์šฉ๋„ ๊ธฐ์ˆ 
ํ’€์Šคํƒ ํ”„๋ ˆ์ž„์›Œํฌ Next.js
UI ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ React
ํƒ€์ž… ์‹œ์Šคํ…œ TypeScript
์Šคํƒ€์ผ๋ง Tailwind CSS
์„œ๋ฒ„ ์ƒํƒœ ๊ด€๋ฆฌ TanStack Query
ํด๋ผ์ด์–ธํŠธ ์ƒํƒœ ๊ด€๋ฆฌ Zustand
์• ๋‹ˆ๋ฉ”์ด์…˜ Framer Motion
3D ์ง€๊ตฌ๋ณธ ์‹œ๊ฐํ™” react-globe.gl
์ธ์ฆ (OAuth) NextAuth.js
PWA / ์„œ๋น„์Šค ์›Œ์ปค Serwist

๋ฐฑ์—”๋“œ

์šฉ๋„ ๊ธฐ์ˆ 
ORM / DB ์Šคํ‚ค๋งˆ Prisma
๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค Supabase
์ž…๋ ฅ ์œ ํšจ์„ฑ ๊ฒ€์ฆ Zod
์žฅ์†Œ ๊ฒ€์ƒ‰ ยท ์ž๋™์™„์„ฑ Google Places API

ํ…Œ์ŠคํŠธ / CI

์šฉ๋„ ๊ธฐ์ˆ 
๋‹จ์œ„ ยท ์ปดํฌ๋„ŒํŠธ ํ…Œ์ŠคํŠธ Vitest
API ๋ชจํ‚น MSW
E2E ํ…Œ์ŠคํŠธ Playwright
์ปดํฌ๋„ŒํŠธ ์นดํƒˆ๋กœ๊ทธ Storybook
์‹œ๊ฐ ํšŒ๊ท€ ํ…Œ์ŠคํŠธ ยท CI Chromatic

๋ฐฐํฌ

์šฉ๋„ ๊ธฐ์ˆ 
๋ฐฐํฌ ํ”Œ๋žซํผ Vercel

2. ์ฃผ์š” ๊ธฐ๋Šฅ

๋ฉ”์ธ ํŽ˜์ด์ง€
3D ์ง€๊ตฌ๋ณธ ํ•€ ์‹œ๊ฐํ™”
๐ŸŸก ๊ธˆ์ƒ‰ ๐Ÿ”ด ๋ถ‰์€์ƒ‰ โฌœ ํšŒ์ƒ‰
์ „๋ถ€ ๋‹ฌ์„ฑ ํ•˜๋‚˜๋ผ๋„ ๋งˆ๊ฐ์ผ์ด ์ง€๋‚จ ๊ทธ ์™ธ์˜ ๊ฒฝ์šฐ
  • ์ง€๊ตฌ๋ณธ์„ ๋“œ๋ž˜๊ทธํ•ด ์ž์œ ๋กญ๊ฒŒ ํšŒ์ „ํ•˜๋ฉฐ ๋“ฑ๋กํ•œ ๋ฒ„ํ‚ท๋ฆฌ์ŠคํŠธ ํ•€์„ ํ•œ๋ˆˆ์— ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ํ•€์€ ๊ตญ๊ฐ€๋ณ„๋กœ ํด๋Ÿฌ์Šคํ„ฐ๋ง๋˜์–ด ๊ฐœ์ˆ˜๊ฐ€ ํ•จ๊ป˜ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.
  • ํ•€ ์ƒ‰์ƒ์€ ํ•ด๋‹น ๊ตญ๊ฐ€ ๋ฒ„ํ‚ท๋ฆฌ์ŠคํŠธ์˜ ๋‹ฌ์„ฑ ์ƒํƒœ์— ๋”ฐ๋ผ ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค.

๋ฒ„ํ‚ท๋ฆฌ์ŠคํŠธ ์ž‘์„ฑ
๋ฒ„ํ‚ท๋ฆฌ์ŠคํŠธ ์ž‘์„ฑ
  • ํ•˜๋‹จ ๋‚ด๋น„๊ฒŒ์ด์…˜์˜ ์šฐ์ธก ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ์ž‘์„ฑ ํŒจ๋„์ด ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค.
  • ์ œ๋ชฉ, ๋‚ด์šฉ, ์žฅ์†Œ, ๋‚œ์ด๋„, ์„ค๋ ˆ์ž„, ๊ณต๊ฐœ ๋ฒ”์œ„๋ฅผ ์ž…๋ ฅํ•ด ๋ฒ„ํ‚ท๋ฆฌ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฒ„ํ‚ท๋ฆฌ์ŠคํŠธ ์ƒ์„ธ ํ™”๋ฉด
ํ•€ ํด๋ฆญ โ†’ ๋ชฉ๋ก โ†’ ์ƒ์„ธ
  • ํ•€์„ ํด๋ฆญํ•˜๋ฉด ํ•ด๋‹น ๊ตญ๊ฐ€์˜ ๋ฒ„ํ‚ท๋ฆฌ์ŠคํŠธ ๋ชฉ๋ก์ด ์Šฌ๋ผ์ด๋“œ์—… ํŒจ๋„๋กœ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.
  • ํ•ญ๋ชฉ์„ ์„ ํƒํ•˜๋ฉด ๋ฒ„ํ‚ท๋ฆฌ์ŠคํŠธ ์ƒ์„ธ ํ™”๋ฉด์œผ๋กœ ์ „ํ™˜๋ฉ๋‹ˆ๋‹ค.
  • ์šฐ์ธก ์ƒ๋‹จ์˜ ๋ฒ„ํŠผ์„ ํ†ตํ•ด ๊ณต์œ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฒ„ํ‚ท๋ฆฌ์ŠคํŠธ ์ƒํƒœ ๋ณ€๊ฒฝ
๋‹ฌ์„ฑ ํ† ๊ธ€ + ์ถ•ํ•˜ ํŒ์—…
  • ๋ฏธ๋‹ฌ์„ฑ ํ•ญ๋ชฉ์€ ๋‹ฌ์„ฑ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋‹ฌ์„ฑํ•œ ํ•ญ๋ชฉ์€ ๋ฏธ๋‹ฌ์„ฑ ์ƒํƒœ๋กœ ๋˜๋Œ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋งˆ๊ฐ์ผ์ด ์ง€๋‚œ ํ•ญ๋ชฉ์€ ์ƒˆ ๋งˆ๊ฐ์ผ์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋Œ€์‹œ๋ณด๋“œ ์œ„์ ฏ
๋Œ€์‹œ๋ณด๋“œ ์œ„์ ฏ
  • ํ•˜๋‹จ ๋‚ด๋น„๊ฒŒ์ด์…˜์˜ ๋Œ€์‹œ๋ณด๋“œ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด 4๊ฐœ์˜ ํ†ต๊ณ„ ์œ„์ ฏ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋งคํŠธ๋ฆญ์Šค ์œ„์ ฏ์„ ํด๋ฆญํ•˜๋ฉด ์ƒ์„ธ ์Šฌ๋ผ์ด๋“œ ํŒจ๋„๋กœ ์ „ํ™˜๋ฉ๋‹ˆ๋‹ค.

์นœ๊ตฌ ํŽ˜์ด์ง€ ์นœ๊ตฌ ์ถ”๊ฐ€
์นœ๊ตฌ ํŽ˜์ด์ง€ ์นœ๊ตฌ ์ถ”๊ฐ€
  • ์นœ๊ตฌ ์•„์ด์ฝ˜์„ ํด๋ฆญํ•˜๋ฉด ์นœ๊ตฌ ๋ชฉ๋ก ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.
  • ์นœ๊ตฌ ์ด๋ฆ„์„ ํด๋ฆญํ•˜๋ฉด ํ•ด๋‹น ์‚ฌ์šฉ์ž์˜ ๋ฒ„ํ‚ท๋ฆฌ์ŠคํŠธ ํŽ˜์ด์ง€๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์นœ๊ตฌ ํŽ˜์ด์ง€์—์„œ ๋‹‰๋„ค์ž„์œผ๋กœ ์‚ฌ์šฉ์ž๋ฅผ ๊ฒ€์ƒ‰ํ•˜๊ณ  ์นœ๊ตฌ ์š”์ฒญ์„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ”„๋กœํ•„ ๋ฐฐ์ง€ ํ”„๋กœํ•„ ์‚ฌ์ง„ ๋ณ€๊ฒฝ ๋‹‰๋„ค์ž„ ๋ณ€๊ฒฝ
ํ”„๋กœํ•„ ๋ฐฐ์ง€ ํ”„๋กœํ•„ ์‚ฌ์ง„ ๋ณ€๊ฒฝ ๋‹‰๋„ค์ž„ ๋ณ€๊ฒฝ
  • ํ”„๋กœํ•„ ๋ฐฐ์ง€๋ฅผ ํด๋ฆญํ•˜๋ฉด ๋‚ด ํ”„๋กœํ•„ ํ™”๋ฉด์œผ๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.
  • ํ”„๋กœํ•„ ํ™”๋ฉด์—์„œ ๋ณ€๊ฒฝ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•ด ํ”„๋ฆฌ์…‹ ์•„๋ฐ”ํƒ€ ์ค‘ ์›ํ•˜๋Š” ์‚ฌ์ง„์œผ๋กœ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ํ”„๋กœํ•„ ํ™”๋ฉด์—์„œ ๋‹‰๋„ค์ž„ ๋ณ€๊ฒฝ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•ด ์ƒˆ๋กœ์šด ๋‹‰๋„ค์ž„์œผ๋กœ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

3. ์•„ํ‚คํ…์ฒ˜ ๊ตฌ์กฐ

๋ณ„๋„ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„ ์—†์ด Next.js App Router ์œ„์—์„œ ์ธ์ฆยทDBยท์™ธ๋ถ€ API๋ฅผ ๋ชจ๋‘ ์ฒ˜๋ฆฌํ•˜๋Š” ์„œ๋ฒ„๋ฆฌ์Šค ์•„ํ‚คํ…์ฒ˜์ž…๋‹ˆ๋‹ค.

flowchart TD
    User(["์‚ฌ์šฉ์ž\nBrowser / PWA"])

    subgraph Vercel["Vercel โ€” Next.js 16"]
        SSR["SSR / RSC\nํŽ˜์ด์ง€ ๋ Œ๋”๋ง"]
        API["API Routes\nPlaces ํ”„๋ก์‹œ ยท Auth ์ฝœ๋ฐฑ"]
        SA["Server Actions\n๋ฒ„ํ‚ท๋ฆฌ์ŠคํŠธ CRUD"]
    end

    subgraph Supabase["Supabase"]
        PG[("PostgreSQL")]
    end

    OAuth["Google / Kakao OAuth 2.0"]
    Places["Google Places API\nAutocomplete ยท Details ยท Photos"]

    User -->|HTTPS| SSR
    User -->|OAuth ๋กœ๊ทธ์ธ| OAuth
    OAuth -->|"NextAuth v5 ์ฝœ๋ฐฑ"| API
    SSR --> SA
    SA -->|"Prisma ORM"| PG
    API -->|"Prisma ORM"| PG
    API -->|"์„œ๋ฒ„ ํ”„๋ก์‹œ"| Places
Loading

4. ERD

erDiagram
    User {
        String id PK
        String email UK
        String username UK
        String name
        String image
        Boolean isOnboarded
        Int tokenVersion
        DateTime createdAt
        DateTime updatedAt
    }

    Account {
        String id PK
        String userId FK
        String provider
        String providerAccountId
        String type
    }

    Session {
        String id PK
        String userId FK
        String sessionToken UK
        DateTime expires
    }

    BucketList {
        String id PK
        String shareToken UK
        String userId FK
        String title
        String description
        Visibility visibility
        DateTime deadlineAt
        Int difficulty
        Int excitement
        Boolean achieved
        DateTime achievedAt
        String placeId
        Float lat
        Float lng
        String countryCode
        String displayName
        DateTime createdAt
        DateTime updatedAt
    }

    Friendship {
        String id PK
        String requesterId FK
        String addresseeId FK
        FriendshipStatus status
        DateTime createdAt
        DateTime respondedAt
    }

    User ||--o{ Account : "has"
    User ||--o{ Session : "has"
    User ||--o{ BucketList : "owns"
    User ||--o{ Friendship : "sends"
    User ||--o{ Friendship : "receives"
Loading

5. ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ

  • ์ปดํฌ๋„ŒํŠธ โ€” ๋ผ์šฐํŠธ๊ฐ€ ์•„๋‹Œ ๊ธฐ๋Šฅ ๋‹จ์œ„()๋กœ ๊ตฌ์„ฑ
  • ๋ฐ์ดํ„ฐ ๋ ˆ์ด์–ด โ€” actions/(์“ฐ๊ธฐ) ยท app/api/(์ฝ๊ธฐยทํ”„๋ก์‹œ) ยท src/api/(ํด๋ผ์ด์–ธํŠธ fetch) ์„ธ ๋ ˆ์ด์–ด๋กœ ๋ถ„๋ฆฌ
  • ๋ผ์šฐํŒ… โ€” Parallel + Intercepting Routes๋กœ ๋ชจ๋‹ฌ์„ URL ๊ธฐ๋ฐ˜์œผ๋กœ ๊ด€๋ฆฌ

ํŒŒ์ผ ํŠธ๋ฆฌ

LogLife/
โ”œโ”€โ”€ prisma/
โ”‚   โ””โ”€โ”€ schema.prisma             # DB ์Šคํ‚ค๋งˆ ์ •์˜ (UserยทBucketListยทFriendship ๋“ฑ 5๊ฐœ ๋ชจ๋ธ)
โ”œโ”€โ”€ public/
โ”‚   โ”œโ”€โ”€ avatars/                  # 10์ข… ํ”„๋ฆฌ์…‹ ์•„๋ฐ”ํƒ€
โ”‚   โ”œโ”€โ”€ geo/
โ”‚   โ”‚   โ””โ”€โ”€ countries-110m.json   # ์ง€๊ตฌ๋ณธ ๊ตญ๊ฐ€ ํด๋ฆฌ๊ณค ๋ฐ์ดํ„ฐ
โ”‚   โ”œโ”€โ”€ icons/
โ”‚   โ””โ”€โ”€ manifest.json             # PWA manifest
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ actions/                  # Server Actions โ€” ๋„๋ฉ”์ธ๋ณ„ mutation
โ”‚   โ”œโ”€โ”€ api/                      # ํด๋ผ์ด์–ธํŠธ fetch ํ•จ์ˆ˜ โ€” ๋„๋ฉ”์ธ๋ณ„ ํŒŒ์ผ๋กœ ๋ถ„๋ฅ˜
โ”‚   โ”œโ”€โ”€ app/
โ”‚   โ”‚   โ”œโ”€โ”€ (afterLogin)/
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ @modal/           # Parallel + Intercepting Routes (๋ชจ๋‹ฌ ์˜ค๋ฒ„๋ ˆ์ด)
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ friends/
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ main/
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ onboarding/
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ profile/
โ”‚   โ”‚   โ”œโ”€โ”€ (auth)/
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ login/
โ”‚   โ”‚   โ”œโ”€โ”€ (e2e)/                # E2E ํ…Œ์ŠคํŠธ ์ „์šฉ ๋ผ์šฐํŠธ
โ”‚   โ”‚   โ”œโ”€โ”€ _providers/           # TanStack QueryยทNextAuth ๋“ฑ ์ „์—ญ Provider ๋ž˜ํผ
โ”‚   โ”‚   โ”œโ”€โ”€ api/                  # Route Handlers โ€” ๋„๋ฉ”์ธ๋ณ„ ์ฝ๊ธฐยทํ”„๋ก์‹œ (authยทplaces ํฌํ•จ)
โ”‚   โ”‚   โ”œโ”€โ”€ b/[token]/            # ๊ณต์œ  ํ’€ํŽ˜์ด์ง€
โ”‚   โ”‚   โ”œโ”€โ”€ u/[username]/         # ๊ณต๊ฐœ ์‚ฌ์šฉ์ž ํŽ˜์ด์ง€
โ”‚   โ”‚   โ”œโ”€โ”€ layout.tsx            # ๋ฃจํŠธ ๋ ˆ์ด์•„์›ƒ (ํฐํŠธยท๋ฉ”ํƒ€๋ฐ์ดํ„ฐยทProvider ๋งˆ์šดํŠธ)
โ”‚   โ”‚   โ”œโ”€โ”€ page.tsx              # ๋žœ๋”ฉ ํŽ˜์ด์ง€
โ”‚   โ”‚   โ””โ”€โ”€ sw.ts                 # PWA Service Worker
โ”‚   โ”œโ”€โ”€ auth.ts                   # NextAuth v5 ์„ค์ • (OAuth ์ œ๊ณต์žยท์ฝœ๋ฐฑยท์„ธ์…˜ ์ „๋žต)
โ”‚   โ”œโ”€โ”€ components/               # ๊ธฐ๋Šฅ ๋‹จ์œ„(bucketยทdashboardยทfriendsยทglobeยทnav ๋“ฑ)๋กœ ๋ถ„๋ฅ˜
โ”‚   โ”œโ”€โ”€ lib/                      # ์ˆœ์ˆ˜ ์œ ํ‹ธยท๋„๋ฉ”์ธ ๋กœ์ง โ€” ๋„๋ฉ”์ธ๋ณ„ ๋ถ„๋ฅ˜ (bucketListยทfriendยทdate ๋“ฑ)
โ”‚   โ””โ”€โ”€ types/                    # next-auth ์„ธ์…˜ ํƒ€์ž… ํ™•์žฅ ๋“ฑ ์ „์—ญ ๊ณต์œ  ํƒ€์ž…
โ”œโ”€โ”€ tests/
โ”‚   โ””โ”€โ”€ e2e/
โ”‚       โ”œโ”€โ”€ setup/                # globalSetup / teardown / auth
โ”‚       โ””โ”€โ”€ specs/                # E2E ์‹œ๋‚˜๋ฆฌ์˜ค
โ”œโ”€โ”€ docs/                         # ํ”„๋กœ์ ํŠธ ๋ฌธ์„œ
โ”‚   โ”œโ”€โ”€ plan_spec.md              # ๋น„์ฆˆ๋‹ˆ์Šค ๋„๋ฉ”์ธ ์‚ฌ์–‘ ยท ADR ยท ํŽ˜์ด์ง€ ์‚ฌ์–‘
โ”‚   โ”œโ”€โ”€ cost_constraint.md        # 0์› ์šด์˜ ์ œ์•ฝ ์ •์˜
โ”‚   โ””โ”€โ”€ templates/                # commit ยท issue ยท PR ๋ฉ”์‹œ์ง€ ์–‘์‹
โ”œโ”€โ”€ .storybook/                   # Storybook ์„ค์ • (addonยทwebpackยทpreview)
โ”œโ”€โ”€ .claude/                      # Claude Code ํ•˜๋„ค์Šค ์„ค์ •
โ”‚   โ”œโ”€โ”€ rules/                    # ์ž‘์—… ์œ ํ˜•๋ณ„ ๊ทœ์น™ ํŒŒ์ผ (code_styleยทsecurityยทdeployยทtesting ๋“ฑ 8์ข…)
โ”‚   โ”œโ”€โ”€ skills/                   # ๋กœ์ปฌ ์Šคํ‚ฌ ์ •์˜ (/commitยท/prยท/handoffยท/e2e ๋“ฑ)
โ”‚   โ”œโ”€โ”€ hooks/                    # PreToolUseยทPostToolUse ์ด๋ฒคํŠธ ํ›… ์Šคํฌ๋ฆฝํŠธ
โ”‚   โ”œโ”€โ”€ memory/                   # ์„ธ์…˜ ๊ฐ„ ์ž๋™ ๋ฉ”๋ชจ๋ฆฌ ์ €์žฅ์†Œ (MEMORY.md + ๊ฐœ๋ณ„ md ํŒŒ์ผ)
โ”‚   โ””โ”€โ”€ settings.json             # ๋„๊ตฌ ๊ถŒํ•œยทํ™˜๊ฒฝ๋ณ€์ˆ˜ยทhooks ๋“ฑ๋ก
โ”œโ”€โ”€ .dev/                         # AI ์ž‘์—… ํ”์  (git ์ถ”์  ์ œ์™ธ)
โ”‚   โ”œโ”€โ”€ learnings/                # ์ž‘์—… ์ค‘ ๋ฐœ๊ฒฌํ•œ ํŒจํ„ดยท์ด์Šˆยท์žฌํ˜„ ์–ด๋ ค์› ๋˜ ์˜ค๋ฅ˜ ๊ธฐ๋ก
โ”‚   โ””โ”€โ”€ scratchpad/               # ์ž„์‹œ ๋ฉ”๋ชจ (์ž‘์—… ์ข…๋ฃŒ ํ›„ ์‚ญ์ œ โ€” ๋น„์–ด์žˆ๋Š” ๊ฒŒ ์ •์ƒ)
โ”œโ”€โ”€ CLAUDE.md                     # AI ์ž‘์—… ์ง€์นจยท๊ทœ์น™ ๋งต (์ž‘์—… ์ „ ํ•„๋…)
โ”œโ”€โ”€ AGENTS.md                     # AI ์—์ด์ „ํŠธ ์„ค์ • ํŒŒ์ผ
โ”œโ”€โ”€ proxy.ts                      # Next.js 16 ๋ฏธ๋“ค์›จ์–ด ๋Œ€์ฒด ๋ผ์šฐํŒ… ํ”„๋ก์‹œ
โ”œโ”€โ”€ next.config.ts                # Next.js ๋นŒ๋“œยท์ด๋ฏธ์ง€ยทPWA ์„ค์ •
โ”œโ”€โ”€ vitest.config.ts              # unitยทstorybook ํ”„๋กœ์ ํŠธ ๋ถ„๋ฆฌ ํ…Œ์ŠคํŠธ ์„ค์ •
โ””โ”€โ”€ package.json

์ฝ”๋“œ ๋ ˆ์ด์–ด ๊ตฌ์กฐ ๋‹ค์ด์–ด๊ทธ๋žจ

flowchart TD

subgraph group_app["Next.js App"]
  node_src_app_root["App shell<br/>nextjs shell<br/>[layout.tsx]"]
  node_src_app_auth["Auth routes<br/>route group<br/>[page.tsx]"]
  node_src_app_afterlogin["App routes<br/>route group<br/>[layout.tsx]"]
  node_src_app_modal["Modal routes<br/>parallel routes<br/>[default.tsx]"]
  node_src_app_e2e["E2E routes<br/>test routes<br/>[page.tsx]"]
end

subgraph group_ui["UI Components"]
  node_src_store["Client stores<br/>state stores<br/>[globeStore.ts]"]
  node_src_components_globe(("Globe view<br/>visualization UI<br/>[GlobeView.tsx]"))
  node_src_components_bucket["Bucket tools<br/>feature UI"]
  node_src_components_friends["Friends UI<br/>feature UI<br/>[FriendsView.tsx]"]
  node_src_components_dashboard["Dashboard UI<br/>feature UI<br/>[DashboardPanel.tsx]"]
  node_src_components_profile["Profile UI<br/>feature UI"]
  node_src_components_user["Public profile UI<br/>feature UI"]
  node_src_components_landing["Landing UI<br/>marketing UI<br/>[HeroContent.tsx]"]
  node_src_components_shared["Shared UI<br/>base UI<br/>[Button.tsx]"]
end

subgraph group_logic["Domain Logic"]
  node_src_lib_domain["Domain helpers<br/>pure logic<br/>[bucketStatus.ts]"]
end

subgraph group_data["Data Layer"]
  node_src_app_api_auth["Auth callback<br/>api route<br/>[route.ts]"]
  node_src_app_api_data["Read APIs<br/>api routes<br/>[route.ts]"]
  node_src_actions["Server actions<br/>mutation layer<br/>[actions.ts]"]
  node_src_auth["NextAuth setup<br/>auth config<br/>[auth.ts]"]
  node_src_lib_prisma[("Prisma access<br/>db client<br/>[prisma.ts]")]
  node_prisma_schema["DB schema<br/>[schema.prisma]"]
end

subgraph group_workflow["Workflow"]
  node_tests_workflow["Tests<br/>quality stack<br/>[vitest.config.ts]"]
  node_ops_workflow["Dev workflow<br/>tooling rules<br/>[CLAUDE.md]"]
end

node_src_app_root -->|"routes to"| node_src_app_auth
node_src_app_root -->|"hosts"| node_src_app_afterlogin
node_src_app_afterlogin -->|"overlays"| node_src_app_modal
node_src_app_afterlogin -->|"renders"| node_src_components_globe
node_src_app_afterlogin -->|"renders"| node_src_components_dashboard
node_src_app_afterlogin -->|"renders"| node_src_components_friends
node_src_app_afterlogin -->|"renders"| node_src_components_profile
node_src_app_afterlogin -->|"renders"| node_src_components_bucket
node_src_app_auth -->|"uses"| node_src_auth
node_src_app_api_auth -->|"calls"| node_src_auth
node_src_app_api_data -->|"reads/writes"| node_src_lib_prisma
node_src_actions -->|"mutates"| node_src_lib_prisma
node_src_lib_prisma -->|"implements"| node_prisma_schema
node_src_app_api_data -->|"computes"| node_src_lib_domain
node_src_actions -->|"validates"| node_src_lib_domain
node_src_components_globe -->|"uses"| node_src_store
node_src_components_bucket -->|"fetches"| node_src_app_api_data
node_src_components_friends -->|"fetches"| node_src_app_api_data
node_src_components_dashboard -->|"fetches"| node_src_app_api_data
node_src_components_profile -->|"submits"| node_src_actions
node_src_components_user -->|"fetches"| node_src_app_api_data
node_src_components_landing -->|"reuses"| node_src_components_globe
node_tests_workflow -.->|"covers"| node_src_components_shared
node_tests_workflow -.->|"stabilizes"| node_src_app_e2e
node_ops_workflow -.->|"guides"| node_src_actions

click node_src_app_root "https://github.com/coral0723/loglife/blob/main/src/app/layout.tsx"
click node_src_app_auth "https://github.com/coral0723/loglife/blob/main/src/app/(auth)/login/page.tsx"
click node_src_app_afterlogin "https://github.com/coral0723/loglife/blob/main/src/app/(afterLogin)/layout.tsx"
click node_src_app_modal "https://github.com/coral0723/loglife/blob/main/src/app/(afterLogin)/@modal/default.tsx"
click node_src_app_e2e "https://github.com/coral0723/loglife/blob/main/src/app/(e2e)/e2e-login/page.tsx"
click node_src_app_api_auth "https://github.com/coral0723/loglife/blob/main/src/app/api/auth/[...nextauth]/route.ts"
click node_src_app_api_data "https://github.com/coral0723/loglife/blob/main/src/app/api/bucketlists/[id]/route.ts"
click node_src_actions "https://github.com/coral0723/loglife/blob/main/src/actions/user/actions.ts"
click node_src_auth "https://github.com/coral0723/loglife/blob/main/src/auth.ts"
click node_src_lib_prisma "https://github.com/coral0723/loglife/blob/main/src/lib/prisma.ts"
click node_prisma_schema "https://github.com/coral0723/loglife/blob/main/prisma/schema.prisma"
click node_src_lib_domain "https://github.com/coral0723/loglife/blob/main/src/lib/bucketList/bucketStatus.ts"
click node_src_store "https://github.com/coral0723/loglife/blob/main/src/store/globeStore.ts"
click node_src_components_globe "https://github.com/coral0723/loglife/blob/main/src/components/globe/GlobeView.tsx"
click node_src_components_bucket "https://github.com/coral0723/loglife/blob/main/src/components/bucket/BucketDetailView.tsx"
click node_src_components_friends "https://github.com/coral0723/loglife/blob/main/src/components/friends/FriendsView.tsx"
click node_src_components_dashboard "https://github.com/coral0723/loglife/blob/main/src/components/dashboard/DashboardPanel.tsx"
click node_src_components_profile "https://github.com/coral0723/loglife/blob/main/src/components/profile/ProfileSettingsView.tsx"
click node_src_components_user "https://github.com/coral0723/loglife/blob/main/src/components/user/PublicProfileView.tsx"
click node_src_components_landing "https://github.com/coral0723/loglife/blob/main/src/components/landing/HeroContent.tsx"
click node_src_components_shared "https://github.com/coral0723/loglife/blob/main/src/components/ui/Button.tsx"
click node_tests_workflow "https://github.com/coral0723/loglife/blob/main/vitest.config.ts"
click node_ops_workflow "https://github.com/coral0723/loglife/blob/main/CLAUDE.md"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_src_app_root,node_src_app_auth,node_src_app_afterlogin,node_src_app_modal,node_src_app_e2e toneBlue
class node_src_store,node_src_components_globe,node_src_components_bucket,node_src_components_friends,node_src_components_dashboard,node_src_components_profile,node_src_components_user,node_src_components_landing,node_src_components_shared toneAmber
class node_src_lib_domain toneMint
class node_src_app_api_auth,node_src_app_api_data,node_src_actions,node_src_auth,node_src_lib_prisma,node_prisma_schema toneRose
class node_tests_workflow,node_ops_workflow toneIndigo
Loading

6. AI ์›Œํฌํ”Œ๋กœ์šฐ

flowchart TD
    User(["๐Ÿ‘ค ์‚ฌ์šฉ์ž"])

    subgraph P1["โ‘  ๊ณ„ํš โ†’ ์Šน์ธ โ†’ ๊ตฌํ˜„"]
        Plan["Plan Mode\n๊ณ„ํš ์ˆ˜๋ฆฝ"]
        Approve{"์‚ฌ์šฉ์ž ์Šน์ธ"}
        Impl["๊ตฌํ˜„ ์ž‘์—…\nClaude Code"]
    end

    subgraph P2["โ‘ก ์—ญํ• ๋ณ„ AI ๋ถ„๋ฆฌ"]
        subgraph Auto["์ž๋™ ์œ„์ž„ โ€” OMC"]
            direction LR
            explore["explore"]
            executor["executor"]
            debugger["debugger"]
        end
        subgraph Gates["์ˆ˜๋™ ๊ฒ€์ฆ ๊ฒŒ์ดํŠธ โ€” ์ƒˆ ์„ธ์…˜"]
            direction LR
            test["/test\ntest-engineer"]
            e2e["/e2e\nqa-tester"]
            sec["/security-review\nsecurity-reviewer"]
            qual["/quality-review\ncode-reviewer"]
        end
        Gemini["Gemini Code Assistant\n๊ต์ฐจ ๋ฆฌ๋ทฐ"]
    end

    subgraph P3["โ‘ข ๋กœ๊ทธ ํŒŒ์ดํ”„๋ผ์ธ"]
        direction LR
        Hooks["ํ›… ์ž๋™ ์ˆ˜์ง‘\nUserPromptSubmit ยท PostToolUse"]
        JSONL[".dev/session-logs/*.jsonl"]
        NotionLog["Notion DB\n/sessionlog ยท /branchlog"]
    end

    subgraph P4["โ‘ฃ ์ง€์‹ ๋ˆ„์  ๋ฃจํ”„"]
        direction LR
        Learnings["/learnings\n.dev/learnings/"]
        Rules[".claude/rules/\nknown_issues ยท code_style ยท security ยท testing ยท deploy"]
    end

    User --> Plan
    Plan --> Approve
    Approve -->|๋ฐ˜๋ ค| Plan
    Approve -->|์Šน์ธ| Impl
    Impl <-->|๋ณต์žกํ•œ ์ž‘์—… ์ž๋™ ๋ถ„ํ•ด| Auto
    Impl -->|๋‹จ๊ณ„ ์™„๋ฃŒ| Gates
    Gates -->|PR ๋‹จ๊ณ„| Gemini
    Auto ~~~ Hooks
    Impl --> Hooks
    Hooks --> JSONL --> NotionLog
    Hooks ~~~ Learnings
    Impl -->|์‹ค์ˆ˜ ๋ฐ˜๋ณต| Learnings
    Learnings --> Rules
    Rules -.->|๋‹ค์Œ ์„ธ์…˜ ์ž๋™ ์ฃผ์ž…| Impl
Loading

1๏ธโƒฃ Plan Mode ์„ ์ง„์ž…๊ณผ ์‚ฌ์šฉ์ž ์Šน์ธ ๊ฐ•์ œ

AI๋Š” ์ฆ‰์‹œ ๊ตฌํ˜„ํ•˜๋ ค๋Š” ๊ฒฝํ–ฅ์ด ์žˆ๊ธฐ์— ๋ฐฉํ–ฅ์ด ํ‹€๋ฆฐ ์ฑ„ ์ž‘์—…์ด ๋๋‚˜๋ฉด ๋˜๋Œ๋ฆฌ๋Š” ๋น„์šฉ์ด ํฝ๋‹ˆ๋‹ค.
๊ทธ๋ž˜์„œ ์•„๋ž˜์˜ ๋ฐฉ๋ฒ•์œผ๋กœ ์ž‘์—…์„ ์ง„ํ–‰ํ–ˆ์Šต๋‹ˆ๋‹ค.

  • ๊ทœ์น™ํ™”: CLAUDE.md์— Karpathy 4์›์น™๊ณผ "Plan Mode ์šฐ์„ , ์Šน์ธ ์ „ ๊ตฌํ˜„ ๊ธˆ์ง€" ๋ช…์‹œ
  • ์šด์˜: ๊ธฐ๋Šฅ ์„ธ์…˜๋งˆ๋‹ค Plan Mode ์ง„์ž… โ†’ ๊ณ„ํš ์ˆ˜๋ฆฝ โ†’ ์‚ฌ์šฉ์ž ์Šน์ธ โ†’ ๊ตฌํ˜„ ์ˆœ์„œ ์ค€์ˆ˜

2๏ธโƒฃ AI ์—ญํ• ์„ ๋ถ„๋ฆฌํ•˜์—ฌ ๊ตฌํ˜„๊ณผ ๊ฒ€์ฆ์„ ๋…๋ฆฝ์‹œํ‚ค๋Š” ํ’ˆ์งˆ ๊ด€๋ฆฌ ๊ตฌ์กฐ ์„ค๊ณ„

  • ์ปจํ…์ŠคํŠธ ๊ฒฉ๋ฆฌ: ๋‹ค๋ฅธ ์—ญํ•  ์—์ด์ „ํŠธ๋Š” ํ•ญ์ƒ ์ƒˆ ์„ธ์…˜์œผ๋กœ ์ „ํ™˜ โ€” ๊ตฌํ˜„ ์ปจํ…์ŠคํŠธ ์˜ค์—ผ ๋ฐฉ์ง€
  • ์ž๋™ ์œ„์ž„: ๊ตฌํ˜„ ์ค‘ OMC๊ฐ€ explore ยท executor ๋“ฑ ์„œ๋ธŒ์—์ด์ „ํŠธ๋ฅผ ์ž๋™ ์„ ํƒํ•ด ๋ณต์žก ์ž‘์—…์„ ์ „๋ฌธ ์—ญํ• ๋กœ ๋ถ„ํ•ด
  • ์ˆ˜๋™ ๊ฒ€์ฆ ๊ฒŒ์ดํŠธ: ๋‹จ๊ณ„๋ณ„ ์ „์šฉ ์Šคํ‚ฌ ์ˆ˜๋™ ํ˜ธ์ถœ:
    • /test (test-engineer) โ€” ์ฝ”๋“œ ์ž‘์„ฑ ํ›„
    • /e2e (qa-tester) โ€” ๊ธฐ๋Šฅ ํ๋ฆ„ ์™„์„ฑ ํ›„
    • /security-review (security-reviewer) โ€” auth ยท api ์ž‘์—… ํ›„
    • /quality-review (code-reviewer) โ€” PR ์ „
  • ๊ต์ฐจ ๋ฆฌ๋ทฐ: PR ๋‹จ๊ณ„์—์„œ Gemini Code Assistant ์ถ”๊ฐ€ โ€” ๋™์ผ AI ํŽธํ–ฅ ํ•ด์†Œ

3๏ธโƒฃ AI์˜ ๋ฐ˜๋ณต ์‹ค์ˆ˜๋ฅผ ์ง€์‹์œผ๋กœ ์ถ•์ ํ•˜๋Š” Learning Loop ์„ค๊ณ„

  • ํฌ์ฐฉ: /learnings ์Šคํ‚ฌ๋กœ .dev/learnings/YYYY-MM-DD_{topic}.md์— ์ฆ์ƒ ยท ์›์ธ ยท ๊ฒฐ๋ก  ๊ตฌ์กฐํ™”
  • ์••์ถ•: ํ•ต์‹ฌ 1~2์ค„๋กœ ์š”์•ฝ ํ›„ ์œ ํ˜•๋ณ„ md ํŒŒ์ผ์— ๋ˆ„์ :
    • ๋ฒ„๊ทธ ยท ํ™˜๊ฒฝ โ†’ known_issues.md
    • ์ฝ”๋”ฉ ์Šคํƒ€์ผ โ†’ code_style.md
    • ํ…Œ์ŠคํŠธ โ†’ testing_guide.md
    • ๋ณด์•ˆ โ†’ security.md
    • ๋ฐฐํฌ โ†’ deploy.md
  • ์ž๋™ ํ™œ์„ฑํ™”: CLAUDE.md์— ๋งคํ•‘ ๋ช…์‹œ โ†’ ๋‹ค์Œ ์„ธ์…˜๋ถ€ํ„ฐ ์ž๋™ ์ฃผ์ž…. ์ด์ƒ ์ฆ์ƒ ๋ฐœ๊ฒฌ ์‹œ known_issues.md ์šฐ์„  ํ™•์ธ

4๏ธโƒฃ AI ์ž‘์—…์„ ์ถ”์  ๊ฐ€๋Šฅํ•œ ํ˜•ํƒœ๋กœ ๊ธฐ๋กํ•˜๋Š” ๋กœ๊ทธ ํŒŒ์ดํ”„๋ผ์ธ ์„ค๊ณ„

  • ํ›… ์ž๋™ ์ˆ˜์ง‘: UserPromptSubmit ยท PostToolUse ์‹œ ํ”„๋กฌํ”„ํŠธ ํ…์ŠคํŠธ ยท ํŒŒ์ผ ์ˆ˜์ • ยท ๋ช…๋ น์–ด ์‹คํ–‰์„ .dev/session-logs/{๋ธŒ๋žœ์น˜}/{YYYY-MM-DD}_{์„ธ์…˜ID ์•ž 8์ž}.jsonl์— ์‹ค์‹œ๊ฐ„ ๊ธฐ๋ก
  • ์„ธ์…˜ ๋กœ๊ทธ(/sessionlog): โ€” JSONL์„ ์„ ํƒํ•˜๋ฉด Notion "SessionLog" DB์— ์ฑ•ํ„ฐ๋ณ„ ์ •๋ฆฌ
  • ๋ธŒ๋žœ์น˜ ๋กœ๊ทธ(/branchlog): โ€” git diff ยท git log ๊ธฐ๋ฐ˜ ๋ถ„์„ยท์ •๋ฆฌ ํ›„ Notion "BranchLog" DB์— ๊ธฐ๋ก. /pr ์‹คํ–‰ ์‹œ ํฐ ์ž‘์—… ๋ธŒ๋žœ์น˜๋กœ ํŒ๋‹จ๋˜๋ฉด ์ž๋™ ๊ถŒ์žฅ

7. ๋กœ์ปฌ ์‹คํ–‰ ๋ฐฉ๋ฒ•

์‚ฌ์ „ ์š”๊ตฌ์‚ฌํ•ญ

Node.js 20.9+
pnpm 10+

ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ค์ •

.env.example์„ ๋ณต์‚ฌํ•ด .env ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๊ณ  ์•„๋ž˜ ๊ฐ’์„ ์ฑ„์šด๋‹ค.

# Supabase PostgreSQL
DATABASE_URL="postgresql://user:password@host/dbname?sslmode=verify-full"

# NextAuth v5
AUTH_SECRET=""
AUTH_GOOGLE_ID=""
AUTH_GOOGLE_SECRET=""
AUTH_KAKAO_ID=""
AUTH_KAKAO_SECRET=""

# Google Places API (์„œ๋ฒ„ ์ „์šฉ)
GOOGLE_PLACES_API_KEY=""

์„ค์น˜ ๋ฐ DB ์ดˆ๊ธฐํ™”

๋กœ์ปฌ DB ์„ค์น˜ ๋ถˆํ•„์š” โ€” Vercel Neon(์„œ๋ฒ„๋ฆฌ์Šค PostgreSQL)์— ์ง์ ‘ ์—ฐ๊ฒฐ

pnpm install                  # ํŒจํ‚ค์ง€ ์„ค์น˜ + prisma generate (postinstall ์ž๋™ ์‹คํ–‰)
pnpm prisma migrate deploy    # ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ Neon DB์— ์ ์šฉ

๊ฐœ๋ฐœ ์„œ๋ฒ„ ์‹คํ–‰

pnpm dev

http://localhost:3000 ์—์„œ ํ™•์ธ

ํ…Œ์ŠคํŠธ ์‹คํ–‰

pnpm test              # ๋‹จ์œ„ ํ…Œ์ŠคํŠธ (Vitest)
pnpm test:e2e:ui       # E2E ํ…Œ์ŠคํŠธ (Playwright UI ๋ชจ๋“œ)
pnpm storybook         # ์ปดํฌ๋„ŒํŠธ ์นดํƒˆ๋กœ๊ทธ (ํฌํŠธ 6006)

About

๐ŸŒŽ ์ฃฝ๊ธฐ ์ „์— ์ด๋ฃจ๊ณ  ์‹ถ์€ ๋ฒ„ํ‚ท๋ฆฌ์ŠคํŠธ๋ฅผ ์ง€๊ตฌ ์œ„์— ๊ธฐ๋กํ•˜๋Š” ์„œ๋น„์Šค

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages