Add waiting system application files

- 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>
This commit is contained in:
2025-12-14 00:29:39 +09:00
parent dd1322625e
commit f699a29a85
120 changed files with 35602 additions and 0 deletions

View File

@@ -0,0 +1,218 @@
# 대기자 관리 화면 리스트 표시 오류 수정 완료
## 문제점
대기자 관리 화면에서:
- 클래스 탭에는 "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명"으로 표시되고, 해당 클래스를 선택하면 대기자 리스트가 정상적으로 표시됩니다.**