개요
테이블 오더 시스템에서는 메뉴나 옵션 가격이 바뀌었을 때 과거 주문 데이터까지 변해버리는 문제가 발생할 수 있습니다.
이 글에서는 주문 시점에 가격을 저장하여 과거 거래 데이터를 안전하게 보존하고, 데이터 신뢰성을 유지하는 방법을 소개합니다.
문제 상황: 가격 변경으로 생기는 혼란
"사장님, 저번에 이거 7,000원이었는데 오늘은 왜 7,500원이죠?"
POS 시스템을 열어보니 메뉴 가격이 정말 변경되어 있던 경험, 한 번쯤 있으시죠?
이런 문제는 대부분 메뉴 및 옵션 가격을 주문 시점에 실시간 조회하는 구조 때문에 발생합니다.
실시간 가격 조회의 한계
테이블 오더 시스템을 처음 설계할 때는, 주문 시 DB에서 메뉴와 옵션 가격을 실시간으로 조회하는 방식을 쉽게 떠올릴 수 있습니다.
하지만 이 구조에는 치명적인 문제가 숨어 있습니다.
- 메뉴나 옵션 가격이 변경되면,
- 과거 주문 기록까지 새 가격으로 덮어쓰기 됩니다.
이로 인해:
- 과거 주문 금액을 정확히 확인할 수 없고,
- 환불 및 클레임 처리도 힘들어지며,
- 시스템 전체에 대한 신뢰가 떨어집니다.
거래 기록은 변해서는 안 됩니다.
이 원칙이 무너지면, 고객 불신은 물론이고 법적 문제까지 이어질 수 있습니다.
해결 방법: 주문 시점 가격 저장하기
답은 간단합니다. 주문 생성 시 가격을 저장하면 됩니다.
구체적으로는 다음 정보를 별도로 기록해야 합니다.
- 메뉴 가격 (
price
) - 옵션 가격 (
option_price
)
이렇게 하면, 이후 메뉴나 옵션 가격이 아무리 변경되어도 과거 주문 내역은 변하지 않습니다.
PostgreSQL 테이블 설계 예시
주문 시 가격 저장을 위해 테이블을 이렇게 구성할 수 있습니다.
주문 아이템 테이블 (order_items
)
컬럼명 | 타입 | 설명 |
---|---|---|
id | SERIAL | 기본 키 |
order_id | INTEGER | 주문 ID |
menu_id | VARCHAR | 메뉴 ID |
quantity | INTEGER | 수량 |
price | NUMERIC(10,2) | 주문 당시 메뉴 가격 |
주문 아이템 옵션 테이블 (order_item_options
)
컬럼명 | 타입 | 설명 |
---|---|---|
id | SERIAL | 기본 키 |
order_item_id | INTEGER | 주문 아이템 ID |
option_id | VARCHAR | 옵션 ID |
option_price | NUMERIC(10,2) | 주문 당시 옵션 가격 |
💬 팁: 금액 데이터는
NUMERIC(10,2)
타입을 사용해야 부동소수점 오차 없이 안전하게 다룰 수 있습니다.
주문 총액 계산 쿼리 작성하기
가격을 저장했다면, 주문별 총액은 이렇게 간단히 계산할 수 있습니다.
SELECT
SUM(oi.price * oi.quantity) + COALESCE(SUM(oio.option_price), 0) AS total_price
FROM order_items oi
LEFT JOIN order_item_options oio ON oi.id = oio.order_item_id
WHERE oi.order_id = 101;
COALESCE
를 사용해 옵션이 없는 경우에도 0으로 처리합니다.- 상황에 따라
GROUP BY
를 추가할 수 있습니다.
PostgreSQL 버전에 따라 JOIN 및 SUM 연산 최적화 방식은 다를 수 있습니다.
기대할 수 있는 효과
- 과거 주문 내역이 가격 변경에 영향을 받지 않습니다.
- 환불, 증빙, 고객 문의 대응이 쉬워집니다.
- 메뉴 가격이 바뀌어도 시스템이 문제없이 작동합니다.
개발 시 유의사항
- 주문 생성 시 가격을 반드시 저장해야 합니다.
- 총 금액 계산은 저장된 가격을 기준으로 해야 합니다.
- 프론트엔드와 백엔드 모두 이 원칙을 이해하고 일관성 있게 구현해야 합니다.
거래 데이터는 시간이 지나도 변하지 않아야 합니다.
변하는 데이터는 신뢰를 잃습니다.