목록 · /engineering:debug · Claude Code · Opus 5.5 · 생각 깊이 중간 · 마지막 답 원문

디버그 리포트: 주문 내역 1쪽에 최근 주문이 안 보임

list_orders의 페이지 계산이 한 쪽씩 밀려 있었고, 정렬 기준도 없었습니다. 둘 다 고쳤고, 고친 뒤 다시 돌려서 확인했습니다.

재현

주문 25개짜리 테스트 DB를 scratchpad에 따로 만들어 list_orders(user_id, page)를 호출했습니다. 실제 shop.db는 건드리지 않았습니다.

1쪽 2쪽
기대 최신 주문 20개 (25→6) 나머지 5개 (5→1)
수정 전 [21, 22, 23, 24, 25] (5개만) []
수정 후 [25, 24, … , 6] (20개) [5, 4, 3, 2, 1]

수정 전에는 1~20번 주문이 어느 쪽에서도 보이지 않았습니다.

원인

shop.py:25 list_orders에 문제가 두 개 있었습니다.

  1. 페이지 번호 계산이 하나 밀림. 쪽 번호는 1부터 받는데, 계산은 0부터 시작하는 것처럼 offset = page * PAGE_SIZE로 하고 있었습니다. 그래서 1쪽을 열면 앞의 20개를 건너뛰고 21번째부터 보여 줬습니다. 주문이 25개면 1쪽에 5개만 나오고 2쪽은 비고, 처음 20개는 볼 방법이 없었습니다.
  2. ORDER BY가 없음. 정렬 기준이 없으면 SQLite가 행을 돌려주는 순서는 보장되지 않습니다. 인덱스나 VACUUM 상태에 따라 바뀝니다. 그래서 "1쪽 = 최근 주문"이라는 전제 자체가 성립하지 않았습니다. 테스트 DB에서는 우연히 최신 5개가 1쪽에 나왔지만, 실제 DB에서는 오래된 주문 5개가 나와도 이상하지 않습니다. 손님이 말한 "최근 주문이 하나도 안 보인다"는 이 두 문제가 겹쳐서 생긴 것으로 봅니다.

수정 내용 (shop.py)

if page < 1:
    raise ValueError("page는 1부터 시작")
offset = (page - 1) * PAGE_SIZE
orders = db.execute(
    "SELECT id, created_at FROM orders WHERE user_id = ?"
    " ORDER BY created_at DESC, id DESC LIMIT ? OFFSET ?",
    ...

확인할 점: 지금까지 화면에서 page=0을 첫 쪽으로 넘기고 있었다면, 이제는 오류가 납니다. 호출하는 쪽이 1부터 넘기는지 확인해 주세요.

재발 방지

이번 범위 밖이지만 같은 파일에서 본 문제

요청 범위가 아니라서 손대지 않았습니다. 원하면 이어서 고치겠습니다. - SQL 인젝션: search_products가 f-string으로 SQL을 만듭니다. - 남의 주문 조회: get_order가 current_user_id를 받기만 하고 검사하지 않아서, 다른 손님의 주문도 조회됩니다. - 경로 조작: download_invoice에서 ../가 들어간 파일명으로 다른 디렉터리의 파일을 읽을 수 있습니다. - 비밀값 노출: ADMIN_TOKEN이 코드에 그대로 박혀 있습니다. 비교도 일반 ==라서 타이밍 공격에 취약합니다. - 주문 처리 예외: place_order는 없는 상품이면 None에서 터지고, 동시에 주문이 들어오면 재고가 꼬일 수 있습니다. - 쿠폰 오류 숨김: apply_coupon이 오류가 나면 조용히 None을 돌려줍니다. - N+1 쿼리: list_orders가 주문마다 상품 목록을 따로 조회합니다.