AOIWALLET / DOCS
아키텍처
갱신 2026-10-24
고객 화면과 담당자 화면은 주소가 다르다. 돈의 기록은 PostgreSQL 원장 하나다. 키와 서명은 그 화면에 없고, 지갑 파일을 가진 custody 한 곳에만 있다.
브라우저는 고객 앱과 담당자 화면만 연다. 앱 안의 relay는 체인을 확인한 뒤 읽기만 하고 송신을 거절한다. 서명은 custody 안의 signer 프로세스다. 문서 사이트는 원장과 세션을 열지 않는다. /health가 응답해도 /ready의 인수 완료는 아니다.
전체 구조
선은 요청이나 기록이 오가는 길이다. 문서 사이트에는 원장으로 가는 선이 없다. 앱이 체인을 읽는 relay는 송신 선이 아니다.
늘릴 수 있는 것과 하나로 두는 것
replica는 같은 프로그램을 여러 개 띄우는 것이다. 코드를 나누는 것이 아니다.
화면은 나눌 수 있다
고객 앱과 관리자는 주소와 세션이 따로다. 앱 replica에는 지갑 볼륨과 master key를 넣지 않는다.
다만 지금 DB session pool 한도는 15다. 연결 합계를 다시 계산하기 전에는 replica를 추가하지 않는다.
하나로 두는 것
custody는 서비스 1개, /vault 볼륨 1개, replica 1개다. 공개 주소도 없다. 볼륨을 다른 서비스와 같이 보지 않는다.
signer는 그 안의 별도 프로세스다. 관측 worker와 실행을 한 설정에 섞지 않는다.
서비스 역할
| 서비스 | 여는 곳 | 하는 일 | replica | 메모 |
|---|---|---|---|---|
| app | 4310 | 고객 화면. 주문, 스왑, 브릿지, 출금 요청과 견적. | 조건부 | 키 없음. relay는 송신을 거절한다. |
| admin | 4311 | 담당자 화면. 수수료와 출금 정책. | 1 | 고객 돈을 서명해서 옮기지 않는다. |
| observer | 공개 주소 없음 | 잔액 관측과 일별 시세 수집. | 1 | 실행 큐와 signer가 없다. 시세 키는 여기만 둔다. |
| custody | 공개 주소 없음 | 지갑 발급. 실행과 서명은 같은 볼륨의 다음 인수. | 1 고정 | 볼륨은 /vault 하나. 서비스를 둘로 나누지 않는다. |
| docs | 4312 | 이 문서 사이트. | 1 | 원장, 세션, 서명을 열지 않는다. |
| schema | 명령 | 스키마 설치. | 원샷 | 서버가 켜질 때 자동으로 깔지 않는다. |
데이터와 체인
PostgreSQL 원장
캐시가 아니다. 주문한 행동과 실제 체결을 구분하고, 금액은 정확한 숫자로 남긴다. 아직 관측하지 않은 잔액은 0으로 채우지 않는다.
표시 환율은 daily_display_rates의 저장된 종가다. 앱과 관리자는 그 값만 읽는다.
세 네트워크 외부
Solana, Ethereum, Robinhood다. 관측은 잔액 증거를 남기고, 송신은 custody의 signer만 한다.
원금, 네트워크 가스, 앱 수수료 USDT는 같은 원장에서 구분한다. Redis로 이 기록을 대신하지 않는다.
두 가지 길
1. 잔액이 보이는 길
- 체인의 잔액을 observer가 읽는다.
- 증거와 수정 기록을 원장에 남긴다.
- 앱은 그 기록을 화면에 보여 준다.
앱만 다시 배포해도 잔액이 따라오지 않을 수 있다.
2. 돈이 움직이는 길
- 화면은 요청과 승인을 원장에 저장한다.
- custody의 signer가 저장된 원문으로 서명하고 보낸다.
- 실제 체결만 체결 기록에 남긴다.
응답이 없으면 실패나 환불로 단정하지 않는다. 지금 발급과 실제 송신 인수는 아직 별개다.
왜 이렇게 쪼개나
화면 서버가 키를 들고 보내면, 서버를 늘릴 때마다 서명이 겹칠 수 있다.
화면은 요청만 남긴다. 키와 송신은 custody 한 replica다. 프로세스가 살아 있는 것과 인수 완료는 다르다.
배포 단위
운영에 올라가는 프로세스는 앱, 관리자, 관측, custody, 문서다. 원장은 그 밖의 PostgreSQL이다.