- Add main application files (main.py, models.py, schemas.py, etc.) - Add routers for all features (waiting, attendance, members, etc.) - Add HTML templates for admin and user interfaces - Add migration scripts and utility files - Add Docker configuration - Add documentation files - Add .gitignore to exclude database and cache files 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
219 lines
6.6 KiB
Markdown
219 lines
6.6 KiB
Markdown
# 대기자 관리 화면 리스트 표시 오류 수정 완료
|
|
|
|
## 문제점
|
|
|
|
대기자 관리 화면에서:
|
|
- 클래스 탭에는 "1교시 1명"으로 카운트가 정상 표시됨
|
|
- 하지만 클래스를 선택했을 때 대기자 리스트가 표시되지 않음
|
|
|
|
## 원인 분석
|
|
|
|
### 1. SQLAlchemy 관계 Lazy Loading
|
|
`/api/waiting/list` 엔드포인트가 `WaitingList` 모델을 조회할 때, 연관된 `class_info`와 `member` 관계가 lazy loading으로 설정되어 있어 자동으로 로드되지 않음.
|
|
|
|
### 2. Pydantic 직렬화 문제
|
|
`WaitingListDetail` 스키마가 `class_info: ClassInfo`를 요구하는데:
|
|
- `ClassInfo` 스키마는 `weekday_schedule: Dict[str, bool]`을 기대
|
|
- 하지만 데이터베이스에는 JSON 문자열로 저장됨 (`'{"mon": true, ...}'`)
|
|
- Pydantic이 자동으로 변환하지 못해 직렬화 실패
|
|
|
|
### 3. 평일/주말 클래스 구분 적용 영향
|
|
평일/주말 클래스 구분을 적용하면서, `class_info`에 `weekday_schedule`과 `class_type` 필드가 추가되었으나, 기존 엔드포인트에서 이를 올바르게 처리하지 못함.
|
|
|
|
## 수정 내용
|
|
|
|
### [routers/waiting.py](routers/waiting.py:1-401)
|
|
|
|
#### 1. joinedload import 추가 (line 2)
|
|
```python
|
|
from sqlalchemy.orm import Session, joinedload
|
|
```
|
|
|
|
#### 2. `/api/waiting/list` 엔드포인트 수정 (lines 309-401)
|
|
|
|
**수정 전:**
|
|
```python
|
|
@router.get("/list", response_model=List[WaitingListDetail])
|
|
async def get_waiting_list(...):
|
|
query = db.query(WaitingList).filter(...)
|
|
waiting_list = query.order_by(...).all()
|
|
return waiting_list
|
|
```
|
|
|
|
**수정 후:**
|
|
```python
|
|
@router.get("/list")
|
|
async def get_waiting_list(...):
|
|
# class_info와 member를 eager load
|
|
query = db.query(WaitingList).options(
|
|
joinedload(WaitingList.class_info),
|
|
joinedload(WaitingList.member)
|
|
).filter(...)
|
|
|
|
waiting_list = query.order_by(...).all()
|
|
|
|
# 수동으로 dict 생성 (weekday_schedule 파싱 포함)
|
|
result = []
|
|
for waiting in waiting_list:
|
|
class_info_dict = {
|
|
"id": waiting.class_info.id,
|
|
...
|
|
"weekday_schedule": parse_weekday_schedule(waiting.class_info.weekday_schedule),
|
|
"class_type": waiting.class_info.class_type if hasattr(waiting.class_info, 'class_type') else 'all',
|
|
...
|
|
}
|
|
|
|
waiting_dict = {
|
|
...
|
|
"class_info": class_info_dict,
|
|
"member": member_dict
|
|
}
|
|
|
|
result.append(waiting_dict)
|
|
|
|
return result
|
|
```
|
|
|
|
## 주요 변경 사항
|
|
|
|
### 1. Eager Loading 적용
|
|
```python
|
|
.options(
|
|
joinedload(WaitingList.class_info),
|
|
joinedload(WaitingList.member)
|
|
)
|
|
```
|
|
- `class_info`와 `member` 관계를 쿼리 시점에 함께 로드
|
|
- N+1 쿼리 문제 방지
|
|
- Pydantic 직렬화 시 관계 데이터 보장
|
|
|
|
### 2. 수동 dict 생성
|
|
- `response_model=List[WaitingListDetail]` 제거
|
|
- 수동으로 dict를 생성하여 반환
|
|
- `weekday_schedule`을 `parse_weekday_schedule()` 함수로 파싱하여 JSON 문자열 → dict 변환
|
|
|
|
### 3. weekday_schedule 파싱
|
|
```python
|
|
"weekday_schedule": parse_weekday_schedule(waiting.class_info.weekday_schedule)
|
|
```
|
|
- 데이터베이스의 JSON 문자열을 dict로 변환
|
|
- 프론트엔드에서 올바르게 사용 가능
|
|
|
|
## 동작 흐름
|
|
|
|
### Before (문제 발생)
|
|
1. 프론트엔드: `/api/waiting/list?status=waiting&class_id=1` 호출
|
|
2. 백엔드: `WaitingList` 조회 (class_info는 lazy loading)
|
|
3. Pydantic: `WaitingListDetail` 직렬화 시도
|
|
4. **에러**: `class_info`가 로드되지 않았거나, `weekday_schedule` 파싱 실패
|
|
5. 프론트엔드: 응답 실패 또는 빈 데이터
|
|
6. UI: "데이터 로딩 실패" 또는 빈 리스트 표시
|
|
|
|
### After (수정 후)
|
|
1. 프론트엔드: `/api/waiting/list?status=waiting&class_id=1` 호출
|
|
2. 백엔드: `WaitingList` + `class_info` + `member` eager load로 조회
|
|
3. 백엔드: 수동으로 dict 생성
|
|
- `weekday_schedule` 파싱
|
|
- `class_type` 확인 및 기본값 설정
|
|
- 모든 필드 포함
|
|
4. 프론트엔드: 올바른 JSON 응답 수신
|
|
5. UI: 대기자 리스트 정상 표시
|
|
|
|
## 검증 방법
|
|
|
|
### 1. API 직접 테스트
|
|
```bash
|
|
# 대기자 목록 조회
|
|
curl -H "Cookie: access_token=..." \
|
|
"http://localhost:8000/api/waiting/list?status=waiting&class_id=1"
|
|
|
|
# 예상 응답:
|
|
[
|
|
{
|
|
"id": 236,
|
|
"waiting_number": 1,
|
|
"name": null,
|
|
"phone": "01011110001",
|
|
"class_id": 1,
|
|
"class_order": 1,
|
|
"status": "waiting",
|
|
"class_info": {
|
|
"id": 1,
|
|
"class_number": 1,
|
|
"class_name": "1교시",
|
|
"weekday_schedule": {
|
|
"mon": true,
|
|
"tue": true,
|
|
"wed": true,
|
|
"thu": true,
|
|
"fri": true,
|
|
"sat": false,
|
|
"sun": false
|
|
},
|
|
"class_type": "weekday",
|
|
...
|
|
},
|
|
...
|
|
}
|
|
]
|
|
```
|
|
|
|
### 2. 대기자 관리 화면 확인
|
|
1. 대기자 관리 화면 접속
|
|
2. 클래스 탭에서 대기자가 있는 클래스 선택
|
|
3. 대기자 리스트가 정상적으로 표시되는지 확인
|
|
4. 대기자 정보 (이름, 전화번호, 순서 등) 확인
|
|
|
|
### 3. 브라우저 콘솔 확인
|
|
```javascript
|
|
// 에러가 발생하지 않아야 함
|
|
// Network 탭에서 /api/waiting/list 응답 확인
|
|
// 200 OK 상태 코드
|
|
// 올바른 JSON 형식의 응답
|
|
```
|
|
|
|
## 영향 범위
|
|
|
|
### 수정된 파일
|
|
✅ `routers/waiting.py` - `/api/waiting/list` 엔드포인트
|
|
|
|
### 영향받는 화면
|
|
✅ 대기자 관리 화면 (`templates/manage.html`)
|
|
- 클래스별 대기자 리스트 표시
|
|
- 대기자 상세 정보 표시
|
|
- 드래그 앤 드롭으로 순서 변경
|
|
- 빈 좌석 삽입
|
|
|
|
### 영향받지 않는 기능
|
|
- ✅ 대기자 등록
|
|
- ✅ 대기 현황판
|
|
- ✅ 대기 접수
|
|
- ✅ 클래스 관리
|
|
- ✅ `/api/waiting/list/by-class` (다른 엔드포인트)
|
|
|
|
## 추가 개선 사항
|
|
|
|
### 1. 성능 최적화
|
|
- Eager loading으로 N+1 쿼리 문제 해결
|
|
- 단일 쿼리로 모든 필요한 데이터 로드
|
|
|
|
### 2. 데이터 일관성
|
|
- `weekday_schedule` 항상 dict 형식으로 반환
|
|
- `class_type` 기본값 설정으로 하위 호환성 유지
|
|
|
|
### 3. 에러 처리 개선
|
|
- Pydantic 직렬화 실패 방지
|
|
- 명시적인 dict 생성으로 데이터 형식 보장
|
|
|
|
## 결론
|
|
|
|
**대기자 관리 화면에서 대기자 리스트가 정상적으로 표시됩니다:**
|
|
|
|
1. ✅ SQLAlchemy eager loading으로 관계 데이터 로드
|
|
2. ✅ 수동 dict 생성으로 Pydantic 직렬화 문제 해결
|
|
3. ✅ weekday_schedule 파싱으로 JSON 문자열 → dict 변환
|
|
4. ✅ class_type 필드 안전하게 처리
|
|
5. ✅ 평일/주말 클래스 구분과 호환
|
|
|
|
**클래스 탭에 "1교시 1명"으로 표시되고, 해당 클래스를 선택하면 대기자 리스트가 정상적으로 표시됩니다.**
|