리워드 서비스를 만들어 달라는 요청을 받으면, 대부분 “미션 하면 포인트 주는 거요”라고 말씀하십니다. 기능만 보면 맞습니다. 그런데 실제로 어려운 건 포인트를 주는 게 아니라, 틀리지 않게 주는 일입니다.
한 번 잘못 주면 신뢰가 무너집니다
포인트는 돈입니다. 사용자 입장에서 10원이 덜 들어오면 그 서비스는 못 믿을 서비스가 됩니다. 반대로 실수로 두 번 지급되면 회사가 손해를 봅니다.
저희가 만든 오퍼월은 지금까지 누적 3,300만 건이 넘는 미션을 처리했습니다. 이 규모에서는 0.01%의 오류도 수천 건이 됩니다. 그래서 처음부터 “틀릴 수 있는 경우”를 하나씩 막아두고 시작해야 합니다.
문제 1. 같은 요청이 두 번 온다
네트워크가 불안하면 앱이 같은 요청을 두 번 보냅니다. 사용자는 한 번 눌렀는데 서버에는 두 번 도착합니다. 아무 장치가 없으면 포인트가 두 배로 들어갑니다.
해결은 간단합니다. 요청마다 고유한 키를 붙이고, 같은 키가 다시 오면 무시합니다. 말은 쉽지만 이걸 처음부터 넣어두지 않으면, 나중에 전체 로직을 뜯어야 합니다.

문제 2. 광고사가 나중에 취소한다
외부 광고 네트워크를 붙이면, 미션 완료가 들어온 뒤에 취소되는 일이 있습니다. 부정 참여로 판정되면 광고사가 며칠 뒤에 취소 신호를 보냅니다.
이미 사용자에게 포인트를 준 뒤라면 곤란해집니다. 그래서 지급을 두 단계로 나눕니다.
- 적립 예정: 미션이 완료되면 일단 예정 상태로 쌓습니다.
- 확정: 취소 기간이 지나면 실제 포인트로 바꿉니다.
사용자에게는 “적립 예정”이라고 그대로 보여줍니다. 숨기면 나중에 더 큰 불만이 됩니다.
사용자는 기다리는 건 참습니다. 설명 없이 사라지는 건 못 참습니다.
문제 3. 부정 참여
미션을 자동으로 반복하는 프로그램을 쓰는 사용자가 있습니다. 막지 않으면 광고주 예산이 순식간에 빠집니다.
전부를 막을 수는 없지만, 걸러낼 수 있는 신호는 많습니다. 같은 기기에서 비정상적으로 빠르게 반복되는 참여, 실제 체류 시간이 지나치게 짧은 경우 같은 것들입니다. 이런 규칙을 데이터로 계속 다듬어 가는 게 실무입니다.

문제 4. 숫자가 안 맞을 때 찾을 수 있어야 한다
가장 중요한 건 이겁니다. 정산이 안 맞았을 때 어디서 틀렸는지 찾을 수 있어야 합니다.
그래서 포인트는 “현재 잔액”만 저장하지 않습니다. 언제 무엇 때문에 얼마가 오갔는지를 한 줄씩 전부 남깁니다. 잔액은 그 기록을 더한 결과일 뿐입니다. 이렇게 해두면 문제가 생겨도 원인을 정확히 짚을 수 있습니다.
정리
- 같은 요청이 두 번 와도 한 번만 처리되게 만듭니다.
- 지급을 예정과 확정으로 나눕니다.
- 사용자에게 상태를 그대로 보여줍니다.
- 모든 변동을 기록으로 남기고, 잔액은 계산해서 씁니다.
기능 목록만 보면 단순해 보이는 서비스가, 실제로는 이런 걸 다 갖춰야 굴러갑니다. 견적이 회사마다 크게 다른 이유이기도 합니다.
