송금 플로우
Senco의 핵심 사용자 여정인 해외 송금(돈 또는 크립토) 플로우다. 금액 입력, 수단 비교, 수취인 선택, 비용 내역을 하나의 직선형 3단계 플로우로 묶는다.
디자인 시스템의 나머지는 모두 이 플로우가 제대로 동작하게 하려고 있다. 제품에서 유일하게 되돌릴 수 없는 액션이고, 실수하면 사용자가 실제로 돈을 잃는 유일한 곳이다. 그리고 사용자 대부분이 신호가 두 칸뿐인 중급 휴대폰으로 보게 될 화면이다.
플로우 구조
Send → Review → Confirm 순서로 진행하는 직선형 3단계 플로우다.
각 단계는 다음으로 넘어가기 전에 입력을 검증한다. 뒤로 가도 입력한 데이터는 사라지지 않는다.
왜 세 단계인가
송금에는 세 가지 결정이 필요하다. 얼마를 보낼지, 누구에게 어떤 경로로 보낼지, 그리고 정말 보낼지. 세 단계는 이 결정을 나눌 수 있는 최소한의 수다. 검토와 확인을 합치면 수수료와 합계를 맞춰 볼 마지막 기회가 없어진다. 네 번째 단계가 생긴다면 다른 곳에 있어야 할 무언가를 플로우가 떠안았다는 뜻이다.
| Step | The question | What can still change |
|---|---|---|
| 1 · Send | 얼마를, 어떤 경로로 보낼까? | 전부 |
| 2 · Review | 내가 의도한 게 맞나? | 뒤로 가면 전부 |
| 3 · Confirm | 정말 보낼까? | 제출하면 아무것도 바꿀 수 없음 |
상태 유지
- 뒤로 가거나, 앱이 백그라운드로 가거나, 연결이 끊겨도 데이터는 유지된다.
- 그만뒀던 송금으로 돌아오면 단계와 입력값을 복원한다: "You have an unfinished transfer to Maria Santos."
- 플로우는 사용자가 직접 넘길 때만 진행된다. 환율 갱신에 성공했을 때를 포함해 어떤 경우에도 자동으로 넘어가지 않는다.
- 제출하면 플로우를 상태 화면 위에 겹치지 않고 상태 화면으로 바꾼다. 결과 화면 뒤에 폼이 남아 있어 돌아갈 수 있으면 같은 송금이 두 번 나간다.
환율을 고정하는 시점
환율은 1단계에서 견적을 내고 플로우가 끝날 때까지 유지한다. 확인 전에 견적이 만료되거나 환율이 크게 움직이면, 3단계에서 다시 견적을 내고 바뀐 내용을 분명히 알린다. 바뀐 환율을 말없이 적용하지 않는다. 412,500 NGN을 확인했는데 408,000 NGN을 받았다면, 사용자가 본 숫자는 아무 의미 없는 장식이었던 셈이다.
송금 비교
사용자는 은행 송금(법정화폐 환전)과 크립토 송금(스테이블코인) 중 하나를 고른다. 비교 카드에는 다음을 보여 준다.
- 환율 또는 환산율
- 서비스 수수료
- 도착 속도
- 받는 총액
- 더 유리한 쪽에 "Cheaper" / "Faster" 배지
사용자가 충분히 비교하고 고를 수 있도록 두 옵션은 항상 나란히 보여 준다.
설정이 아니라 비교로 보여 준다
이 단계를 선택 트리로 만들면 사용자는 돈을 보내기 전에 정산 경로부터 이해해야 한다. 비교로 보여 주면 실제로 결정을 가르는 두 숫자, 받는 총액과 도착 시간만 보고 한 줄을 고르면 된다. 할 수 있는 일은 같고 전문 지식은 필요 없다. Design principles를 참고한다.
배지는 빠르게 고르는 길이다
"Cheapest"와 "Fastest" 배지가 있으면 카드를 끝까지 읽지 않고도 고를 수 있고, 실제로 대부분 그렇게 고른다. 배지가 정직하게 동작하도록 두 가지 규칙을 둔다.
- 배지는 계산해서 붙이고, 임의로 붙이지 않는다. 은행 송금이 더 싸고 더 빠르면 은행 송금에 배지 두 개를 모두 붙이고 크립토에는 하나도 붙이지 않는다.
- 배지는 옵션의 접근 가능한 이름에 포함한다. 그래야 스크린 리더 사용자도 같은 방식으로 빠르게 고를 수 있다.
어느 옵션도 미리 선택해 두지 않는다. 수수료가 붙는 경로를 미리 선택해 두는 건 사용자 대신 결정을 내리는 것이다.
접근성
Radio card 의미 구조를 기반으로 한다. Tab 정지점은 하나이고, 화살표 키로 이동하면서 선택한다. 선택 상태는 테두리 두께, 배경색, 표시기 채움으로 함께 나타낸다. 색각 이상이 있으면 배경색은 거의 보이지 않으므로 테두리 두께가 구분을 맡는다.
비용 내역
확인하기 전에 수수료 내역 전체를 보여 준다.
- 보내는 금액
- 환율 또는 환산율
- 환전 마진 (은행 송금만)
- 서비스 수수료
- 도착 시간
- 받는 총액 (강조)
- 다른 수단과 비교한 절약 금액
숨은 수수료도, 별표 주석도 없다. 총비용은 항상 보이게 한다.
내역을 접어서 숨기지 않는다
수수료는 접힌 Details 블록 안이 아니라 검토 단계 화면에 바로 보여 준다. Details에는 이미 합계로 보여 준 수수료의 세부 구성을 넣을 수는 있다. 하지만 비용이 있다는 사실 자체를 그 안에 숨기면 안 된다.
이렇게 하면 전환율은 떨어진다. 수수료를 보고 멈추는 사용자도 있을 것이다. 하지만 수수료를 알았다면 보내지 않았을 사용자라면 보내지 않는 게 맞다. 이 트레이드오프는 Design principles에 적혀 있고, 그 비용을 실제로 치르는 화면이 여기다.
환전 마진은 따로 표시한다
환전 마진은 서비스 수수료와 분리해서 표시한다. "수수료"를 하나로 합쳐 보여 주면 대부분의 경쟁사가 숨기는 바로 그 부분이 가려진다. 사용자가 두 경로를 비교하는 이유가 바로 그걸 보려는 것이다.
접근성
- 설명 목록으로 렌더링해서 라벨과 값이 짝을 이루게 한다. 그래야 서로 상관없는 두 열이 아니라 구조화된 데이터로 읽힌다.
- 금액에는
tabular-nums를 쓰고, 모든 금액에 통화 코드를 붙인다. - 합계는 색을 바꾸지 않고 굵고 크게 표시한다. 그래야 흑백으로 봐도 강조가 유지된다.
수취인 선택
- 최근/저장된 수취인을 먼저 보여 준다 (스마트 기본값)
- 이름으로 검색할 수 있다
- 나라, 결제 수단, 통화 태그를 보여 준다
- 은행 계좌, 모바일 머니, 지갑 주소를 지원한다
수취인을 고르면 경로도 정해진다
같은 사람이라도 은행 송금으로 받을 때와 모바일 머니로 받을 때 수수료와 도착 시간이 다르다. 그래서 연락처 카드에 결제 수단을 함께 보여 준다. 어떻게 보낼지 정하지 않고 "Maria"만 고르는 건 선택이 끝난 게 아니다.
확정하기 전에 확인한다
검토 단계에서 수취인 계좌 정보를 확인용으로 보여 준다. 계좌 번호는 마지막 네 자리만 남기고 가리고, 계좌 이름은 은행에 등록된 그대로 보여 준다. 이름 불일치는 해외 결제가 반려되는 가장 흔한 원인이다. 제출 전에 잡으면 간단하지만 제출 후에 잡으면 비용이 크다.
접근성
- 각 연락처 카드는
<button>이고, 접근 가능한 이름에 화면에 보이는 정보를 모두 담는다: "Maria Santos, Nigeria, bank transfer." - 검색은 이름, 나라, 계좌 번호 일부로 찾을 수 있고, 결과 개수는 polite로 알린다.
- 국기는 장식 요소다. 나라 정보는 이미 이름에 들어 있다.
목표 환율 알림
사용자가 목표 환율을 정해 두면 그 환율에 도달했을 때 알려 주는 선택 기능이다. 대상 통화 쌍이라면 1단계(금액 입력)에서 쓸 수 있다.
대상 조건
- 통화 쌍의 환율이 변동할 때만 보여 준다
- 고정 환율 통화(예: USDT → USD)나 같은 통화끼리의 송금에서는 숨긴다
- 자동으로 판단한다. 해당 통화 쌍에 변동 환율 수단이 없으면 토글을 숨긴다
흐름
- 사용자가 보낼 금액과 통화를 입력한다
- "Wait for a better rate?" 토글이 나타난다 (Switch,
lg크기) - 켜면:
- 송금 수단 선택기가 나타난다 (변동 환율 수단만)
- 현재 환율을 참고용으로 보여 준다
- 목표 환율 입력: 원하는 환율을 입력한다 (현재 환율보다 높아야 한다)
- 만료 기간 선택: "24 hours" 또는 "7 days"
- 검증: 목표 환율은 현재 환율보다 높아야 한다. 값이 비어 있거나 잘못되면 제출 버튼이 비활성화된다
- 제출하면 홈으로 이동하고 성공 토스트를 보여 준다
송금 플로우와의 관계
| Toggle state | Method selector | Rate alert fields | Submit button |
|---|---|---|---|
| OFF | 보임 (기본) | 숨김 | "Continue to review" |
| ON | 숨김 (알림용 수단 선택으로 대체) | 보임 | "Set rate alert" |
검증 규칙
| Rule | Error message |
|---|---|
| 목표 환율이 비어 있음 | "Enter a target rate" |
| 목표 환율 ≤ 현재 환율 | "Target must be higher than current rate" |
| 수단을 선택하지 않음 | 버튼 비활성 (에러 표시 없음) |
환율 알림은 송금이 아니다
토글을 켜면 주요 버튼의 동작이 "Continue to review"에서 "Set rate alert"로 바뀌고, 돈은 움직이지 않는다. 이 차이를 버튼 라벨이 알려 주기 때문에 라벨을 "Continue"로 그대로 두지 않고 바꾼다. 알림이 만료돼도 송금을 실행하지 않고 알려 주기만 한다. Senco는 사용자가 그 순간 직접 확인하지 않은 일정으로 돈을 보내지 않는다.
디자인과 접근성
- 토글은 눈에 잘 띄도록
lgSwitch(48×28px)를 쓴다 - 현재 환율은 읽기 전용 참고 텍스트로 보여 준다
- 목표 환율 입력은 표준 Input에
inputMode="decimal"을 지정해 쓴다 - 만료 기간 버튼은 옵션 두 개짜리 알약형 선택기다 (옵션 두 개에 라디오 카드는 너무 무겁다)
- 성공 토스트는 DS Sonner success 스타일(초록 테두리, 체크 아이콘)을 쓴다
- 스위치를 켜고 끄면 폼 구성이 바뀌므로, 어떤 필드가 생기고 사라졌는지 알린다
- "수단을 선택하지 않음"일 때 에러 없이 버튼을 비활성화하는 건, 제출 버튼을 항상 활성으로 둔다는 폼 규칙의 예외로 문서화해 둔 것이다. 아래 알려진 공백에 올려 두었다
디자인과 접근성
- 송금 비교 카드는 키보드(화살표 키)로 이동할 수 있다
- 선택한 수단은 색만이 아니라 테두리와 체크 표시로도 보여 준다
- 비용 내역은 스크린 리더에서 데이터 표로 읽힌다
- 금액 입력은 직접 입력과 붙여 넣기를 모두 지원한다
- 통화 선택기는 키보드로 조작할 수 있다
- 목표 환율 토글은 터치 영역이 48×28px인
lgSwitch를 쓴다 - 환율 알림 폼 필드는 표준 에러 패턴으로 인라인 검증한다
실패 경로
플로우는 가장 좋은 상황이 아니라 가장 나쁜 상황에서도 제대로 동작해야 한다.
| Failure | Behavior |
|---|---|
| 플로우 중간에 연결이 끊김 | 데이터를 기기에 저장해 두고, 돌아오면 그 단계를 복원한다 |
| 제출이 서버에 닿지 못함 | "We'll send this when you're back online"을 보여 주고 대기열에 넣는다. 말없이 버리지 않는다 |
| 서버가 송금을 거부함 | 에러에서 원인을 밝히고, 돈이 움직이지 않았으며 잔액도 그대로라고 알린다 |
| 확인 전에 환율 견적이 만료됨 | 다시 견적을 내고, 바뀐 내용을 알리고, 다시 확인받는다 |
| 확인 버튼을 두 번 누름 | 첫 번째로 누르는 순간, 요청을 보내기 전에 플로우가 확인 버튼의 loading을 켠다. 플로우가 해제할 때까지 버튼은 추가 입력을 무시한다 |
| 제출은 했지만 결과를 알 수 없음 | 상태 화면에 참조 번호와 함께 Pending을 보여 준다. 말없이 실패로 끝내지 않는다 |
가장 중요한 건 "결과를 알 수 없음"이다. 확인 요청이 타임아웃되면 사용자는 돈이 나갔는지 알 수 없다. 이때 플로우는 아무 일도 없었던 것처럼 보이는 에러로 끝나면 안 되고, 사용자가 문의할 때 쓸 수 있는 참조 번호를 남겨야 한다.
알려진 공백
- 기기 저장과 오프라인 대기열은 이 페이지와 Forms에 걸쳐 정의돼 있지만 공용 메커니즘으로 구현되지 않았다.
- 환율 알림에서 제출 버튼을 비활성화하는 경우는, 제출 버튼을 활성으로 두고 에러로 설명한다는 폼 규칙과 어긋난다.
- 글자 하나만 잘못 입력해도 되돌릴 수 없는 지갑 주소에 대해, 수취인을 확인하는 단계가 문서화되지 않았다.