DevLog

병원 예약 시스템 Part 3 - 데이터베이스 리팩토링과 API 연동

기마니 2025. 12. 15. 14:50

예약 기능을 완성하고 테스트까지 성공했는데 데이터베이스 구조가 너무 비효율적이라 생각해서 수정을 하기로 결심했다.

기존 DOCTOR_SCHEDULE 테이블에는 의사 1명당 5개의 근무 데이터가 필요했다. 하지만 모든 의사의 진료 시간은 평일 9-6, 주말 9-2로 고정되기 때문에 굳이 시간을 DB에 저장할 필요가 없었다.

그래서 DOCTOR_SCHEDULE 테이블을 제거하고 병원 운영 시간은 application.yml 설정 파일로 관리하고 의사 휴무일은 DOCTOR 테이블에 day_off 컬럼을 추가하는 방식으로 변경했다.

이렇게 하면 의사 1명당 데이터가 1개로 줄어들고 휴무일이 변경 시 dayOff 컬럼만 업데이트하면 돼서 유지보수성도 좋아진다. 결과적으로 중복 데이터는 사라지고 운영 시간 관리는 더 유연해졌다.

 

[리팩토링 과정]

1. DOCTOR_SCHEDULE 테이블 제거

 

2. Doctor 엔티티 수정 - day_off 컬럼 추가

@Entity
@Getter @Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Doctor extends BaseEntity{ // BaseEntity 상속(created_at 필드 자동 상속)

	...

    // 개인 휴무일
    @Column(name = "day_off", length = 10)
    private String dayOff;

    // dayOff 추가
    public static Doctor createDoctor(String name, Department department, String dayOff) {
        Doctor doctor = new Doctor();
        doctor.setName(name);
        doctor.setDepartment(department);
        doctor.setDayOff(dayOff);
        return doctor;
    }

}

 

이제 의사는 근무 시간이 아닌 쉬는 날 정보만 가진다.

 

 

3. resources/application.yml 설정 - 병원 운영 시간 추가

hospital:
  schedule:
    weekday:
      start-time: "09:00"
      end-time: "18:00"
    saturday:
      start-time: "09:00"
      end-time: "14:00"
    lunch:
      start-time: "13:00"
      end-time: "14:00"

 

운영 시간은 설정 파일로 분리하여 관리한다.

 

 

4. HospitalProperties 클래스 - 설정값을 Java 객체로 변환

@Getter @Setter
@Component
@ConfigurationProperties(prefix = "hospital.schedule")
public class HospitalProperties {

    private TimeSlot weekday;
    private TimeSlot saturday;
    private TimeSlot lunch;

    // 내부 클래스: 시작,종료 시간-
    @Getter @Setter
    public  static class TimeSlot {
        private String startTime; // yml의 start-time과 자동 매핑
        private String endTime;
    }
}

 

@ConfigurationProperties(prefix = "hospital.schedule"): yml의 hospital.schedule 하위 값들을 자동으로 매핑

 

 

5. DoctorScheduleRepository 삭제 - DoctorService 생성

DOCTOR_SCHEDULE 테이블이 사라졌으므로 이를 조회하던 Repository도 삭제했다.

기존에는 DoctorScheduleRepository를 조회해서 모든 정보를 DB에서 가져왔는데 이제는 2단계 검증 로직으로 변경했다.
1단계: 병원 운영 시간 확인 (.yml)

2단계: 의사 휴무일 확인 (DB)

이렇게 설정과 데이터를 분리하여 효율성을 높였다.

 

 

6. Controller 구현 - 변경된 로직 연결

서비스 계층에서 '계산된 예약 가능 시간'을 반환 로직(getAvailableSlots)을 완성했고 이를 프론트엔드에서 호출할 수 있도록 API를 연결했다. 기존에는 DB를 바로 조회했는데 이제는 Service를 통해 계산된 결과를 반환한다.

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1")
public class DepartmentController {
    
    private final DoctorService doctorService;

	...
    
    @GetMapping("/doctors/{doctorId}/availability")
    public List<LocalTime> getDoctorAvailability(
            @PathVariable("doctorId") Long doctorId,
            @RequestParam("date") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date) {
        
        // DoctorService의 getAvailableSlots 메서드 호출 (예약 가능 시간 계산)
        return doctorService.getAvailableSlots(doctorId, date);
    }
}

 

 

7. Frontend(TypeScript) 동기화

interface Doctor {
  id: number;
  name: string;
  dayOff: string; // 백엔드 엔티티 변경 사항 반영
  department: {
    id: number;
    deptName: string;
  };
}

 

마지막으로 백엔드의 바뀐 데이터 구조대로 프론트엔드의 타입 정의도 맞춰야 한다. DOCTOR 엔티티에 day_off 필드가 생겼으므로  TypeScript Interface에도 이를 추가했다. 이렇게 타입을 맞춰두면 백엔드 변경 사항을 놓치지 않고 안전하게 개발할 수 있다.

 


 

이번 리팩토링을 통해 데이터 중복을 없애고 운영 시간을 유연하게 관리하며, API 계층까지 깔끔하게 연결했다. 처음엔 '그냥 테이블 하나 지우는 건데?' 라고 가볍게 생각했지만 그 과정에서 객체지향적인 책임 분리와 유지보수성에 대해 깊게 고민해볼 수 있었다.