# 소셜 로그인 백엔드 API 가이드

## 개요

이 백엔드는 여러 앱에서 공통으로 사용할 수 있는 소셜 로그인 API를 제공합니다.
카카오, 네이버, 구글, 애플 4가지 소셜 로그인을 지원하며, 앱 이름을 통해 앱별로 사용자를 구분합니다.

## 설정 방법

### 1. 의존성 설치

```bash
cd D:\source\works\kssoft\flutter_project\app-master-back
npm install
```

### 2. 환경 변수 설정

`.env` 파일을 생성하고 다음 내용을 설정하세요:

```env
# 서버 설정
PORT=3000
NODE_ENV=development

# 데이터베이스 설정
DB_HOST=localhost
DB_USER=your_db_user
DB_PASSWORD=your_db_password
DB_PORT=3306
DB_NAME=app_master_db

# JWT 시크릿 키 (반드시 변경하세요!)
JWT_SECRET=your-super-secret-jwt-key-change-this-in-production

# 구글 OAuth 클라이언트 ID
GOOGLE_CLIENT_ID=your-google-client-id.apps.googleusercontent.com
```

### 3. 데이터베이스 생성

MySQL에 데이터베이스를 생성합니다:

```sql
CREATE DATABASE app_master_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
```

### 4. 서버 실행

```bash
# 개발 모드 (nodemon)
npm run dev

# 프로덕션 모드
npm start
```

서버가 실행되면 다음과 같은 메시지가 표시됩니다:
```
🔗 Connecting to MySQL database...
✅ MySQL database connected successfully
✅ Users table initialized
✅ User sessions table initialized
🚀 Server running on port 3000
📱 App Master Backend API
🌐 http://localhost:3000
```

## API 엔드포인트

### 1. 카카오 로그인 콜백

**Endpoint:** `POST /api/auth/kakao/callback`

**Request Body:**
```json
{
  "appName": "baby_note",
  "accessToken": "카카오_액세스_토큰",
  "deviceSerial": "디바이스_시리얼_번호",
  "deviceInfo": {
    "platform": "android",
    "model": "SM-G991N",
    "manufacturer": "Samsung"
  }
}
```

**Response:**
```json
{
  "success": true,
  "data": {
    "token": "JWT_토큰",
    "sessionId": "세션_ID",
    "user": {
      "id": "사용자_UUID",
      "socialId": "카카오_사용자_ID",
      "loginType": "kakao",
      "appName": "baby_note",
      "name": "홍길동",
      "email": "user@example.com",
      "profileImage": "프로필_이미지_URL"
    }
  }
}
```

### 2. 네이버 로그인 콜백

**Endpoint:** `POST /api/auth/naver/callback`

**Request Body:**
```json
{
  "appName": "baby_note",
  "accessToken": "네이버_액세스_토큰",
  "deviceSerial": "디바이스_시리얼_번호",
  "deviceInfo": { }
}
```

### 3. 구글 로그인 콜백

**Endpoint:** `POST /api/auth/google/callback`

**Request Body:**
```json
{
  "appName": "baby_note",
  "idToken": "구글_ID_토큰",
  "deviceSerial": "디바이스_시리얼_번호",
  "deviceInfo": { }
}
```

### 4. 애플 로그인 콜백

**Endpoint:** `POST /api/auth/apple/callback`

**Request Body:**
```json
{
  "appName": "baby_note",
  "identityToken": "애플_아이덴티티_토큰",
  "authorizationCode": "애플_인증_코드",
  "user": {
    "name": {
      "givenName": "길동",
      "familyName": "홍"
    },
    "email": "user@privaterelay.appleid.com"
  },
  "deviceSerial": "디바이스_시리얼_번호",
  "deviceInfo": { }
}
```

### 5. 사용자 정보 조회

**Endpoint:** `GET /api/auth/me`

**Headers:**
```
Authorization: Bearer JWT_토큰
```

**Response:**
```json
{
  "success": true,
  "data": {
    "user": {
      "id": "사용자_UUID",
      "socialId": "소셜_사용자_ID",
      "loginType": "kakao",
      "appName": "baby_note",
      "name": "홍길동",
      "email": "user@example.com",
      "profileImage": "프로필_이미지_URL",
      "lastLoginAt": "2025-10-13T10:00:00.000Z",
      "createdAt": "2025-10-01T09:00:00.000Z"
    }
  }
}
```

### 6. 로그아웃

**Endpoint:** `POST /api/auth/logout`

**Headers:**
```
Authorization: Bearer JWT_토큰
```

**Request Body:**
```json
{
  "sessionId": "세션_ID"
}
```

**Response:**
```json
{
  "success": true,
  "message": "Logged out successfully"
}
```

## 데이터베이스 스키마

### users 테이블

| 컬럼명 | 타입 | 설명 |
|--------|------|------|
| id | VARCHAR(36) | 사용자 UUID (Primary Key) |
| social_id | VARCHAR(255) | 소셜 플랫폼의 사용자 ID |
| login_type | ENUM | 'kakao', 'naver', 'google', 'apple' |
| app_name | VARCHAR(100) | 앱 이름 (예: 'baby_note') |
| name | VARCHAR(255) | 사용자 이름 |
| email | VARCHAR(255) | 이메일 |
| profile_image | TEXT | 프로필 이미지 URL |
| device_serial | VARCHAR(255) | 디바이스 시리얼 |
| last_login_at | TIMESTAMP | 마지막 로그인 시간 |
| created_at | TIMESTAMP | 생성 시간 |
| updated_at | TIMESTAMP | 업데이트 시간 |

**Unique Key:** (social_id, login_type, app_name)

### user_sessions 테이블

| 컬럼명 | 타입 | 설명 |
|--------|------|------|
| id | VARCHAR(36) | 세션 UUID (Primary Key) |
| user_id | VARCHAR(36) | 사용자 ID (Foreign Key) |
| app_name | VARCHAR(100) | 앱 이름 |
| access_token | TEXT | JWT 액세스 토큰 |
| refresh_token | TEXT | 리프레시 토큰 (선택사항) |
| device_serial | VARCHAR(255) | 디바이스 시리얼 |
| device_info | JSON | 디바이스 정보 |
| expires_at | TIMESTAMP | 만료 시간 |
| created_at | TIMESTAMP | 생성 시간 |
| updated_at | TIMESTAMP | 업데이트 시간 |

## Flutter 앱 연동

### 1. ApiService 설정

`lib/services/api_service.dart` 파일에서 백엔드 서버 URL을 설정하세요:

```dart
class ApiService {
  // 프로덕션 서버 URL
  static const String baseUrl = 'https://your-server.com:3000/api';

  // 로컬 테스트 (Android 에뮬레이터)
  // static const String baseUrl = 'http://10.0.2.2:3000/api';

  // 로컬 테스트 (iOS 시뮬레이터)
  // static const String baseUrl = 'http://localhost:3000/api';

  static const String appName = 'baby_note'; // 앱 이름 설정
}
```

### 2. 소셜 로그인 흐름

1. 사용자가 소셜 로그인 버튼 클릭
2. Flutter 앱에서 해당 소셜 플랫폼 SDK로 로그인 처리
3. 소셜 플랫폼에서 액세스 토큰 또는 ID 토큰 받기
4. `ApiService`를 통해 백엔드 서버에 토큰 전송
5. 백엔드에서 토큰 검증 및 사용자 정보 조회
6. 사용자 생성/업데이트 및 JWT 토큰 발급
7. Flutter 앱에서 JWT 토큰 및 사용자 정보 저장
8. 메인 화면으로 이동

## 보안 고려사항

### 1. JWT 시크릿 키
- 프로덕션 환경에서는 반드시 강력한 시크릿 키를 사용하세요
- 환경 변수로 관리하고 절대 코드에 하드코딩하지 마세요

### 2. HTTPS 사용
- 프로덕션 환경에서는 반드시 HTTPS를 사용하세요
- SSL 인증서를 설정하고 HTTP는 HTTPS로 리다이렉트하세요

### 3. CORS 설정
- 프로덕션 환경에서는 특정 도메인만 허용하도록 CORS를 설정하세요

```javascript
// server.js
const corsOptions = {
  origin: ['https://your-app-domain.com'],
  credentials: true
};
app.use(cors(corsOptions));
```

### 4. Rate Limiting
- API 엔드포인트에 Rate Limiting을 적용하여 악용을 방지하세요

```bash
npm install express-rate-limit
```

```javascript
const rateLimit = require('express-rate-limit');

const authLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15분
  max: 10 // 최대 10회
});

app.use('/api/auth', authLimiter, authRoutes);
```

## 다중 앱 지원

이 백엔드는 `appName` 파라미터를 통해 여러 앱을 지원합니다.

### 예시

**아기노트 앱:**
```json
{
  "appName": "baby_note",
  "accessToken": "..."
}
```

**다른 앱:**
```json
{
  "appName": "another_app",
  "accessToken": "..."
}
```

동일한 소셜 계정이더라도 `appName`이 다르면 별도의 사용자로 관리됩니다.

## 테스트

### 1. API 테스트 (Postman)

Postman을 사용하여 API를 테스트할 수 있습니다.

**카카오 로그인 테스트:**
```
POST http://localhost:3000/api/auth/kakao/callback
Content-Type: application/json

{
  "appName": "baby_note",
  "accessToken": "실제_카카오_액세스_토큰",
  "deviceSerial": "test-device-001",
  "deviceInfo": {
    "platform": "android",
    "model": "test"
  }
}
```

### 2. 사용자 정보 조회 테스트

```
GET http://localhost:3000/api/auth/me
Authorization: Bearer 받은_JWT_토큰
```

## 문제 해결

### 1. 데이터베이스 연결 오류

```
❌ Database initialization failed: Error: connect ECONNREFUSED
```

**해결 방법:**
- MySQL 서버가 실행 중인지 확인
- `.env` 파일의 데이터베이스 정보가 올바른지 확인

### 2. 카카오/네이버 API 오류

```
Kakao login error: Request failed with status code 401
```

**해결 방법:**
- 소셜 플랫폼에서 발급받은 액세스 토큰이 유효한지 확인
- 토큰이 만료되지 않았는지 확인

### 3. 구글 ID 토큰 검증 실패

```
Google login error: Token used too early
```

**해결 방법:**
- `.env` 파일의 `GOOGLE_CLIENT_ID`가 올바른지 확인
- 구글 클라우드 콘솔에서 OAuth 2.0 클라이언트 ID 설정 확인

## 추가 기능 구현 (선택사항)

### 1. 리프레시 토큰 구현
- 액세스 토큰 만료 시 리프레시 토큰으로 갱신
- `user_sessions` 테이블의 `refresh_token` 컬럼 활용

### 2. 소셜 계정 연결
- 한 사용자가 여러 소셜 계정 연결 가능하도록 구현
- `social_accounts` 테이블 추가

### 3. 사용자 프로필 업데이트
- 사용자 이름, 프로필 이미지 변경 API
- `PUT /api/auth/profile` 엔드포인트 추가

## 라이선스

이 프로젝트는 ISC 라이선스를 따릅니다.
