Skip to content

Parkseojin08/DevChat

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

14 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

DevChat

Node.js React PostgreSQL Socket.io

DevChat 은 페이슀뢁 ν˜•μ‹μ˜ SNS 와 페이슀뢁 λ©”μ‹ μ € ν˜•μ‹μ˜ μ‹€μ‹œκ°„ μ±„νŒ…μ„ ν•œ μ„œλΉ„μŠ€λ‘œ ν†΅ν•©ν•œ ν•™μŠ΅μš© ν’€μŠ€νƒ μ›Ή μ• ν”Œλ¦¬μΌ€μ΄μ…˜μž…λ‹ˆλ‹€. κ²Œμ‹œκΈ€Β·λŒ“κΈ€Β·μ’‹μ•„μš”Β·μΉœκ΅¬ 관계 같은 SNS 핡심 κΈ°λŠ₯κ³Ό, Socket.io 기반 μ‹€μ‹œκ°„ 1:1 / κ·Έλ£Ή μ±„νŒ…, 그리고 μ‚¬μš©μž ν™œλ™μ„ μΆ”μ ν•˜λŠ” μ•Œλ¦Ό μ‹œμŠ€ν…œμ„ ν•˜λ‚˜μ˜ μΌκ΄€λœ μ•„ν‚€ν…μ²˜ μœ„μ— κ΅¬ν˜„ν–ˆμŠ΅λ‹ˆλ‹€. JWT + HttpOnly μΏ ν‚€ 기반 인증, 이메일 인증 κ°€μž… 흐름, 계측 뢄리(Controller / Service / Repository) λ°±μ—”λ“œ ꡬ쑰, PostgreSQL 의 CASCADE μ œμ•½κ³Ό ENUM νƒ€μž…μ„ 적극 ν™œμš©ν•œ 데이터 λͺ¨λΈλ§μ„ 톡해 μ‹€μ œ μ„œλΉ„μŠ€ μˆ˜μ€€μ˜ 섀계 원칙을 μ μš©ν•˜λŠ” 것을 λͺ©ν‘œλ‘œ ν•©λ‹ˆλ‹€.


λͺ©μ°¨


μ£Όμš” κΈ°λŠ₯

총 5개 μ˜μ—­ / 31개 κΈ°λŠ₯ 으둜 κ΅¬μ„±λ©λ‹ˆλ‹€.

Auth β€” 인증 / 계정 관리

  • 이메일 인증 μ½”λ“œ λ°œμ†‘ (νšŒμ›κ°€μž… 1단계, 60초 μΏ¨λ‹€μš΄)
  • 이메일 인증 μ½”λ“œ 검증 + 계정 생성 + μžλ™ 둜그인 (νšŒμ›κ°€μž… 2단계)
  • 둜그인 / λ‘œκ·Έμ•„μ›ƒ
  • JWT Access(1h) + Refresh(14d) 토큰 μžλ™ μž¬λ°œκΈ‰
  • λ‚΄ ν”„λ‘œν•„ 쑰회 / νŽΈμ§‘ (ν”„λ‘œν•„ 이미지 μ—…λ‘œλ“œ 포함)
  • 곡개 ν”„λ‘œν•„ 쑰회
  • νšŒμ› νƒˆν‡΄ (CASCADE 둜 κ΄€λ ¨ 데이터 정리)

Friend β€” 친ꡬ 관계

  • μ‚¬μš©μž 검색 (handle 기반)
  • 친ꡬ μ‹ μ²­ / 수락 / 거절 / μ·¨μ†Œ / 끊기
  • 친ꡬ λͺ©λ‘ 쑰회
  • 보낸 / 받은 친ꡬ μ‹ μ²­ λͺ©λ‘

Feed β€” κ²Œμ‹œκΈ€ / λŒ“κΈ€ / μ’‹μ•„μš”

  • κ²Œμ‹œκΈ€ μž‘μ„± / μˆ˜μ • / μ‚­μ œ (μ΅œλŒ€ 5μž₯ λ―Έλ””μ–΄ 첨뢀)
  • λ‰΄μŠ€ν”Όλ“œ 쑰회 (본인 + accepted 친ꡬ의 κ²Œμ‹œκΈ€)
  • 탐색 ν”Όλ“œ (본인 μ œμ™Έ λ¬΄μž‘μœ„ κ²Œμ‹œκΈ€)
  • ν”„λ‘œν•„ ν”Όλ“œ (νŠΉμ • μœ μ €μ˜ κ²Œμ‹œκΈ€)
  • λŒ“κΈ€ μž‘μ„± / μ‚­μ œ (parent_id 둜 λŒ€λŒ“κΈ€ 계측 지원)
  • μ’‹μ•„μš” / μ’‹μ•„μš” μ·¨μ†Œ (UNIQUE(post_id, user_id) 둜 쀑볡 λ°©μ§€)

Messenger β€” μ‹€μ‹œκ°„ μ±„νŒ…

  • 1:1 μ±„νŒ…λ°© 생성 (direct_key 둜 쀑볡 λ°©μ§€)
  • κ·Έλ£Ή μ±„νŒ…λ°© 생성 / 이름 λ³€κ²½ / 멀버 μ΄ˆλŒ€
  • μ±„νŒ…λ°© λͺ©λ‘ / 멀버 λͺ©λ‘ 쑰회
  • μ‹€μ‹œκ°„ λ©”μ‹œμ§€ μ†‘μˆ˜μ‹  (Socket.io)
  • λ©”μ‹œμ§€ λ‚΄μ—­ 쑰회 (νŽ˜μ΄μ§€λ„€μ΄μ…˜)
  • μ±„νŒ… 이미지 μ—…λ‘œλ“œ
  • λ©”μ‹œμ§€ μ‚­μ œ (soft delete)
  • λ©”μ‹œμ§€ 읽음 ν‘œμ‹œ μ‹€μ‹œκ°„ 동기화
  • μ±„νŒ…λ°© λ‚˜κ°€κΈ°

Notification β€” μ•Œλ¦Ό

  • μ•Œλ¦Ό λͺ©λ‘ 쑰회 (친ꡬ μ‹ μ²­ / 수락, μ’‹μ•„μš”, λŒ“κΈ€, λŒ€λŒ“κΈ€, μ±„νŒ… μ΄ˆλŒ€ λ“± 6μ’…)
  • κ°œλ³„ / 전체 읽음 처리
  • μ•Œλ¦Ό μ‚­μ œ
  • λΆ€λΆ„ 인덱슀(WHERE is_read = FALSE) 둜 미읽음 카운트 μ΅œμ ν™”

기술 μŠ€νƒ

Frontend

ν•­λͺ© μ‚¬μš© 기술
Framework React 19 (functional + hooks)
Routing react-router-dom v7
HTTP Client axios (withCredentials: true)
Real-time socket.io-client
Styling CSS Module (*.module.css)
State useState / useReducer / Context (Redux λ―Έμ‚¬μš©)
Build Create React App (react-scripts 5)

Backend

ν•­λͺ© μ‚¬μš© 기술
Runtime Node.js + Express 5
Real-time Socket.io 4
Auth JWT (jsonwebtoken) + HttpOnly Cookie
Password bcrypt
File Upload multer
Mailer nodemailer (Gmail SMTP)
Env dotenv

Database

ν•­λͺ© μ‚¬μš© 기술
RDBMS PostgreSQL 15+
Driver pg (node-postgres)
νŠΉμ§• UUID + BIGSERIAL ν˜Όν•© PK, ENUM νƒ€μž… 3μ’…, ON DELETE CASCADE, λΆ€λΆ„ 인덱슀, JSONB

Infra / Tooling

ν•­λͺ© μ‚¬μš© 기술
Dev Server (FE) react-scripts dev server (port 3000)
Dev Server (BE) Node.js (port 5000)
CORS cors + credentials
Static Files /uploads 디렉토리 정적 μ„œλΉ™

μ•„ν‚€ν…μ²˜

DevChat λ°±μ—”λ“œλŠ” Single Responsibility λ₯Ό λ”°λ₯Έ 4계측 ꡬ쑰이며, 각 계측은 본인 μ±…μž„λ§Œ μˆ˜ν–‰ν•©λ‹ˆλ‹€.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                       Client (React)                        β”‚
β”‚  pages β†’ components β†’ hooks/contexts β†’ services (axios)     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                         β”‚ HTTPS + Cookie (HttpOnly)
                         β”‚ WebSocket (Socket.io)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                   Express App / Socket.io                   β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  Routes        (URL β†’ Controller)                     β”‚  β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€  β”‚
β”‚  β”‚  Middlewares   (authenticate, upload, errorHandler)   β”‚  β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€  β”‚
β”‚  β”‚  Controllers   (HTTP I/O, ν˜•μ‹ 검증, res.json)         β”‚  β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€  β”‚
β”‚  β”‚  Services      (λΉ„μ¦ˆλ‹ˆμŠ€ 둜직 + λΉ„μ¦ˆλ‹ˆμŠ€ 검증)            β”‚  β”‚
β”‚  β”‚                μ‹€νŒ¨λŠ” boolean 이 μ•„λ‹Œ AppError throw    β”‚  β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€  β”‚
β”‚  β”‚  Repositories  (DB 쿼리만 β€” parameterized)             β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                            β”‚ pg pool
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              PostgreSQL  (10 tables, 3 ENUMs)               β”‚
β”‚  users Β· friendships Β· posts Β· posts_media Β· comments       β”‚
β”‚  likes Β· chat_rooms Β· messages Β· room_members Β· notificationsβ”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

계측별 μ±…μž„

계측 μ±…μž„ κΈˆμ§€
Controller HTTP 처리, ν˜•μ‹ 검증, Service 호좜, 응닡 μž‘μ„± DB 쿼리
Service λΉ„μ¦ˆλ‹ˆμŠ€ 둜직, λΉ„μ¦ˆλ‹ˆμŠ€ 검증, AppError throw res / res.json μ‚¬μš©
Repository DB 쿼리(parameterized)만 λΉ„μ¦ˆλ‹ˆμŠ€ 둜직
Middleware νš‘λ‹¨ 관심사 (인증, μ—…λ‘œλ“œ, μ—λŸ¬ λ³€ν™˜) 도메인 둜직

μ—λŸ¬ 처리: throw + globalHandler νŒ¨ν„΄

// Service β€” μ‹€νŒ¨λŠ” throw
throw new ConflictError('HANDLE_TAKEN', 'ν˜„μž¬ μ‚¬μš©μ€‘μΈ IDμž…λ‹ˆλ‹€.');

// Controller β€” try/catch β†’ next(err)
try {
  const result = await authService.signup(req.body);
  res.status(201).json({ data: result });
} catch (err) { next(err); }

// errorHandler β€” AppError.statusCode 기반 HTTP λ³€ν™˜
// β†’ { error: { code, message } }

응닡 envelope

// 성곡
{ "data": { ... } }

// μ‹€νŒ¨
{ "error": { "code": "HANDLE_TAKEN", "message": "ν˜„μž¬ μ‚¬μš©μ€‘μΈ IDμž…λ‹ˆλ‹€." } }

디렉토리 ꡬ쑰

projectDevChat/
β”œβ”€β”€ client/                          # React ν”„λ‘ νŠΈμ—”λ“œ
β”‚   β”œβ”€β”€ public/
β”‚   β”œβ”€β”€ src/
β”‚   β”‚   β”œβ”€β”€ api/                     # axios 기반 API 호좜 ν•¨μˆ˜
β”‚   β”‚   β”‚   β”œβ”€β”€ axios.js             # μΈμŠ€ν„΄μŠ€ + interceptor (μžλ™ μž¬λ°œκΈ‰)
β”‚   β”‚   β”‚   β”œβ”€β”€ auth.js
β”‚   β”‚   β”‚   β”œβ”€β”€ friend.js
β”‚   β”‚   β”‚   β”œβ”€β”€ feed.js
β”‚   β”‚   β”‚   β”œβ”€β”€ messenger.js
β”‚   β”‚   β”‚   └── user.js
β”‚   β”‚   β”œβ”€β”€ components/
β”‚   β”‚   β”‚   └── feature/             # 도메인 μ»΄ν¬λ„ŒνŠΈ (PostCard, CommentSection λ“±)
β”‚   β”‚   β”œβ”€β”€ contexts/                # AuthContext, SocketContext, UnreadContext
β”‚   β”‚   β”œβ”€β”€ pages/                   # 라우트 λ‹¨μœ„ νŽ˜μ΄μ§€
β”‚   β”‚   β”‚   β”œβ”€β”€ auth/                # Login, Signup, Profile
β”‚   β”‚   β”‚   β”œβ”€β”€ messenger/           # Messenger, ChatRoom, NewChatModal
β”‚   β”‚   β”‚   β”œβ”€β”€ Home.jsx
β”‚   β”‚   β”‚   β”œβ”€β”€ Friends.jsx
β”‚   β”‚   β”‚   └── UserProfile.jsx
β”‚   β”‚   β”œβ”€β”€ App.js
β”‚   β”‚   └── index.js
β”‚   └── package.json
β”‚
β”œβ”€β”€ server/                          # Express λ°±μ—”λ“œ
β”‚   β”œβ”€β”€ src/
β”‚   β”‚   β”œβ”€β”€ app.js / index.js        # μ•± λΆ€νŠΈμŠ€νŠΈλž© (Express + Socket.io)
β”‚   β”‚   β”œβ”€β”€ routes/                  # URL β†’ Controller λ§€ν•‘
β”‚   β”‚   β”‚   β”œβ”€β”€ auth.js
β”‚   β”‚   β”‚   β”œβ”€β”€ friend.js
β”‚   β”‚   β”‚   β”œβ”€β”€ feed.js Β· posts.js Β· comments.js
β”‚   β”‚   β”‚   β”œβ”€β”€ messenger.js
β”‚   β”‚   β”‚   β”œβ”€β”€ users.js
β”‚   β”‚   β”‚   └── notification.js
β”‚   β”‚   β”œβ”€β”€ controllers/             # HTTP 처리 + ν˜•μ‹ 검증
β”‚   β”‚   β”œβ”€β”€ services/                # λΉ„μ¦ˆλ‹ˆμŠ€ 둜직
β”‚   β”‚   β”‚   β”œβ”€β”€ auth.js Β· mailer.js Β· storage.js
β”‚   β”‚   β”‚   β”œβ”€β”€ feed.js Β· friend.js
β”‚   β”‚   β”‚   β”œβ”€β”€ messenger.js Β· notification.js
β”‚   β”‚   β”œβ”€β”€ repositories/            # DB 쿼리
β”‚   β”‚   β”‚   β”œβ”€β”€ user.js Β· emailVerification.js
β”‚   β”‚   β”‚   β”œβ”€β”€ friendship.js Β· feed.js
β”‚   β”‚   β”‚   β”œβ”€β”€ messenger.js Β· notification.js
β”‚   β”‚   β”œβ”€β”€ middlewares/             # authenticate, upload, errorHandler
β”‚   β”‚   β”œβ”€β”€ errors/                  # AppError 클래슀
β”‚   β”‚   β”œβ”€β”€ sockets/                 # Socket.io ν•Έλ“€λŸ¬
β”‚   β”‚   β”‚   β”œβ”€β”€ index.js             # 인증 미듀웨어 + λΆ€νŠΈμŠ€νŠΈλž©
β”‚   β”‚   β”‚   └── messenger.js         # message:send / message:read 이벀트
β”‚   β”‚   └── db/
β”‚   β”‚       └── db.js                # pg pool
β”‚   β”œβ”€β”€ uploads/                     # μ—…λ‘œλ“œλœ 파일 (정적 μ„œλΉ™)
β”‚   β”œβ”€β”€ .env
β”‚   └── package.json
β”‚
β”œβ”€β”€ .claude/
β”‚   β”œβ”€β”€ agents/                      # Sub-agent μ •μ˜ (6개)
β”‚   └── document/                    # λͺ…μ„Έ λ¬Έμ„œ (κΈ°λŠ₯/API/DB)
β”œβ”€β”€ CLAUDE.md                        # ν”„λ‘œμ νŠΈ μ»¨λ²€μ…˜ κ°€μ΄λ“œ
└── README.md

μ‹œμž‘ν•˜κΈ°

사전 μš”κ΅¬μ‚¬ν•­

  • Node.js 18 이상
  • PostgreSQL 15 이상
  • npm (λ˜λŠ” yarn)
  • Gmail 계정 β€” 이메일 인증 λ°œμ†‘μš© (μ•± λΉ„λ°€λ²ˆν˜Έ ν•„μš”)

1. μ €μž₯μ†Œ 클둠

git clone https://github.com/Parkseojin08/DevChat.git
cd DevChat

2. PostgreSQL λ°μ΄ν„°λ² μ΄μŠ€ μ€€λΉ„

-- psql λ˜λŠ” pgAdmin μ—μ„œ μ‹€ν–‰
CREATE DATABASE devchat;

이후 .claude/document/DBν…Œμ΄λΈ”μ •λ¦¬.md 에 μ •μ˜λœ 10개 ν…Œμ΄λΈ”κ³Ό 3개 ENUM νƒ€μž…μ„ μˆœμ„œλŒ€λ‘œ μƒμ„±ν•©λ‹ˆλ‹€.

  • ENUM: friend_status, room_type_status, notification_type
  • ν…Œμ΄λΈ”: users β†’ friendships β†’ posts β†’ posts_media β†’ comments β†’ likes β†’ chat_rooms β†’ messages β†’ room_members β†’ notifications
  • 이메일 인증용: email_verifications (migration 파일: server/src/db/migrations/002_email_verifications.sql)

3. ν™˜κ²½ λ³€μˆ˜ μ„€μ •

server/.env νŒŒμΌμ„ μƒμ„±ν•˜κ³  μ•„λž˜ λ³€μˆ˜λ₯Ό μ±„μ›λ‹ˆλ‹€.

# Node.js / Front URL
NODE_ENV=development
NODE_PORT=5000
FRONT_URL=http://localhost:3000

# PostgreSQL
PG_USER=postgres
PG_HOST=localhost
PG_DATABASE=devchat
PG_PASSWORD=your_password
PG_PORT=5432

# JWT
JWT_SECRET=replace_with_strong_random_string
JWT_REFRESH_SECRET=replace_with_another_strong_random_string

# SMTP (이메일 인증) β€” Gmail μ•± λΉ„λ°€λ²ˆν˜Έ μ‚¬μš©
# Google 계정 β†’ λ³΄μ•ˆ β†’ 2단계 인증 β†’ μ•± λΉ„λ°€λ²ˆν˜Έ 생성
SMTP_USER=your_gmail@gmail.com
SMTP_PASS=your_app_password

.env λŠ” μ ˆλŒ€ μ»€λ°‹ν•˜μ§€ λ§ˆμ„Έμš”. .gitignore 에 ν¬ν•¨λ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€.

4. μ˜μ‘΄μ„± μ„€μΉ˜ & μ‹€ν–‰

# Backend
cd server
npm install
npm start           # http://localhost:5000

# Frontend (별도 터미널)
cd client
npm install
npm start           # http://localhost:3000

λΈŒλΌμš°μ €μ—μ„œ http://localhost:3000 으둜 μ ‘μ†ν•©λ‹ˆλ‹€.

5. λΉŒλ“œ (ν”„λ‘œλ•μ…˜)

cd client
npm run build       # client/build/ 생성

μ‚¬μš©λ°©λ²•

νšŒμ›κ°€μž…

  1. /signup νŽ˜μ΄μ§€μ—μ„œ 아이디(handle), 이메일, 이름, λΉ„λ°€λ²ˆν˜Έ, 생년월일을 μž…λ ₯ν•©λ‹ˆλ‹€.
  2. μ„ νƒμ μœΌλ‘œ ν”„λ‘œν•„ 이미지λ₯Ό 첨뢀할 수 μžˆμŠ΅λ‹ˆλ‹€.
  3. 인증 μ½”λ“œ λ°œμ†‘ λ²„νŠΌμ„ λˆ„λ₯΄λ©΄ μž…λ ₯ν•œ μ΄λ©”μΌλ‘œ 6자리 μ½”λ“œκ°€ λ°œμ†‘λ©λ‹ˆλ‹€.
  4. μ½”λ“œλ₯Ό μž…λ ₯ν•΄ κ²€μ¦ν•˜λ©΄ 계정이 μƒμ„±λ˜κ³  μžλ™μœΌλ‘œ λ‘œκ·ΈμΈλ©λ‹ˆλ‹€.
  5. μ½”λ“œλŠ” 10λΆ„κ°„ μœ νš¨ν•˜λ©°, 60초 μΏ¨λ‹€μš΄ ν›„ μž¬λ°œμ†‘ κ°€λŠ₯ν•©λ‹ˆλ‹€.

ν”Όλ“œ (SNS)

  • ν™ˆ ν™”λ©΄ 상단 μž…λ ₯λž€μ—μ„œ κ²Œμ‹œκΈ€μ„ μž‘μ„±ν•©λ‹ˆλ‹€. μ΄λ―Έμ§€λŠ” μ΅œλŒ€ 5μž₯ 첨뢀 κ°€λŠ₯ν•©λ‹ˆλ‹€.
  • λ‰΄μŠ€ν”Όλ“œ νƒ­: 본인과 친ꡬ의 κ²Œμ‹œκΈ€μ΄ μ΅œμ‹ μˆœμœΌλ‘œ ν‘œμ‹œλ©λ‹ˆλ‹€.
  • 탐색 νƒ­: μΉœκ΅¬κ°€ μ•„λ‹Œ λ‹€λ₯Έ μ‚¬μš©μžμ˜ κ²Œμ‹œκΈ€μ„ λ¬΄μž‘μœ„λ‘œ νƒμƒ‰ν•©λ‹ˆλ‹€.
  • κ²Œμ‹œκΈ€μ— λŒ“κΈ€μ„ λ‹¬κ±°λ‚˜, λŒ“κΈ€μ— λŒ€λŒ“κΈ€μ„ 달 수 μžˆμŠ΅λ‹ˆλ‹€.
  • ν•˜νŠΈ(μ’‹μ•„μš”) λ²„νŠΌμœΌλ‘œ λ°˜μ‘μ„ 남길 수 μžˆμŠ΅λ‹ˆλ‹€.

친ꡬ

  • 상단 검색 λ˜λŠ” 친ꡬ 관리 νŽ˜μ΄μ§€μ—μ„œ handle둜 μ‚¬μš©μžλ₯Ό κ²€μƒ‰ν•©λ‹ˆλ‹€.
  • 친ꡬ 신청을 보내면 μƒλŒ€λ°©μ΄ 수락/κ±°μ ˆν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • 수락된 μΉœκ΅¬λŠ” λ‰΄μŠ€ν”Όλ“œμ— κ²Œμ‹œκΈ€μ΄ ν‘œμ‹œλ˜κ³  DM을 보낼 수 μžˆμŠ΅λ‹ˆλ‹€.

λ©”μ‹ μ €

  • ν•˜λ‹¨ λ„€λΉ„κ²Œμ΄μ…˜μ˜ λ©”μ‹ μ € μ•„μ΄μ½˜μœΌλ‘œ μ΄λ™ν•©λ‹ˆλ‹€.
  • μ±„νŒ… λͺ©λ‘μ—μ„œ κΈ°μ‘΄ μ±„νŒ…λ°©μ„ μ„ νƒν•˜κ±°λ‚˜, + λ²„νŠΌμœΌλ‘œ μƒˆ μ±„νŒ…λ°©μ„ λ§Œλ“­λ‹ˆλ‹€.
  • 1:1 μ±„νŒ…: 친ꡬ λͺ©λ‘μ—μ„œ μƒλŒ€λ°©μ„ μ„ νƒν•©λ‹ˆλ‹€.
  • κ·Έλ£Ή μ±„νŒ…: μ—¬λŸ¬ λͺ…을 선택해 방을 λ§Œλ“€κ³  이름을 μ§€μ •ν•©λ‹ˆλ‹€.
  • 이미지 첨뢀 λ²„νŠΌμœΌλ‘œ 사진을 전솑할 수 μžˆμŠ΅λ‹ˆλ‹€.
  • λ‚΄ λ©”μ‹œμ§€λ₯Ό 길게 λˆ„λ₯΄λ©΄ μ‚­μ œν•  수 μžˆμŠ΅λ‹ˆλ‹€.

ν”„λ‘œν•„

  • 우츑 ν•˜λ‹¨ ν”„λ‘œν•„ μ•„μ΄μ½˜ β†’ ν”„λ‘œν•„ νŽΈμ§‘ μ—μ„œ 이름, μ†Œκ°œκΈ€, ν”„λ‘œν•„ 이미지λ₯Ό λ³€κ²½ν•©λ‹ˆλ‹€.
  • λ‹€λ₯Έ μ‚¬μš©μžμ˜ μ΄λ¦„μ΄λ‚˜ ν”„λ‘œν•„μ„ ν΄λ¦­ν•˜λ©΄ ν•΄λ‹Ή μ‚¬μš©μžμ˜ 곡개 ν”„λ‘œν•„ νŽ˜μ΄μ§€λ‘œ μ΄λ™ν•©λ‹ˆλ‹€.

API κ°œμš”

전체 λͺ…μ„ΈλŠ” .claude/document/API λͺ…μ„Έμ„œ *.md 및 .claude/document/add_function.md λ₯Ό μ°Έμ‘°ν•˜μ„Έμš”. μ•„λž˜λŠ” μ£Όμš” μ—”λ“œν¬μΈνŠΈ μš”μ•½μž…λ‹ˆλ‹€.

Auth β€” /auth

Method Path Auth μ„€λͺ…
POST /auth/email/send-code – νšŒμ›κ°€μž… 1단계: 이메일 인증 μ½”λ“œ λ°œμ†‘
POST /auth/email/verify – νšŒμ›κ°€μž… 2단계: μ½”λ“œ 검증 + 계정 생성 + μžλ™ 둜그인
POST /auth/login – 둜그인 (μΏ ν‚€ λ°œκΈ‰)
POST /auth/logout required λ‘œκ·Έμ•„μ›ƒ (μΏ ν‚€ 제거 + refresh token λ¬΄νš¨ν™”)
POST /auth/refresh refresh cookie Access token μž¬λ°œκΈ‰ (νšŒμ „)
GET /auth/me required λ‚΄ ν”„λ‘œν•„ 쑰회
PATCH /auth/me required ν”„λ‘œν•„ νŽΈμ§‘ (이미지 포함)
DELETE /auth/me required νšŒμ› νƒˆν‡΄

Friend β€” /friendships

Method Path μ„€λͺ…
GET /friendships/search?q=handle μ‚¬μš©μž 검색
GET /friendships 친ꡬ λͺ©λ‘ / 보낸·받은 μ‹ μ²­ λͺ©λ‘
POST /friendships 친ꡬ μ‹ μ²­ (pending 생성)
PATCH /friendships/:id 친ꡬ 수락 (pending β†’ accepted)
DELETE /friendships/:id 거절 / μ‹ μ²­ μ·¨μ†Œ / 친ꡬ 끊기

Feed β€” /posts, /comments, /feed

Method Path μ„€λͺ…
GET /feed λ‰΄μŠ€ν”Όλ“œ (본인 + 친ꡬ)
GET /feed/explore 탐색 ν”Όλ“œ (λ¬΄μž‘μœ„)
POST /posts κ²Œμ‹œκΈ€ μž‘μ„± (μ΅œλŒ€ 5μž₯ λ―Έλ””μ–΄)
PATCH /posts/:id κ²Œμ‹œκΈ€ μˆ˜μ •
DELETE /posts/:id κ²Œμ‹œκΈ€ μ‚­μ œ
GET /posts/user/:userId νŠΉμ • μœ μ €μ˜ κ²Œμ‹œκΈ€
GET /posts/:postId/comments λŒ“κΈ€ λͺ©λ‘
POST /posts/:postId/comments λŒ“κΈ€ μž‘μ„±
DELETE /comments/:id λŒ“κΈ€ μ‚­μ œ
POST /posts/:postId/likes μ’‹μ•„μš”
DELETE /posts/:postId/likes μ’‹μ•„μš” μ·¨μ†Œ

Messenger β€” /chat-rooms, /messages

Method Path μ„€λͺ…
POST /chat-rooms μ±„νŒ…λ°© 생성 (direct / group)
GET /chat-rooms λ‚΄ μ±„νŒ…λ°© λͺ©λ‘
GET /chat-rooms/:id/messages λ©”μ‹œμ§€ λ‚΄μ—­
POST /chat-rooms/:id/messages/upload μ±„νŒ… 이미지 μ—…λ‘œλ“œ
PATCH /chat-rooms/:id μ±„νŒ…λ°© 이름 λ³€κ²½ (group 만)
GET /chat-rooms/:id/members 멀버 λͺ©λ‘
POST /chat-rooms/:id/members 멀버 μ΄ˆλŒ€
DELETE /chat-rooms/:id/members/me μ±„νŒ…λ°© λ‚˜κ°€κΈ°
DELETE /messages/:id λ©”μ‹œμ§€ μ‚­μ œ (soft)

User / Notification

Method Path μ„€λͺ…
GET /users/:id 곡개 ν”„λ‘œν•„ 쑰회
GET /notifications μ•Œλ¦Ό λͺ©λ‘
PATCH /notifications/read-all 전체 읽음 처리
PATCH /notifications/:id κ°œλ³„ 읽음 처리
DELETE /notifications/:id μ•Œλ¦Ό μ‚­μ œ

Socket.io 이벀트

Socket.io λŠ” μΏ ν‚€μ˜ accessToken 으둜 인증되며, μ—°κ²° μ‹œ μ‚¬μš©μžκ°€ μ†ν•œ λͺ¨λ“  μ±„νŒ…λ°©μ˜ room:{roomId} 에 μžλ™ join λ©λ‹ˆλ‹€.

Client β†’ Server

Event Payload μ„€λͺ…
message:send { room_id, content, media_url } λ©”μ‹œμ§€ 전솑 β€” 같은 λ°© μ „μ›μ—κ²Œ message:receive emit
message:read { room_id, last_message_id } 읽음 ν‘œμ‹œ β€” 같은 방의 λ‹€λ₯Έ λ©€λ²„μ—κ²Œ message:read:update emit

Server β†’ Client

Event Payload μ„€λͺ…
message:receive { id, room_id, sender_id, content, media_url, created_at } μƒˆ λ©”μ‹œμ§€ μˆ˜μ‹ 
message:read:update { room_id, user_id, last_read_message_id } λ‹€λ₯Έ λ©€λ²„μ˜ 읽음 μƒνƒœ κ°±μ‹ 
message:error { code, message } μ „μ†‘Β·μ½μŒ 처리 μ‹€νŒ¨

λ³΄μ•ˆ 섀계

ν•­λͺ© 적용
λΉ„λ°€λ²ˆν˜Έ bcrypt ν•΄μ‹œ μ €μž₯. 평문·응닡 λ…ΈμΆœ μ ˆλŒ€ κΈˆμ§€
토큰 μ €μž₯μ†Œ localStorage λ―Έμ‚¬μš© β†’ HttpOnly Cookie (XSS λ°©μ–΄)
토큰 ꡬ쑰 Access(1h) + Refresh(14d), refresh token νšŒμ „
CSRF λ°©μ–΄ sameSite: lax μΏ ν‚€ μ˜΅μ…˜
CORS FRONT_URL ν™”μ΄νŠΈλ¦¬μŠ€νŠΈ + credentials: true
SQL Injection μ „ 쿼리 parameterized ($1, $2 …)
User Enumeration λ―Έκ°€μž… 이메일과 λΉ„λ°€λ²ˆν˜Έ 뢈일치λ₯Ό 동일 μ—λŸ¬λ‘œ 응닡
이메일 인증 6자리 μ½”λ“œ + 10λΆ„ 만료 + 5회 μ‹œλ„ μ œν•œ + 60초 μž¬λ°œμ†‘ μΏ¨λ‹€μš΄
κΆŒν•œ 검증 λͺ¨λ“  λΉ„-곡개 라우트 authenticate 미듀웨어 톡과 + Service λ‹¨μ—μ„œ μ†Œμœ κΆŒ/멀버십 μž¬κ²€μ¦
CASCADE νšŒμ› νƒˆν‡΄ μ‹œ μž‘μ„±ν•œ λͺ¨λ“  데이터 μžλ™ 정리
μ‹œν¬λ¦Ώ ν•˜λ“œμ½”λ”© κΈˆμ§€ β†’ .env 둜 뢄리
파일 μ—…λ‘œλ“œ multer 둜 νƒ€μž…Β·ν¬κΈ° μ œν•œ, uploads/ λ””λ ‰ν† λ¦¬λ§Œ 정적 μ„œλΉ™

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors