헬스 MBTI API 만들기

keymu·2025년 1월 7일
0
  1. 앤드포인트 설계
  2. 비즈니스 로직 구현
  3. 응답구조 결정
  4. 데이터베이스 연동
  5. 만들어야하는 테이블

1. 앤드포인트 설계

트레이너-회원 MBTI 매칭 시스템의 API 엔드포인트를 설계

기본 URL: /api/v1

MBTI 관련 엔드포인트

GET /mbti-traits             - 모든 MBTI 유형의 특성 조회
GET /mbti-traits/{type}      - 특정 MBTI 유형의 특성 조회 (예: /mbti-traits/ENFJ)

트레이너 관련 엔드포인트

GET    /trainers             - 트레이너 목록 조회
GET    /trainers/{id}        - 특정 트레이너 정보 조회
POST   /trainers             - 새로운 트레이너 등록
PUT    /trainers/{id}        - 트레이너 정보 수정
DELETE /trainers/{id}        - 트레이너 정보 삭제

매칭 관련 엔드포인트

POST   /matching             - MBTI 기반 트레이너 매칭 요청
GET    /matching/history     - 매칭 히스토리 조회

각 엔드포인트의 쿼리 파라미터와 요청/응답 예시를 설계

MBTI 특성 조회

GET /api/v1/mbti-traits
- 쿼리 파라미터:
  - category (선택): training, communication, motivation
  예시: /mbti-traits?category=training

GET /api/v1/mbti-traits/{type}
- 경로 변수: type (MBTI 유형)
- 쿼리 파라미터 없음

트레이너 목록 조회

GET /api/v1/trainers
- 쿼리 파라미터:
  - mbti: MBTI 유형으로 필터링
  - specialty: 전문분야 (weight, diet, rehab 등)
  - page: 페이지 번호 (기본값 0)
  - size: 페이지 크기 (기본값 10)
  - sort: 정렬 기준 (experience, rating)
  예시: /trainers?mbti=ENFJ&specialty=weight&page=0&size=10

매칭 요청

POST /api/v1/matching
- 요청 바디 파라미터:
  - userMbti: 사용자 MBTI
  - preferredStyle: 선호하는 트레이닝 스타일
  - goals: 운동 목표
  - location: 선호 지역
  - priceRange: 가격대

각 엔드포인트의 요청/응답 구조 자세한 설계

MBTI 특성 전체 조회

GET /api/v1/mbti-traits

응답 예시:
{
    "status": "success",
    "data": [
        {
            "type": "ENFJ",
            "training": {
                "preferredStyle": ["group", "motivation"],
                "learningMethod": "demonstration",
                "feedbackStyle": "positive-reinforcement"
            },
            "communication": {
                "style": "encouraging",
                "preferredFormat": "detailed-explanation"
            }
        },
        {
            "type": "INTJ",
            ...
        }
    ]
}

특정 MBTI 특성 조회

GET /api/v1/mbti-traits/ENFJ

응답 예시:
{
    "status": "success",
    "data": {
        "type": "ENFJ",
        "training": { ... },
        "communication": { ... }
    }
}

트레이너 목록 조회

GET /api/v1/trainers?mbti=ENFJ&specialty=weight&page=0&size=10

응답 예시:
{
    "status": "success",
    "data": {
        "trainers": [
            {
                "id": 1,
                "name": "김트레이너",
                "mbti": "ENFJ",
                "specialties": ["weight", "diet"],
                "experience": 5,
                "rating": 4.8,
                "priceRange": {
                    "min": 50000,
                    "max": 100000
                },
                "location": "강남구"
            }
        ],
        "pagination": {
            "currentPage": 0,
            "totalPages": 5,
            "totalElements": 48
        }
    }
}

매칭 요청

POST /api/v1/matching

요청 바디:
{
    "userMbti": "INTJ",
    "preferences": {
        "trainingStyle": ["individual", "data-driven"],
        "goals": ["muscle-gain", "strength"],
        "location": "강남구",
        "priceRange": {
            "min": 50000,
            "max": 150000
        }
    }
}
응답 예시:
{
    "status": "success",
    "data": {
        "matches": [
            {
                "trainerId": 1,
                "matchScore": 95,
                "matchReason": [
                    "MBTI 궁합도: 높음",
                    "선호 트레이닝 스타일 일치",
                    "위치 적합"
                ],
                "trainerInfo": {
                    "name": "김트레이너",
                    "specialties": ["weight", "diet"],
                    ...
                }
            }
        ]
    }
}
에러 응답 구조

{
    "status": "error",
    "error": {
        "code": "INVALID_MBTI",
        "message": "Invalid MBTI type provided",
        "details": "MBTI type must be one of: ENFJ, INFJ..."
    }
}

2. 비즈니스 로직 구현

MBTI 매칭 점수 계산 로직

@Service
public class MatchingService {
    public int calculateMatchScore(String userMbti, Trainer trainer) {
        int score = 0;
        
        // 1. MBTI 성향 매칭 (40점)
        score += calculateMbtiCompatibility(userMbti, trainer.getMbti());
        
        // 2. 트레이닝 스타일 매칭 (30점)
        score += calculateTrainingStyleMatch(userMbti, trainer.getTrainingStyle());
        
        // 3. 경험 점수 (20점)
        score += Math.min(trainer.getExperience() * 4, 20);
        
        // 4. 리뷰 평점 반영 (10점)
        score += (trainer.getRating() * 2);
        
        return score;
    }
}

3. 응답구조 결정

응답구조는 크게 성공과 실패 두 가지 경우로 나누어 설계

성공 응답 구조

@Getter
class MatchingResponse {
    private String status = "success";
    private MatchingData data;
}

@Getter
class MatchingData {
    private List<MatchResult> matches;  // 매칭 결과 리스트
    private int totalScore;             // 전체 매칭 점수
}

@Getter
class MatchResult {
    private Long trainerId;             // 트레이너 ID
    private String trainerName;         // 트레이너 이름
    private String mbti;                // 트레이너 MBTI
    private int matchScore;             // 매칭 점수
    private Map<String, Integer> scoreDetails; // 점수 상세 내역
    private TrainerInfo trainerInfo;    // 트레이너 상세 정보
}

실패 응답 구조

@Getter
class ErrorResponse {
    private String status = "error";
    private ErrorData error;
}

@Getter
class ErrorData {
    private String code;        // 에러 코드
    private String message;     // 에러 메시지
    private String details;     // 상세 설명
}

이렇게 응답구조를 일관되게 가져가면 프론트엔드에서 데이터를 처리하기가 훨씬 수월하다.

Lombok을 사용하면?


@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
class MatchingResponse {
    private String status = "success";
    private MatchingData data;
}

@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
class MatchingData {
    private List<MatchResult> matches;
    private int totalScore;
}

@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
class MatchResult {
    private Long trainerId;
    private String trainerName;
    private String mbti;
    private int matchScore;
    private Map<String, Integer> scoreDetails;
    private TrainerInfo trainerInfo;
}

@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
class ErrorResponse {
    private String status = "error";
    private ErrorData error;
}

@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
class ErrorData {
    private String code;
    private String message;
    private String details;
}

4. 데이터베이스 연동을 위한 Spring Boot + MySQL 설정

application.yml 설정

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mbti_matching?useSSL=false&serverTimezone=UTC
    username: root
    password: yourpassword
    driver-class-name: com.mysql.cj.jdbc.Driver
  
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true
    properties:
      hibernate:
        format_sql: true

Entity 클래스 생성

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name = "trainers")
public class Trainer {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String name;
    private String mbti;
    
    @ElementCollection
    private List<String> specialties;
    
    private int experience;
    private double rating;
    
    @Embedded
    private Address address;
}

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name = "matching_results")
public class MatchingResult {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @ManyToOne(fetch = FetchType.LAZY)
    private Trainer trainer;
    
    private String userMbti;
    private int matchScore;
    private LocalDateTime matchedAt;
}

Repository 인터페이스

@Repository
public interface TrainerRepository extends JpaRepository<Trainer, Long> {
    List<Trainer> findByMbti(String mbti);
    List<Trainer> findBySpecialtiesContaining(String specialty);
}

@Repository
public interface MatchingResultRepository extends JpaRepository<MatchingResult, Long> {
    List<MatchingResult> findByUserMbti(String userMbti);
}

5. 데이터베이스 테이블 설계

trainers (트레이너 정보)


CREATE TABLE trainers (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(50) NOT NULL,
    mbti VARCHAR(4) NOT NULL,
    experience INT NOT NULL,
    rating DECIMAL(2,1),
    introduction TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

trainer_specialties (트레이너 전문분야)

CREATE TABLE trainer_specialties (
    trainer_id BIGINT,
    specialty VARCHAR(50),
    PRIMARY KEY (trainer_id, specialty),
    FOREIGN KEY (trainer_id) REFERENCES trainers(id)
);

matching_results (매칭 결과)

CREATE TABLE matching_results (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    trainer_id BIGINT,
    user_mbti VARCHAR(4) NOT NULL,
    match_score INT NOT NULL,
    matched_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (trainer_id) REFERENCES trainers(id)
);

mbti_traits (MBTI 특성)

CREATE TABLE mbti_traits (
    mbti_type VARCHAR(4) PRIMARY KEY,
    preferred_training_style JSON,
    communication_style VARCHAR(100),
    learning_preference VARCHAR(100)
);
trainer_reviews (트레이너 리뷰)
sql
CREATE TABLE trainer_reviews (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    trainer_id BIGINT,
    rating INT NOT NULL,
    comment TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (trainer_id) REFERENCES trainers(id)
);

정리하자면,

Spring Boot로 API를 만들 때 전체적인 구조

Controller: API 엔드포인트를 정의하고 요청을 받는 곳
DTO: 요청/응답의 데이터 구조를 정의하는 클래스
Service: 비즈니스 로직이 실제로 구현되는 곳
Entity: 데이터베이스 테이블과 매핑되는 클래스
Repository: 데이터베이스 작업을 처리하는 인터페이스

// 1. Controller + DTO
@RestController
@RequestMapping("/api/v1")
public class MatchingController {
    @PostMapping("/matching")
    public ResponseEntity<MatchingResponseDTO> matchTrainer(@RequestBody MatchingRequestDTO request) {
        return ResponseEntity.ok(matchingService.findMatch(request));
    }
}

// 2. Service (비즈니스 로직)
@Service
public class MatchingService {
    public int calculateMatchScore(String userMbti, Trainer trainer) {
        int score = 0;
        score += calculateMbtiCompatibility(userMbti, trainer.getMbti());
        ...
    }
}

// 3. Entity
@Entity
@Table(name = "trainers")
public class Trainer {
    @Id
    private Long id;
    private String mbti;
    ...
}

// 4. Repository
@Repository
public interface TrainerRepository extends JpaRepository<Trainer, Long> {
    List<Trainer> findByMbti(String mbti);
}

우리가 만드는 API:

@RestController
public class TrainerController {
    @Autowired
    private TrainerRepository trainerRepository; // 데이터베이스 연결

    @GetMapping("/api/v1/trainers")
    public List<Trainer> getTrainers() {
        // MySQL 데이터베이스에서 트레이너 정보를 가져옴
        return trainerRepository.findAll();
    }
}
  • 외부 API를 사용할 때는 그 회사의 데이터베이스에서 데이터를 가져오는 것이고
    우리가 API를 만들 때는 우리가 직접 MySQL같은 데이터베이스를 만들고, 거기에 데이터를 넣어서 사용하는 것.
  • 그래서 아까 테이블 설계에서 만든 데이터베이스 테이블에 실제 트레이너 정보, MBTI 정보 등을 넣어야 API가 제대로 동작한다.

SQL INSERT 문을 사용해 데이터 넣기

MBTI 특성 데이터


-- 기존 데이터 삭제 및 AUTO_INCREMENT 초기화
DELETE FROM mbti_traits;
ALTER TABLE mbti_traits AUTO_INCREMENT = 1;

-- mbti_traits 데이터 삽입
INSERT INTO mbti_traits (mbti_type, preferred_training_style, communication_style, learning_preference)
VALUES 
('ISTJ', '{"styles": ["structured", "consistent", "traditional"], "focus": ["detail-oriented", "routine-based"]}', '명확하고 구체적인 지시', '단계별 체계적 학습'),
('ISFJ', '{"styles": ["supportive", "organized", "patient"], "focus": ["personal-care", "steady-progress"]}', '따뜻하고 개인적인 관심', '실제 경험 기반 학습'),
('INFJ', '{"styles": ["holistic", "personalized", "growth-focused"], "focus": ["long-term-vision", "meaningful-goals"]}', '통찰력 있는 조언', '개념적 이해와 실천'),
('INTJ', '{"styles": ["analytical", "efficient", "goal-oriented"], "focus": ["strategy", "optimization"]}', '논리적이고 직접적인 소통', '이론과 시스템 이해'),
('ISTP', '{"styles": ["practical", "adaptable", "hands-on"], "focus": ["technique", "immediate-results"]}', '간단명료한 설명', '실전 중심 학습'),
('ISFP', '{"styles": ["gentle", "flexible", "individual"], "focus": ["comfort", "enjoyment"]}', '부드럽고 개인적인 방식', '감각적 체험 학습'),
('INFP', '{"styles": ["authentic", "value-driven", "creative"], "focus": ["personal-meaning", "inner-motivation"]}', '공감적이고 영감을 주는 소통', '자기주도적 학습'),
('INTP', '{"styles": ["logical", "innovative", "knowledge-based"], "focus": ["understanding", "mastery"]}', '개념적이고 논리적인 설명', '원리 탐구 중심'),
('ESTP', '{"styles": ["dynamic", "energetic", "action-oriented"], "focus": ["challenge", "variety"]}', '즉각적이고 활동적인 소통', '행동 중심 학습'),
('ESFP', '{"styles": ["fun", "social", "encouraging"], "focus": ["enjoyment", "social-interaction"]}', '열정적이고 친근한 소통', '그룹 활동 학습'),
('ENFP', '{"styles": ["enthusiastic", "creative", "motivating"], "focus": ["inspiration", "possibilities"]}', '열정적이고 영감을 주는 소통', '창의적 접근 학습'),
('ENTP', '{"styles": ["challenging", "innovative", "strategic"], "focus": ["improvement", "experimentation"]}', '도전적이고 지적인 토론', '실험적 학습'),
('ESTJ', '{"styles": ["organized", "result-driven", "directive"], "focus": ["efficiency", "achievement"]}', '명확한 지시와 피드백', '구조화된 목표 중심'),
('ESFJ', '{"styles": ["supportive", "collaborative", "structured"], "focus": ["harmony", "encouragement"]}', '친근하고 상세한 안내', '협력적 학습'),
('ENFJ', '{"styles": ["inspiring", "people-focused", "growth-oriented"], "focus": ["development", "potential"]}', '동기부여와 격려', '관계 중심 학습'),
('ENTJ', '{"styles": ["strategic", "challenging", "leadership"], "focus": ["achievement", "excellence"]}', '전략적이고 결과 중심적 소통', '목표 지향적 학습');

트레이너 데이터 (30명)

-- 기존 데이터 삭제 및 AUTO_INCREMENT 초기화
DELETE FROM trainers;
ALTER TABLE trainers AUTO_INCREMENT = 1;

-- trainers 데이터 삽입
INSERT INTO trainers (name, mbti, experience, rating, introduction, created_at) 
VALUES 
('김지훈', 'ENFJ', 5, 4.8, '따뜻한 동기부여로 목표 달성을 돕는 트레이너입니다.', NOW()),
('이서연', 'INTJ', 7, 4.9, '과학적 접근으로 최적의 결과를 만듭니다.', NOW()),
('박민준', 'ISTP', 3, 4.7, '효율적인 동작과 자세 교정에 강점이 있습니다.', NOW()),
('정다은', 'ENFP', 4, 4.6, '즐거운 운동으로 건강한 습관을 만들어요!', NOW()),
('최준호', 'ISTJ', 8, 4.9, '체계적인 프로그램으로 확실한 변화를 약속합니다.', NOW()),
('한미래', 'ESFJ', 2, 4.5, '초보자도 편하게 시작할 수 있는 트레이닝을 제공합니다.', NOW()),
('송태현', 'ENTJ', 6, 4.8, '목표 달성을 위한 명확한 방향을 제시합니다.', NOW()),
('임수진', 'ISFP', 4, 4.7, '개인의 특성을 고려한 맞춤형 트레이닝을 진행합니다.', NOW()),
('강동원', 'ESTP', 5, 4.6, '다이나믹한 트레이닝으로 재미있게 운동해요!', NOW()),
('윤서아', 'INFJ', 3, 4.8, '건강한 마인드와 함께하는 전인적 트레이닝', NOW()),
('조현우', 'ESTJ', 9, 4.9, '목표 달성을 위한 체계적인 프로그램을 제공합니다.', NOW()),
('백지영', 'INTP', 4, 4.7, '과학적 원리 기반의 효과적인 트레이닝', NOW()),
('신준영', 'ESFP', 3, 4.5, '즐거운 분위기로 운동을 재미있게!', NOW()),
('오민지', 'ISFJ', 6, 4.8, '꾸준한 관리와 케어로 함께 성장해요', NOW()),
('권현석', 'ENTP', 5, 4.7, '창의적인 운동 방법으로 지루하지 않게!', NOW()),
('유하은', 'INFP', 2, 4.6, '개인의 페이스를 존중하는 맞춤 트레이닝', NOW()),
('장민재', 'ENFJ', 7, 4.9, '전문적인 지도와 따뜻한 응원을 함께 제공합니다.', NOW()),
('황세아', 'ISTJ', 4, 4.7, '기초부터 차근차근 탄탄하게 지도합니다.', NOW()),
('문지원', 'ESTP', 5, 4.8, '활기찬 트레이닝으로 운동이 즐거워집니다.', NOW()),
('양현직', 'INTJ', 8, 4.9, '데이터 기반의 과학적인 트레이닝을 제공합니다.', NOW()),
('구자민', 'ESFJ', 3, 4.6, '친근한 방식으로 편안한 트레이닝을 진행합니다.', NOW()),
('배수현', 'ENFP', 4, 4.7, '긍정적인 에너지로 즐거운 운동을 만듭니다.', NOW()),
('홍준표', 'ISTP', 6, 4.8, '정확한 자세와 효율적인 동작을 중점으로 지도합니다.', NOW()),
('서지안', 'ENTJ', 5, 4.7, '목표 달성을 위한 전략적인 트레이닝을 제공합니다.', NOW()),
('남궁원', 'ISFP', 3, 4.6, '개인의 특성을 고려한 맞춤형 프로그램을 진행합니다.', NOW()),
('도하윤', 'INFJ', 4, 4.8, '심신의 균형을 고려한 전인적 트레이닝을 제공합니다.', NOW()),
('설윤아', 'ESTJ', 7, 4.9, '체계적이고 효율적인 트레이닝으로 목표를 달성합니다.', NOW()),
('진현서', 'INTP', 5, 4.7, '과학적 접근으로 최적의 트레이닝을 설계합니다.', NOW()),
('추민혁', 'ESFP', 2, 4.5, '즐거운 분위기에서 효과적인 운동을 진행합니다.', NOW()),
('노지현', 'ISFJ', 6, 4.8, '세심한 관리와 꾸준한 피드백을 제공합니다.', NOW());
-- trainer_specialties 데이터 삽입
INSERT INTO trainer_specialties (trainer_id, specialty)
VALUES 
(1, 'weight-training'), (1, 'diet-management'),
(2, 'bodybuilding'), (2, 'posture-correction'),
(3, 'crossfit'), (3, 'functional-training'),
(4, 'diet-management'), (4, 'yoga'),
(5, 'weight-training'), (5, 'powerlifting'),
(6, 'pilates'), (6, 'rehabilitation'),
(7, 'bodybuilding'), (7, 'weight-training'),
(8, 'yoga'), (8, 'stretching'),
(9, 'crossfit'), (9, 'hiit'),
(10, 'meditation'), (10, 'holistic-training'),
(11, 'weight-training'), (11, 'sports-conditioning'),
(12, 'functional-training'), (12, 'mobility'),
(13, 'dance-fitness'), (13, 'cardio'),
(14, 'rehabilitation'), (14, 'senior-fitness'),
(15, 'calisthenics'), (15, 'parkour'),
(16, 'yoga'), (16, 'mindfulness'),
(17, 'weight-training'), (17, 'diet-management'),
(18, 'posture-correction'), (18, 'core-training'),
(19, 'crossfit'), (19, 'olympic-lifting'),
(20, 'bodybuilding'), (20, 'contest-prep'),
(21, 'pilates'), (21, 'pre-natal'),
(22, 'dance-fitness'), (22, 'zumba'),
(23, 'martial-arts'), (23, 'kickboxing'),
(24, 'sports-conditioning'), (24, 'athletic-training'),
(25, 'yoga'), (25, 'meditation'),
(26, 'holistic-training'), (26, 'wellness-coaching'),
(27, 'weight-training'), (27, 'powerlifting'),
(28, 'functional-training'), (28, 'mobility'),
(29, 'cardio'), (29, 'hiit'),
(30, 'rehabilitation'), (30, 'senior-fitness');

사용자(회원) 데이터 (50명)

-- 기존 데이터 삭제 및 AUTO_INCREMENT 초기화
DELETE FROM users;
ALTER TABLE users AUTO_INCREMENT = 1;

-- users 테이블 데이터 삽입
INSERT INTO users (username, mbti, age, gender, fitness_goal, preferred_training_style, experience_level, created_at) 
VALUES 
('user1', 'ENFJ', 25, 'F', 'weight-loss', '{"preferred": ["supportive", "structured"]}', 'beginner', NOW()),
('user2', 'INTJ', 30, 'M', 'muscle-gain', '{"preferred": ["analytical", "independent"]}', 'intermediate', NOW()),
('user3', 'ISFP', 28, 'F', 'flexibility', '{"preferred": ["gentle", "creative"]}', 'beginner', NOW()),
('user4', 'ENTP', 35, 'M', 'strength', '{"preferred": ["challenging", "varied"]}', 'advanced', NOW()),
('user5', 'ISFJ', 27, 'F', 'wellness', '{"preferred": ["consistent", "supportive"]}', 'beginner', NOW()),
('user6', 'ESTP', 32, 'M', 'athletic', '{"preferred": ["dynamic", "intense"]}', 'intermediate', NOW()),
('user7', 'INFP', 29, 'F', 'mindfulness', '{"preferred": ["gentle", "personal"]}', 'beginner', NOW()),
('user8', 'ESTJ', 31, 'M', 'weight-loss', '{"preferred": ["structured", "efficient"]}', 'intermediate', NOW()),
('user9', 'ENFP', 26, 'F', 'toning', '{"preferred": ["fun", "creative"]}', 'beginner', NOW()),
('user10', 'ISTP', 33, 'M', 'strength', '{"preferred": ["practical", "technical"]}', 'advanced', NOW()),
('user11', 'ENTJ', 28, 'F', 'muscle-gain', '{"preferred": ["challenging", "efficient"]}', 'intermediate', NOW()),
('user12', 'INFJ', 34, 'M', 'wellness', '{"preferred": ["holistic", "meaningful"]}', 'beginner', NOW()),
('user13', 'ESFP', 27, 'F', 'fitness', '{"preferred": ["fun", "social"]}', 'intermediate', NOW()),
('user14', 'ISTJ', 36, 'M', 'strength', '{"preferred": ["structured", "consistent"]}', 'advanced', NOW()),
('user15', 'ESFJ', 29, 'F', 'weight-loss', '{"preferred": ["supportive", "social"]}', 'beginner', NOW()),
('user16', 'INTP', 31, 'M', 'muscle-gain', '{"preferred": ["analytical", "independent"]}', 'intermediate', NOW()),
('user17', 'ENFJ', 28, 'F', 'flexibility', '{"preferred": ["encouraging", "structured"]}', 'beginner', NOW()),
('user18', 'ISTP', 33, 'M', 'strength', '{"preferred": ["practical", "efficient"]}', 'advanced', NOW()),
('user19', 'ENFP', 26, 'F', 'wellness', '{"preferred": ["fun", "creative"]}', 'beginner', NOW()),
('user20', 'INTJ', 35, 'M', 'muscle-gain', '{"preferred": ["analytical", "systematic"]}', 'intermediate', NOW()),
('user21', 'ISFP', 27, 'F', 'toning', '{"preferred": ["gentle", "personal"]}', 'beginner', NOW()),
('user22', 'ESTJ', 32, 'M', 'strength', '{"preferred": ["structured", "efficient"]}', 'advanced', NOW()),
('user23', 'INFP', 29, 'F', 'mindfulness', '{"preferred": ["gentle", "creative"]}', 'beginner', NOW()),
('user24', 'ENTP', 34, 'M', 'athletic', '{"preferred": ["challenging", "varied"]}', 'intermediate', NOW()),
('user25', 'ISFJ', 28, 'F', 'wellness', '{"preferred": ["supportive", "consistent"]}', 'beginner', NOW()),
('user26', 'ESTP', 31, 'M', 'strength', '{"preferred": ["dynamic", "challenging"]}', 'advanced', NOW()),
('user27', 'INFJ', 27, 'F', 'flexibility', '{"preferred": ["holistic", "meaningful"]}', 'beginner', NOW()),
('user28', 'ESFP', 33, 'M', 'fitness', '{"preferred": ["fun", "energetic"]}', 'intermediate', NOW()),
('user29', 'ISTJ', 30, 'F', 'weight-loss', '{"preferred": ["structured", "consistent"]}', 'beginner', NOW()),
('user30', 'ENTJ', 35, 'M', 'muscle-gain', '{"preferred": ["challenging", "efficient"]}', 'advanced', NOW()),
('user31', 'ESFJ', 28, 'F', 'wellness', '{"preferred": ["supportive", "social"]}', 'beginner', NOW()),
('user32', 'INTP', 32, 'M', 'strength', '{"preferred": ["analytical", "technical"]}', 'intermediate', NOW()),
('user33', 'ENFJ', 29, 'F', 'toning', '{"preferred": ["encouraging", "structured"]}', 'beginner', NOW()),
('user34', 'ISTP', 34, 'M', 'athletic', '{"preferred": ["practical", "technical"]}', 'advanced', NOW()),
('user35', 'ENFP', 27, 'F', 'flexibility', '{"preferred": ["fun", "creative"]}', 'beginner', NOW()),
('user36', 'INTJ', 33, 'M', 'muscle-gain', '{"preferred": ["analytical", "systematic"]}', 'intermediate', NOW()),
('user37', 'ISFP', 28, 'F', 'mindfulness', '{"preferred": ["gentle", "personal"]}', 'beginner', NOW()),
('user38', 'ESTJ', 31, 'M', 'strength', '{"preferred": ["structured", "efficient"]}', 'advanced', NOW()),
('user39', 'INFP', 26, 'F', 'wellness', '{"preferred": ["gentle", "creative"]}', 'beginner', NOW()),
('user40', 'ENTP', 35, 'M', 'athletic', '{"preferred": ["challenging", "varied"]}', 'intermediate', NOW()),
('user41', 'ISFJ', 29, 'F', 'weight-loss', '{"preferred": ["supportive", "consistent"]}', 'beginner', NOW()),
('user42', 'ESTP', 32, 'M', 'strength', '{"preferred": ["dynamic", "challenging"]}', 'advanced', NOW()),
('user43', 'INFJ', 28, 'F', 'flexibility', '{"preferred": ["holistic", "meaningful"]}', 'beginner', NOW()),
('user44', 'ESFP', 34, 'M', 'fitness', '{"preferred": ["fun", "energetic"]}', 'intermediate', NOW()),
('user45', 'ISTJ', 27, 'F', 'toning', '{"preferred": ["structured", "consistent"]}', 'beginner', NOW()),
('user46', 'ENTJ', 33, 'M', 'muscle-gain', '{"preferred": ["challenging", "efficient"]}', 'advanced', NOW()),
('user47', 'ESFJ', 30, 'F', 'wellness', '{"preferred": ["supportive", "social"]}', 'beginner', NOW()),
('user48', 'INTP', 35, 'M', 'strength', '{"preferred": ["analytical", "technical"]}', 'intermediate', NOW()),
('user49', 'ENFJ', 28, 'F', 'mindfulness', '{"preferred": ["encouraging", "structured"]}', 'beginner', NOW()),
('user50', 'ISTP', 32, 'M', 'athletic', '{"preferred": ["practical", "technical"]}', 'advanced', NOW());

매칭 결과와 리뷰 데이터

-- 기존 데이터 삭제 및 AUTO_INCREMENT 초기화
DELETE FROM matching_results;
ALTER TABLE matching_results AUTO_INCREMENT = 1;

DELETE FROM trainer_reviews;
ALTER TABLE trainer_reviews AUTO_INCREMENT = 1;

-- matching_results 데이터 삽입
INSERT INTO matching_results (trainer_id, user_mbti, match_score, matched_at)
VALUES 
-- ENFJ 유저들의 매칭
(2, 'ENFJ', 85, '2024-01-15'),
(7, 'ENFJ', 92, '2024-01-16'),
(15, 'ENFJ', 88, '2024-01-17'),
(20, 'ENFJ', 90, '2024-01-18'),

-- INTJ 유저들의 매칭
(5, 'INTJ', 95, '2024-01-19'),
(12, 'INTJ', 87, '2024-01-20'),
(18, 'INTJ', 89, '2024-01-21'),

-- ISFP 유저들의 매칭
(8, 'ISFP', 91, '2024-01-22'),
(16, 'ISFP', 86, '2024-01-23'),
(25, 'ISFP', 88, '2024-01-24'),

-- ENTP 유저들의 매칭
(3, 'ENTP', 93, '2024-02-01'),
(9, 'ENTP', 87, '2024-02-02'),
(22, 'ENTP', 85, '2024-02-03'),

-- 다른 MBTI 유형들의 매칭
(1, 'ISFJ', 89, '2024-02-04'),
(4, 'ESTP', 92, '2024-02-05'),
(6, 'INFP', 84, '2024-02-06'),
(10, 'ESTJ', 88, '2024-02-07'),
(11, 'ENFP', 90, '2024-02-08'),
(13, 'ISTP', 86, '2024-02-09'),
(14, 'ENTJ', 91, '2024-02-10');
-- trainer_reviews 데이터 삽입
INSERT INTO trainer_reviews (trainer_id, rating, comment, created_at)
VALUES 
(1, 5, '트레이너님의 꼼꼼한 지도 덕분에 운동이 많이 늘었어요!', '2024-01-20'),
(1, 4, '체계적인 프로그램으로 목표 달성에 도움이 되었습니다.', '2024-01-21'),
(2, 5, '과학적인 접근방식이 매우 인상적이었습니다.', '2024-01-22'),
(2, 5, '전문성이 돋보이는 트레이너님입니다.', '2024-01-23'),
(3, 4, '효율적인 운동 방법을 잘 알려주셨어요.', '2024-01-24'),
(4, 5, '즐겁게 운동할 수 있도록 도와주셔서 감사합니다.', '2024-01-25'),
(5, 5, '정확한 자세 교정으로 통증이 많이 개선되었어요.', '2024-01-26'),
(6, 4, '초보자도 쉽게 따라할 수 있게 설명해주셔서 좋았습니다.', '2024-01-27'),
(7, 5, '목표 달성을 위한 동기부여가 큰 도움이 되었어요.', '2024-01-28'),
(8, 4, '맞춤형 프로그램으로 꾸준한 관리가 가능했습니다.', '2024-01-29'),
(9, 5, '활기찬 에너지로 운동이 즐거웠어요!', '2024-01-30'),
(10, 5, '전인적인 관리로 건강이 많이 개선되었습니다.', '2024-02-01'),
(11, 4, '체계적인 프로그램이 마음에 들었어요.', '2024-02-02'),
(12, 5, '전문적인 지식을 바탕으로 한 트레이닝이 좋았습니다.', '2024-02-03'),
(13, 4, '즐거운 분위기에서 운동할 수 있었어요.', '2024-02-04'),
(14, 5, '꾸준한 관리와 피드백이 도움이 되었습니다.', '2024-02-05'),
(15, 4, '창의적인 운동 방법으로 지루하지 않았어요.', '2024-02-06');

사용자 선호도와 세션 기록 데이터

-- 기존 데이터 삭제 및 AUTO_INCREMENT 초기화
DELETE FROM user_preferences;
ALTER TABLE user_preferences AUTO_INCREMENT = 1;

DELETE FROM training_sessions;
ALTER TABLE training_sessions AUTO_INCREMENT = 1;

-- user_preferences 데이터 삽입
INSERT INTO user_preferences (user_id, preferred_time, preferred_intensity, health_conditions, goals, created_at)
VALUES 
(1, 'morning', 'moderate', '없음', '{"primary": "weight-loss", "secondary": "muscle-tone"}', NOW()),
(2, 'evening', 'high', '허리 통증', '{"primary": "strength", "secondary": "posture"}', NOW()),
(3, 'afternoon', 'low', '없음', '{"primary": "flexibility", "secondary": "stress-relief"}', NOW()),
(4, 'morning', 'high', '없음', '{"primary": "muscle-gain", "secondary": "strength"}', NOW()),
(5, 'evening', 'moderate', '어깨 통증', '{"primary": "rehabilitation", "secondary": "flexibility"}', NOW());
-- training_sessions 데이터 삽입
INSERT INTO training_sessions (user_id, trainer_id, session_date, duration, session_type, notes, status)
VALUES 
-- 사용자 1의 세션
(1, 3, '2024-01-15', 60, 'personal', '체중 감량 프로그램 시작', 'completed'),
(1, 3, '2024-01-17', 60, 'personal', '유산소 운동 강화', 'completed'),
(1, 3, '2024-01-19', 60, 'personal', '근력 운동 도입', 'completed'),

-- 사용자 2의 세션
(2, 5, '2024-01-16', 90, 'personal', '웨이트 트레이닝 기초', 'completed'),
(2, 5, '2024-01-18', 90, 'personal', '자세 교정 중점', 'completed'),
(2, 5, '2024-01-20', 90, 'personal', '강도 상승', 'cancelled'),

-- 사용자 3의 세션
(3, 8, '2024-01-15', 60, 'personal', '스트레칭 위주 프로그램', 'completed'),
(3, 8, '2024-01-18', 60, 'personal', '코어 강화 운동 추가', 'completed'),
(3, 8, '2024-01-21', 60, 'personal', '유연성 향상 확인', 'scheduled'),

-- 사용자 4의 세션
(4, 2, '2024-01-17', 90, 'personal', '근비대 프로그램 시작', 'completed'),
(4, 2, '2024-01-19', 90, 'personal', '식단 조절 병행', 'completed'),
(4, 2, '2024-01-21', 90, 'personal', '1RM 측정', 'scheduled'),

-- 사용자 5의 세션
(5, 6, '2024-01-16', 60, 'rehabilitation', '어깨 재활 운동', 'completed'),
(5, 6, '2024-01-18', 60, 'rehabilitation', '가동범위 확인', 'completed'),
(5, 6, '2024-01-20', 60, 'rehabilitation', '단계별 부하 증가', 'scheduled');
-- matching_statistics 데이터 삽입
INSERT INTO matching_statistics (trainer_id, total_matches, successful_matches, avg_rating, updated_at)
VALUES 
(1, 45, 40, 4.8, NOW()),
(2, 38, 35, 4.9, NOW()),
(3, 42, 38, 4.7, NOW()),
(4, 30, 27, 4.6, NOW()),
(5, 50, 45, 4.9, NOW()),
(6, 25, 22, 4.5, NOW()),
(7, 35, 32, 4.8, NOW()),
(8, 28, 25, 4.7, NOW()),
(9, 33, 30, 4.6, NOW()),
(10, 40, 36, 4.8, NOW());
profile
Junior Backend Developer

0개의 댓글