할인쿠폰 회원카드 (app in toss 미니앱) 앱 개발 기획서
프로젝트: billcorea-membership
플랫폼: Apps in Toss WebView 미니앱
1. 프로젝트 개요
Billcorea Membership 앱은 멤버십 카드와 영수증을 한 화면에서 관리하는 Apps in Toss 미니앱이다. 사용자는 카메라 또는 앨범에서 이미지를 가져오고, OCR 분석을 통해 멤버십 카드 정보와 영수증 정보를 자동으로 추출한다. 추출된 정보는 사용자가 확인하고 수정한 뒤 저장할 수 있으며, 저장된 데이터는 로컬 지갑처럼 다시 조회할 수 있다.
이 앱은 단순한 카드 보관 앱보다 한 단계 더 나아가 영수증 관리, 월별 소비 달력, 근무지 기반 출퇴근 기록, Toss 배너 광고 연동까지 포함한다. 블로그 관점에서는 "OCR 기반 생활 데이터 지갑을 Apps in Toss 안에서 빠르게 구현한 사례"로 소개할 수 있다.
2. 개발 배경
멤버십 카드와 영수증은 일상적으로 자주 발생하지만 따로 관리하기 번거로운 데이터다. 사용자는 매장 방문 시 멤버십 번호를 찾고, 구매 후에는 영수증을 보관하거나 소비 내역을 다시 확인해야 한다. 이 앱은 이러한 반복 행동을 줄이기 위해 다음 문제를 해결하는 것을 목표로 했다.
- 멤버십 카드 정보를 직접 입력하지 않고 이미지에서 추출한다.
- 영수증의 상호명, 구매일, 결제금액, 품목을 OCR로 구조화한다.
- 월별 소비 금액을 달력에서 빠르게 확인한다.
- 저장된 멤버십 카드별 상세 정보와 자동 출퇴근 기록을 제공한다.
- Toss 미니앱 환경에 맞는 뒤로가기, 권한, 광고, UI 패턴을 적용한다.
3. 핵심 사용자 시나리오
3.1 멤버십 카드 등록
- 메인 화면에서 멤버십 촬영 버튼을 누른다.
- 카메라로 촬영하거나 앨범에서 이미지를 가져온다.
- 이미지 확인 후 OCR 분석을 실행한다.
- 브랜드명, 바코드 번호, 바코드 타입, 테마 색상을 확인하고 수정한다.
- 저장하면 메인 화면의 멤버십 카드 목록에 추가된다.
3.2 영수증 등록
- 최근 영수증 영역에서 영수증 촬영 버튼을 누른다.
- 영수증 이미지를 선택하거나 촬영한다.
- Groq OCR이 상호명, 구매일, 결제금액, 상태, 품목 목록을 추출한다.
- OCR 확인 화면에서 잘못 인식된 값을 수정한다.
- 저장하면 최근 영수증 목록과 달력 통계에 반영된다.
3.3 영수증 달력 확인
- 최근 영수증 타이틀 오른쪽의 달력 버튼을 누른다.
- 월별 총 결제금액을 확인한다.
- 날짜별 결제 합계를 달력 셀에서 확인한다.
- 금액이 길어 셀 안에서 줄바꿈되는 문제를 가로 흐름 애니메이션으로 처리했다.
- 달력 하단에는 Toss 배너 광고 영역을 배치했다.
3.4 앱 종료 처리
- 메인 화면에서 상단 뒤로가기 버튼을 누른다.
- 하드웨어 뒤로가기 버튼을 눌러도 동일한 종료 확인창이 뜬다.
- 사용자가 종료를 선택하면
closeView()로 미니앱 화면을 닫는다.
4. 주요 화면 구성
4.1 메인 화면
메인 화면은 멤버십 카드 목록과 최근 영수증 목록을 함께 보여준다. 상단에는 앱 제목, 뒤로가기 버튼, 설정 버튼을 배치했다. 최근 영수증 타이틀 위에는 Toss 배너 광고 영역을 추가했다.
주요 기능:
- 멤버십 카드 목록 표시
- 멤버십 카드 촬영 진입
- 최근 영수증 목록 표시
- 영수증 촬영 진입
- 영수증 달력 진입
- Toss 배너 광고 표시
4.2 카메라/앨범 이미지 선택 화면
카메라 패널은 OCR 분석 전에 이미지를 확보하는 화면이다. 카메라 촬영, 앨범 불러오기, 저장 이미지 삭제, 선택 이미지 확정 버튼을 제공한다. 모든 주요 액션은 아이콘 버튼으로 구성해 모바일 환경에서 빠르게 조작할 수 있도록 했다.
4.3 OCR 확인 화면
OCR 결과를 바로 저장하지 않고, 사용자가 확인하고 수정할 수 있는 중간 검수 화면을 둔다. OCR은 편리하지만 항상 정확하지 않기 때문에, 저장 전에 수정 가능한 폼을 제공하는 것이 핵심 UX다.
멤버십 카드 OCR 필드:
- 브랜드명
- 바코드 번호
- 바코드 타입
- 테마 색상
- 로고 URL
영수증 OCR 필드:
- 상호명
- 구매일
- 총 결제금액
- 통화
- 결제 상태
- 품목명, 수량, 금액
4.4 멤버십 상세 화면
멤버십 카드를 선택하면 상세 화면으로 이동한다. 카드별 근무지 설정, 출퇴근 기록, 자동 근무지 체크 기능을 제공한다. 근무지 반경을 설정하고 자동 추적을 켜면 위치 변화에 따라 근무 종료 기록을 자동으로 남길 수 있다.
4.5 영수증 상세 바텀시트
영수증 목록에서 항목을 누르면 바텀시트로 상세 내역이 열린다. 제목줄 오른쪽에는 영수증 등록일자를 표시한다. 품목별 금액과 총 결제금액을 분리해 영수증 정보를 빠르게 확인할 수 있도록 구성했다.
4.6 영수증 달력 화면
영수증 달력은 월별 소비 현황을 시각적으로 확인하는 화면이다. 완료 상태의 영수증만 월별 합산에 포함한다. 각 날짜 셀에는 해당 날짜의 결제 합계가 표시된다.
UX 개선 사항:
- 월 이동 버튼 제공
- 오늘 날짜 강조
- 일요일/토요일 색상 구분
- 긴 금액은 줄바꿈 대신 흐르는 텍스트로 표시
- 달력 하단 Toss 배너 광고 영역 추가
5. 기능 명세
| 구분 | 기능 | 설명 |
|---|---|---|
| OCR | 멤버십 카드 분석 | 이미지에서 브랜드명, 바코드 번호, 바코드 타입 추출 |
| OCR | 영수증 분석 | 상호명, 구매일, 결제금액, 품목 목록 추출 |
| 저장 | 로컬 상태 저장 | 앱 상태를 localStorage에 저장 |
| 카메라 | 촬영 | Apps in Toss 카메라 API 사용 |
| 앨범 | 이미지 선택 | 앨범 이미지 base64 로딩 |
| 위치 | 근무지 추적 | 위치 권한을 확인하고 근무지 반경 이탈 시 기록 |
| 내비게이션 | 뒤로가기 제어 | 메인 화면에서 종료 확인창 표시 |
| 광고 | Toss 배너 광고 | VITE_TOSS_AD_BANNER_GROUP_ID 기반 배너 표시 |
| 달력 | 월별 합계 | 완료된 영수증 금액을 날짜별로 합산 |
6. 데이터 모델
6.1 MemberCard
멤버십 카드는 브랜드명, 바코드 번호, 바코드 타입, 색상 테마, 등록일을 기본으로 가진다. 추가로 근무지 기능을 위해 사무실 좌표, 주소, 반경, 자동 출퇴근 설정, 출퇴근 로그를 포함한다.
interface MemberCard {
id: string;
brandName: string;
barcodeNumber: string;
barcodeType: "CODE128" | "QR" | "EAN13";
colorTheme: string;
logoUrl?: string;
createdAt: number;
officeLatitude?: number;
officeLongitude?: number;
officeAddress?: string;
officeRadius?: number;
autoCommuteEnabled?: boolean;
commuteLogs?: CommuteLog[];
}6.2 Receipt
영수증은 상호명, 구매일, 총 결제금액, 결제 상태, 품목 목록, 등록일, 이미지 URL을 가진다. 등록일은 상세 바텀시트 제목줄 오른쪽에 표시된다.
interface Receipt {
id: string;
storeName: string;
purchaseDate: number;
totalAmount: number;
currency: string;
status: "COMPLETED" | "REFUNDED" | "CANCELLED";
items: ReceiptItem[];
createdAt?: number;
imageUrl?: string;
memo?: string;
}7. 기술 구조
7.1 화면 상태 관리
앱은 별도 라우터 대신 ScreenState 유니언 타입으로 화면을 전환한다.
membership: 메인settings: 설정receiptCalendar: 영수증 달력camera: 이미지 선택processing: OCR 분석 중review: OCR 결과 확인error: OCR 실패detail: 멤버십 상세
이 방식은 화면 수가 많지 않은 미니앱에서 구현 비용이 낮고, 뒤로가기 정책을 한 곳에서 제어하기 쉽다.
7.2 상태 저장
WalletProvider가 멤버십 카드와 영수증 목록을 관리한다. 상태는 localStorage에 직렬화해 저장하므로 앱을 닫았다가 다시 열어도 데이터가 유지된다.
7.3 OCR 처리
OCR은 Groq Chat Completions API에 이미지 base64를 전달해 수행한다. 프롬프트는 멤버십 카드와 영수증을 구분해 구성했다. 응답은 JSON object 형식으로 강제하고, 앱 내부에서 다시 정규화한다.
처리 흐름:
- 이미지 base64 생성
- OCR 프롬프트 구성
- Groq API 호출
- JSON 파싱
- 앱 데이터 모델에 맞게 정규화
- OCR 확인 화면에서 사용자 수정
- 저장
7.4 Toss Web Framework 연동
앱은 Apps in Toss Web Framework를 사용한다. 주요 연동 포인트는 다음과 같다.
openCamera: 카메라/앨범 관련 이미지 처리startUpdateLocation: 위치 추적closeView: 미니앱 종료graniteEvent.addEventListener("backEvent"): 하드웨어 뒤로가기 제어TossAds.initialize,TossAds.attachBanner: 배너 광고
7.5 광고 연동
Toss 배너 광고는 VITE_TOSS_AD_BANNER_GROUP_ID 환경 변수를 통해 광고 그룹 ID를 주입한다.
VITE_TOSS_AD_BANNER_GROUP_ID=ait.v2.live.xxxxxxxxxxxxxxxx광고는 다음 위치에 배치했다.
- 메인 화면 최근 영수증 타이틀 위
- 영수증 달력 화면 아래
로컬 개발 환경에서는 Toss 광고 API가 지원되지 않을 수 있으므로 placeholder를 표시하고, 실제 Toss 지원 환경에서는 SDK 배너가 렌더링되도록 분기했다.
8. UX 설계 포인트
8.1 저장 전 검수
OCR 앱에서 가장 중요한 UX는 "자동화"보다 "수정 가능성"이다. OCR 결과를 곧바로 저장하면 오류 데이터가 쌓일 수 있다. 따라서 OCR 확인 화면을 두어 사용자가 저장 전에 값을 고칠 수 있게 했다.
8.2 모바일 중심 버튼 설계
카메라, 앨범, 삭제, 확인, 뒤로가기 같은 반복 액션은 텍스트보다 아이콘 버튼으로 통일했다. 상단 뒤로가기 버튼은 arrow_back_24dp.svg를 사용하고 배경색을 #f2f4f6로 맞췄다.
8.3 뒤로가기 안전장치
메인 화면에서 뒤로가기를 누르면 바로 종료하지 않고 확인창을 띄운다. 이는 실수로 앱을 닫는 상황을 줄인다. 화면 버튼뿐 아니라 하드웨어 뒤로가기 이벤트도 같은 로직에 연결했다.
8.4 좁은 달력 셀 대응
달력의 날짜 셀은 폭이 좁기 때문에 금액이 길어지면 줄바꿈이 발생한다. 이를 해결하기 위해 금액 텍스트는 줄바꿈하지 않고 가로로 흐르는 애니메이션을 적용했다.
9. 환경 변수
| 변수 | 용도 |
|---|---|
VITE_GROQ_API_KEY |
Groq OCR API 인증 |
VITE_GROQ_API_URL |
Groq Chat Completions API URL |
VITE_GROQ_OCR_MODEL |
OCR에 사용할 Groq 모델 |
VITE_KAKAO_REST_API_KEY |
좌표 기반 주소 변환 |
VITE_KAKAO_REST_URI |
Kakao 좌표 변환 API |
VITE_TOSS_AD_BANNER_GROUP_ID |
Toss 배너 광고 그룹 ID |
10. 현재 구현 상태
- 메인 화면 구성 완료
- 멤버십 카드 OCR 등록 완료
- 영수증 OCR 등록 완료
- OCR 결과 검수 화면 완료
- 영수증 상세 바텀시트 완료
- 영수증 달력 완료
- 달력 금액 흐름 표시 완료
- 메인/달력 Toss 배너 광고 영역 완료
- 메인 화면 뒤로가기 종료 확인 완료
- 하드웨어 뒤로가기 종료 확인 완료
- 근무지 자동 추적 설정 및 로그 기록 구현
11. 한계와 개선 방향
11.1 OCR 정확도 개선
영수증은 매장별 포맷이 다양하다. 현재는 프롬프트 기반으로 구조화하지만, 장기적으로는 후처리 규칙을 더 보강할 필요가 있다.
개선 아이디어:
- 합계 후보가 여러 개일 때 우선순위 규칙 강화
- 날짜 파싱 실패 시 사용자 입력 유도
- 품목별 금액과 총액의 합산 검증
11.2 데이터 저장 방식
현재는 localStorage 중심이다. 미니앱을 더 본격적으로 운영하려면 서버 저장 또는 Toss 사용자 식별 기반 동기화가 필요할 수 있다.
개선 아이디어:
- 사용자별 영수증 백업
- 기기 변경 시 데이터 복구
- 월별 통계 서버 집계
11.3 광고 운영
배너 광고는 위치와 빈도를 신중히 조정해야 한다. 현재는 메인 최근 영수증 위와 달력 하단에 배치했다. 사용자의 핵심 작업을 방해하지 않는 선에서 수익화 지점을 확보하는 것이 목표다.
11.4 접근성/문구 정리
현재 구현 과정에서 일부 텍스트가 깨진 상태로 보이는 파일이 있다. 블로그 공개 전에는 인코딩과 사용자 노출 문구를 다시 점검하는 것이 좋다.
12. 블로그 글 구성안
제목 후보
- Apps in Toss에서 OCR 멤버십 지갑 만들기
- 영수증과 멤버십 카드를 OCR로 관리하는 미니앱 개발기
- 카메라, OCR, 위치, 광고까지 붙인 Toss 미니앱 제작 과정
글 흐름
- 왜 멤버십/영수증 관리 앱을 만들었나
- Apps in Toss를 선택한 이유
- OCR 기반 입력 흐름 설계
- 사용자가 직접 검수할 수 있는 UX
- 영수증 달력과 소비 데이터 시각화
- 위치 기반 근무지 기록 기능
- Toss 배너 광고 연동
- 개발 중 만난 문제와 해결
- 앞으로 개선할 점
13. 마무리
Billcorea Membership 앱은 작은 생활 데이터를 자동으로 구조화하고, 사용자가 다시 활용할 수 있게 만드는 미니앱이다. 카메라와 OCR을 통해 입력 비용을 낮추고, 달력과 상세 화면으로 데이터를 다시 볼 수 있게 했으며, Toss 환경에 맞는 뒤로가기 제어와 광고 연동까지 적용했다.
이 개발 과정은 Apps in Toss 미니앱에서 실용적인 기능을 빠르게 조합하는 방법을 보여준다. 특히 OCR처럼 불확실성이 있는 기능은 자동 저장보다 검수 화면을 두는 것이 중요했고, 모바일 화면의 좁은 공간에서는 작은 UI 디테일이 사용성을 크게 좌우했다.
댓글 없음:
댓글 쓰기