개요
Matcha는 ecole42의 웹 프로젝트 중 하나로, Tinder와 유사한 데이팅 웹사이트를 구현한 프로젝트다.
⚠️ 제약사항: 이 프로젝트에서는 ORM, validators, User Accounts Manager, NoSQL Database 사용이 엄격히 금지되어 있다.
스크린샷
| Light Mode | Dark Mode |
|---|---|
![]() | ![]() |
![]() | ![]() |
| Chat | Notification |
|---|---|
![]() | ![]() |
| Mobile | Map |
|---|---|
![]() | ![]() |
| Scroll Pagination |
|---|
![]() |
주요 기능
인증 및 보안
- JWT 인증: Access Token과 Refresh Token을 사용한 인증 플로우
- 이메일 인증: 회원가입 시 이메일 검증 링크 발송
- 비밀번호 재설정: 이메일을 통한 비밀번호 재설정 기능
- Google OAuth2 로그인: 소셜 로그인 지원
사용자 매칭
- 지능형 추천 시스템: 사용자의 관심사, 나이, 언어, 성적 지향(이성애, 동성애, 양성애)을 기반으로 한 매칭 추천
- 위치 기반 매칭: GPS 좌표를 이용한 거리 기반 매칭
- IP 기반 위치 추적: 브라우저 GPS 허용이 없는 경우 IP 주소 기반 위치 추적
- 고급 검색: 나이, 명성 점수, 위치, 태그를 기반으로 한 필터링 및 정렬
소셜 기능
- 실시간 채팅: Socket.IO를 활용한 실시간 메시징
- 좋아요 시스템: 사용자 간 좋아요 및 상호 좋아요 알림
- 프로필 방문 추적: 프로필 방문 기록 및 알림
- 차단 기능: 사용자 차단 기능
- 신고 기능: 부적절한 사용자 신고 기능
사용자 프로필
- 다중 이미지 업로드: 프로필 사진 여러 장 업로드
- 태그 시스템: 관심사 태그 추가 및 관리
- 자기소개: 프로필 소개글 작성
- 명성 점수: 사용자 활동 기반 명성 점수 시스템
UI/UX
- 다크 모드: 라이트/다크 테마 전환 지원
- 반응형 디자인: 모바일 및 데스크톱 최적화
- Google Maps 통합: 인터랙티브 지도를 통한 위치 표시
- 무한 스크롤: 스크롤 이벤트 기반 페이지네이션
- 알림 시스템: 실시간 알림 수신 및 관리
개발 도구
- 시드 데이터: 자동 생성된 500명의 테스트 사용자 데이터
기술 스택
Frontend
- Nuxt.js 2.15: Server Side Rendering (SSR)
- Vue.js: 프론트엔드 프레임워크
- Vuetify: Material Design 컴포넌트 라이브러리
- Vuex: 상태 관리
- Socket.IO Client: 실시간 통신
- Vue2 Google Maps: 지도 통합
Backend
- Express.js: RESTful API 서버
- TypeScript: 타입 안정성
- Socket.IO: 실시간 웹소켓 통신
- MySQL 8.0: 관계형 데이터베이스 (Docker)
- JWT: 인증 토큰 관리
- bcrypt: 비밀번호 해싱
- Multer: 파일 업로드 처리
- Mailgun: 이메일 서비스
DevOps
- Docker & Docker Compose: 데이터베이스 컨테이너화
- Node.js: 런타임 환경
프로젝트 구조
matcha/
├── api/ # Backend API 서버
│ ├── controller/ # 컨트롤러 (비즈니스 로직)
│ │ ├── Authentification.ts
│ │ ├── Chat.ts
│ │ ├── Like.ts
│ │ ├── Profile.ts
│ │ ├── Search.ts
│ │ └── ...
│ ├── models/ # 데이터 모델
│ │ ├── User.ts
│ │ ├── Chat.ts
│ │ ├── UserLike.ts
│ │ └── ...
│ ├── routes/ # API 라우트
│ │ ├── auth.ts
│ │ └── api/
│ │ ├── profile.ts
│ │ ├── chat.ts
│ │ ├── search.ts
│ │ └── ...
│ ├── middleware/ # 미들웨어
│ │ ├── authToken.ts
│ │ ├── validator.ts
│ │ └── ...
│ ├── services/ # 서비스 레이어
│ │ ├── Socket.ts
│ │ ├── Token.ts
│ │ ├── Mailing.ts
│ │ └── Location.ts
│ ├── init/ # 데이터베이스 초기화
│ │ ├── Database.ts
│ │ ├── InitDB.ts
│ │ └── SeedDB.ts
│ └── index.ts # Express 서버 진입점
│
├── app/ # Frontend Nuxt 애플리케이션
│ ├── components/ # Vue 컴포넌트
│ │ ├── App/ # 앱 내부 컴포넌트
│ │ │ ├── chat/
│ │ │ ├── notifications/
│ │ │ ├── profile/
│ │ │ └── search/
│ │ └── Home/ # 홈페이지 컴포넌트
│ ├── pages/ # 페이지 라우트
│ │ ├── app/ # 인증 필요 페이지
│ │ └── index.vue # 홈페이지
│ ├── store/ # Vuex 스토어
│ ├── middleware/ # Nuxt 미들웨어
│ ├── plugins/ # Nuxt 플러그인
│ └── nuxt.config.js # Nuxt 설정
│
├── docker-compose.yml # Docker Compose 설정
├── eval.sh # 자동 실행 스크립트
└── package.json # 루트 패키지 설정
설치 및 실행
사전 요구사항
- Docker 및 Docker Compose (>= 1.27)
- Node.js (권장: v14 이상)
- npm 또는 yarn
필요한 API 키
다음 API 키를 사전에 준비해야 한다:
- Google Maps API Key (Places API)
- Google OAuth API Key
- Mailgun API Key
환경 변수 설정
api 및 app 폴더에 각각 .env 파일을 생성해야 한다. .env.example 파일을 참고하여 다음 변수들을 설정한다:
api/.env
# Database
DB_HOST=localhost
DB_USER=root
DB_PASSWORD=root
DB_NAME=matcha
DB_PORT=3306
# Server
PORT=5000
API=http://localhost:5000
APP=http://localhost:3000
ENVIRONMENT=build
# JWT
JWT_SECRET=your-secret-key
JWT_REFRESH_SECRET=your-refresh-secret-key
# Mailgun
MAILGUN_API_KEY=your-mailgun-api-key
MAILGUN_DOMAIN=your-mailgun-domain
# Google OAuth
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
app/.env
# API Server
API=http://localhost:5000
# Server
PORT=3000
ENVIRONMENT=build
# Google Maps
GOOGLE_MAPS_API_KEY=your-google-maps-api-key
# Google OAuth
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
빠른 시작
자동 실행 스크립트를 사용하여 한 번에 모든 것을 설정하고 실행할 수 있다:
sh ./eval.sh
이 스크립트는 다음 작업을 수행한다:
- Docker로 MySQL 데이터베이스 시작
- 루트 및 서브 프로젝트 의존성 설치
- 프로젝트 빌드
- 데이터베이스 초기화 및 시드 데이터 생성
- API 서버 및 프론트엔드 서버 시작
수동 실행
1. 데이터베이스 시작
npm run db
# 또는
docker-compose up -d
2. 의존성 설치
npm run install
3. 프로젝트 빌드
npm run build
4. 데이터베이스 초기화 및 시드 데이터 생성
npm run init_seed
5. 서버 시작
npm run start
개별 서버 실행:
# API 서버만 실행
npm run start-api
# 프론트엔드 서버만 실행
npm run start-app
개발 모드
개발 중에는 각 디렉토리에서 직접 실행할 수 있다:
# API 서버 (개발 모드)
cd api
npm run server
# 프론트엔드 서버 (개발 모드)
cd app
npm run dev
API 엔드포인트
인증 (/auth)
POST /auth/register- 회원가입POST /auth/login- 로그인POST /auth/refresh- 토큰 갱신DELETE /auth/logout- 로그아웃GET /auth/me- 현재 사용자 정보POST /auth/social- 소셜 로그인GET /auth/email-verification/:jwt- 이메일 인증POST /auth/reset-password- 비밀번호 재설정 요청GET /auth/reset-password/:jwt- 비밀번호 재설정 확인
프로필 (/api/profile)
GET /api/profile- 프로필 목록 조회GET /api/profile/:id- 특정 프로필 조회PUT /api/profile- 프로필 수정POST /api/profile/picture- 프로필 사진 업로드DELETE /api/profile/picture/:id- 프로필 사진 삭제
검색 (/api/search)
GET /api/search- 사용자 검색POST /api/search- 고급 검색
좋아요 (/api/like)
POST /api/like/:id- 사용자 좋아요DELETE /api/like/:id- 좋아요 취소
채팅 (/api/chat)
GET /api/chat- 채팅 목록 조회GET /api/chat/:id- 특정 채팅 메시지 조회POST /api/chat/:id- 메시지 전송
알림 (/api/notifications)
GET /api/notifications- 알림 목록 조회PUT /api/notifications/:id- 알림 읽음 처리PUT /api/notifications- 모든 알림 읽음 처리
차단 (/api/block)
POST /api/block/:id- 사용자 차단DELETE /api/block/:id- 차단 해제GET /api/block- 차단 목록 조회
신고 (/api/report)
POST /api/report/:id- 사용자 신고
태그 (/api/tags)
GET /api/tags- 태그 목록 조회POST /api/tags- 태그 추가DELETE /api/tags/:id- 태그 삭제
데이터베이스 구조
주요 테이블
users
- 사용자 기본 정보 (이메일, 사용자명, 비밀번호, 이름 등)
- 성별, 성적 지향, 자기소개
- 위치 정보 (GPS 좌표)
- 명성 점수, 온라인 상태, 마지막 로그인 시간
user_pictures
- 사용자 프로필 사진 정보
user_tags
- 사용자 관심사 태그
user_likes
- 사용자 간 좋아요 관계
user_blocks
- 사용자 차단 관계
chats
- 채팅방 정보
chat_messages
- 채팅 메시지 내용
user_notifications
- 알림 정보 (좋아요, 메시지, 프로필 방문 등)
tags
- 태그 마스터 데이터
자세한 데이터베이스 구조는 api/models/DATA.md를 참고한다.
보안 기능
- JWT 토큰 기반 인증: Access Token (15분) 및 Refresh Token (7일)
- 비밀번호 해싱: bcrypt를 사용한 안전한 비밀번호 저장
- CORS 설정: 허용된 도메인만 접근 가능
- 쿠키 기반 인증: HttpOnly 쿠키를 통한 토큰 관리
- 이메일 인증: 회원가입 시 이메일 검증 필수
- IP 기반 위치 추적: GPS 미허용 시 IP 기반 위치 추적
테스트
# 프론트엔드 테스트
cd app
npm test
# API 테스트
cd api
npm test
주요 제약사항
이 프로젝트는 ecole42의 교육 목적으로 다음 도구 사용이 금지되어 있다:
- ❌ ORM (Object-Relational Mapping)
- ❌ 외부 Validator 라이브러리
- ❌ User Accounts Manager
- ❌ NoSQL Database
대신 순수 SQL 쿼리와 직접 구현한 검증 로직을 사용한다.









