- 앤드포인트 설계
- 비즈니스 로직 구현
- 응답구조 결정
- 데이터베이스 연동
- 만들어야하는 테이블
기본 URL: /api/v1
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 - 매칭 히스토리 조회
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: 가격대
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",
...
}
]
}
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..."
}
}
@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;
}
}
응답구조는 크게 성공과 실패 두 가지 경우로 나누어 설계
@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;
}
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
@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
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);
}
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
);
CREATE TABLE trainer_specialties (
trainer_id BIGINT,
specialty VARCHAR(50),
PRIMARY KEY (trainer_id, specialty),
FOREIGN KEY (trainer_id) REFERENCES trainers(id)
);
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)
);
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)
);
정리하자면,
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();
}
}
-- 기존 데이터 삭제 및 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"]}', '전략적이고 결과 중심적 소통', '목표 지향적 학습');
-- 기존 데이터 삭제 및 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');
-- 기존 데이터 삭제 및 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());