AI / OCR review / verification flow
BOUT — 영수증과 무상 AS 정보를 잃어버리지 않게 보관하는 앱
팀 프로젝트 | 2026.06 ~ 2026.08
BOUT는 전자·가전기기 영수증과 보증 정보를 한곳에 저장해, 나중에 수리·교환·환불이나 무상 AS 기간 확인이 필요할 때
바로 찾을 수 있게 돕는 앱입니다. 사용자는 영수증을 사진으로 올리고, 서비스는 구매일·제품명·가격·무상 AS 기간 후보를
OCR/AI로 추출합니다. 다만 인식 결과가 틀릴 수 있으므로, 제가 맡은 백엔드 흐름은 추출값을 바로 저장하지 않고
사용자가 확인한 값만 최종 기기/보증 기록으로 남기도록 나누는 데 초점을 뒀습니다.
담당 범위
OCR 후보값 흐름, 검수 후 저장 경계, 영수증/보증 데이터 구조, API 책임 분리를 정리했습니다.
판단
AI/OCR 결과는 사용자가 확인하기 전까지 최종 서비스 데이터가 아니라 임시 후보로 다뤄야 한다고 보았습니다.
검증
OCR 응답 예제와 API 테스트, 영수증 파일 참조 검증으로 추출 단계와 최종 저장 단계의 계약을 확인했습니다.
한계
서버는 사용자가 화면에서 검수를 끝냈는지 직접 증명하지 않습니다. 현재는 서로 다른 API 계약으로 책임을 분리했습니다.
Selected backend case
정상 형식이지만 틀린 OCR 결과를 최종 기록과 분리했습니다
AI가 만든 값은 JSON 형식이 맞아도 실제 영수증 내용과 다를 수 있습니다. 추출 성공을 저장 성공으로 취급하지 않고, 불확실성을 응답에 남긴 뒤 사용자가 확정한 값만 별도 저장 API가 받도록 경계를 나눴습니다.
1. 업로드영수증 이미지와 OCR 요청을 받습니다.
2. 추출구매일·금액·제품·분류 후보를 만듭니다.
3. 불확실성 표시needs_review, warnings, null로 추측을 숨기지 않습니다.
4. 사용자 검수사용자가 후보값을 확인하고 수정합니다.
5. 최종 저장검수된 필드와 receipt_file_ids만 기록으로 확정합니다.
- 위험한 상태
- 잘못 인식한 구매일·가격·제품명이 그럴듯한 정상 응답으로 들어와 최종 데이터처럼 저장되는 상태
- 설계 결정
- 분류 후보는 Pydantic
Literal로 제한하고 읽을 수 없는 선택 필드는 null로 반환했습니다. OCR 응답과 영수증 생성 요청은 서로 다른 스키마로 유지했습니다.
- 실제 코드
app/modules/ocr/infrastructure/receipt_ocr_client.py, app/modules/ocr/api/schemas.py, app/modules/receipts/api/schemas.py, app/modules/receipts/domain/value_objects.py
- 검증 근거
app/modules/ocr/tests/test_api.py에서 검수 필요 응답을 확인하고, app/modules/receipts/tests/test_api.py에서 파일 참조와 잘못된 저장 요청을 검증했습니다.
- 남은 한계
- UI 검수 완료 여부를 서버가 직접 인증하지는 않습니다. OCR 전용 필드가 최종 저장 요청에 섞이지 못하도록 API 계약을 분리해 위험 범위를 제한했습니다.
결론: AI 정확도를 과장하기보다, 틀릴 수 있는 출력을 서비스 데이터로 승격시키는 경계를 백엔드 계약으로 통제했습니다.