Altus (알투스)
경력근거: 자산, 거래, 금융 데이터를 온/오프체인에 걸쳐 모델링하고 통합하여
Altus 는 기관 고객의 외주 파트너가 아니라 공동 빌더로서 맞춤형 아키텍처 설계부터 레거시 시스템 통합까지 함께하고, 그 첫 관문이 고객사 기술팀·경영진·법무와 직접 소통하며 문제를 정의하는 일이라, 통합 착수 자료의 결함을 질문으로 바꾸는 도구는 파견 첫 주에 실제로 필요한 물건입니다. 제가 이 포트폴리오로 보여주는 것은 지저분한 고객사 파일을 파싱해 형식·참조 규칙으로 결함을 잡고 사람이 읽을 문서로 내는 엔지니어링 기술이며, 스테이블코인·실물 자산 토큰화 같은 블록체인 금융 인프라 도메인 전문성을 갖췄다고 주장하지 않습니다.
기관 파트너가 보낸 지갑 주소록·자산 마스터·정산 배치 엑셀을 규칙으로 대조해, 통합을 막는 결함을 담당 팀이 답할 수 있는 질문 문장으로 정리합니다.
열 이름과 체인 표기가 고객사마다 다르므로 매핑 프로파일만 바꿔 같은 도구를 다음 현장에 그대로 가져갑니다.
결함 검출과 심각도 판정은 규칙 엔진이 결정론으로 끝내고, LLM 은 국문·영문 질문 문장과 미회신 시 가정 문장을 쓰는 데만 씁니다.
저는 계약된 기관 파트너 현장에 나가 고객사가 보낸 온보딩 엑셀을 받아, 통합을 막는 결함을 골라 담당 팀이 답할 질문 목록으로 돌려주는 CLI를 만드는 포워드 배포 엔지니어입니다.
온체인 정산 연동을 시작하겠다고 지갑 주소록과 자산 표를 보냈는데, 어느 주소가 왜 못 쓰이는지를 매번 다음 주 회의에서야 듣게 되는 기관 파트너의 정산 운영 담당자입니다.
지갑 주소·자산·정산 행의 결함은 대부분 형식 규칙과 참조 무결성으로 잡히므로, 착수 회의 전에 담당 팀별 질문 목록으로 만들어 돌려줄 수 있습니다.
지갑 주소록·자산 마스터·정산 배치 엑셀 세 파일을 인자로 주면 형식 결함과 참조 결함을 규칙 12종으로 잡아, 담당 팀별로 묶은 확인 질문 목록을 마크다운 파일 한 장으로 저장하고 터미널에는 결함 건수 요약만 찍는 완결품입니다. 질문 문안은 1주차에서 규칙 템플릿 문장으로 채우고 근거 셀 좌표를 함께 답니다.
1주차가 뽑은 결함 목록을 입력으로, 각 질문의 국문·영문 문안과 답을 못 받았을 때 두고 갈 가정 문장을 LLM 이 쓰되 근거 셀 좌표를 입력 화이트리스트에서만 인용하도록 output_schema 로 강제하고, 규칙이 정한 결함 코드와 심각도는 LLM 이 바꾸지 못하게 검증하는 단계입니다.
열 이름과 체인 표기가 다른 두 번째 고객사 자료를 매핑 프로파일 파일만 바꿔 코드 수정 없이 돌리고, 회신받은 답변 파일을 함께 넣으면 해소된 질문을 닫고 남은 질문만 다시 뽑는 재실행을 붙인 단계입니다.
엑셀 세 파일을 인자로 준 한 번의 실행으로 담당 팀별 확인 질문 목록 마크다운이 나오는 걸 터미널에서 시연합니다.
결함 판정이 형식 검사와 참조 대조라 같은 입력에 질문 목록이 100% 재현되며, 표본 34행에서 규칙이 잡은 결함과 근거 셀 좌표를 함께 보여줍니다. 단, 정답 라벨도 같은 규칙으로 붙인 합성 기준이라 성능 검증이 아니라 데모 조건에서의 동작입니다.
체크섬이 깨진 주소·decimals 빈 자산·통화기호가 섞인 금액·소계 행·중복 주소 같은 하드 케이스 24종을 넣어도 도구가 중간에 멈추지 않고 전부 질문으로 올립니다.
진짜 성능 검증은 여기서 멈춥니다. 위 수치는 더미데이터 자가채점이며, 질문 목록이 실제로 회신을 받아내는지는 Altus 의 실제 고객사 자료와 담당자 회신이 있어야 측정됩니다. 이 포트폴리오는 그 검증을 바로 돌릴 수 있는 상태로 만듭니다.
위 수치는 합성 데이터 자가채점이라 성능 증명이 아닙니다. 면접에서는 도구가 도는 것과 실검증을 바로 돌릴 준비 상태를 솔직히 설명합니다.
정답을 제가 만들었으니 잘 잡히는 게 당연한 함정을 피하려고, 체크섬 오류·decimals 누락·표기 흔들림·소계 행 같은 경계 케이스를 더미에 일부러 섞습니다.
제가 보여주는 것은 지저분한 엑셀을 파싱해 형식·참조 규칙으로 결함을 잡고 문서로 내는 기술이며, 블록체인 금융 규제·자산 발행 실무 전문성은 주장하지 않습니다. 정답은 주소 체크섬 검증과 마스터 대조 같은 규칙으로 결정론적으로 채점되고, 모르는 깊이는 면접에서 모른다고 말하는 편이 낫다고 봅니다.
실제 현장에서는 체인별 주소 형식 차이·다국어 열 이름·권한 때문에 일부만 받은 자료처럼 더미에 없던 요인이 결함 분포를 바꾸므로, 이 부분은 실자료 프로파일 작성과 담당자 인터뷰를 도입 단계 과제로 분리합니다.
① 인라인 샘플 · ② seed.json 다운로드 · ③ 증강 프롬프트. 세 층 모두 동일한 schema 에서 파생.
고객사가 보낸 상대 지갑 주소록 시트입니다. 체크섬 오류·주소 충돌·체인 표기 흔들림처럼 통합을 막는 결함을 의도적으로 담습니다.
| row_no | counterparty_name | counterparty_code | chain_raw | wallet_address | owner_team | registered_at | memo |
|---|---|---|---|---|---|---|---|
| 3 | Meridian Capital | CP-A | Cosmos EVM | 0x7d1AfA7B718fb893dB30A3aBc0Cfc608AaCf… | Treasury Ops | 2026-06-02 | — |
| 4 | Meridian Capital | CP-A | EVMOS | 0x3b2C51a9F4A1c0eE0b4d90BF6c1D2E77aA45… | Treasury Ops | 2026-06-09 | 구주소로 알고 있는데 폐기 여부 미확인 |
| 5 | Northbridge Trust | CP-B | evm-1 | 0x9C2fa1B7d0E4a6C8fF31b2D45Ae67C09b123… | — | 07/12/2026 | — |
| 6 | Northbridge Trust | CP-B | Canton | 0x9C2fa1B7d0E4a6C8fF31b2D45Ae67C09b123… | Settlement | 2026-07-12 | 칸톤 계정도 같은 주소로 쓰는 중 |
| 7 | Halcyon Asset | — | Cosmos EVM | 0x51Ab77Cd90Ee12Ff34aB56Cd78Ef90Ab12Cd… | Treasury Ops | 2026-06-18 | 코드 미정, 계약 체결 직후 등록 |
다음 JSON Schema 에 맞는 고객사 지갑 주소록 행을 추가로 생성하십시오: {"type":"object","properties":{"row_no":{"type":"integer"},"counterparty_name":{"type":"string"},"counterparty_code":{"type":["string","null"]},"chain_raw":{"type":"string"},"wallet_address":{"type":"string"},"owner_team":{"type":["string","null"]},"registered_at":{"type":["string","null"]},"memo":{"type":["string","null"]}},"required":["row_no","counterparty_name","chain_raw","wallet_address"]}. 쉬운 데이터만 만들지 마십시오. 다음 하드 케이스를 의도적으로 섞으십시오: 대소문자만 다른 같은 주소가 두 행에 나뉜 중복, 40자리를 못 채운 잘린 주소, 앞뒤 공백이나 0X 대문자 접두사가 붙은 주소, 서로 다른 상대가 같은 주소를 쓰는 충돌, chain_raw 가 'EVMOS'·'evm-1'·'Cosmos EVM' 처럼 흔들리는 표기, 주소 체계가 다른 Canton 계정 문자열, registered_at 이 '07/12/2026' 처럼 다른 날짜 형식인 행, owner_team 이나 counterparty_code 가 비어 있는 행, 표 맨 아래 '소계' 같은 잡행. 형식을 일부러 깨뜨리는 시도 3건(필수 열 누락·타입 위반)은 데이터가 아니라 파서 거부 테스트로 별도 표기하십시오.{"type":"object","properties":{"row_no":{"type":"integer"},"counterparty_name":{"type":"string"},"counterparty_code":{"type":["string","null"]},"chain_raw":{"type":"string"},"wallet_address":{"type":"string"},"owner_team":{"type":["string","null"]},"registered_at":{"type":["string","null"]},"memo":{"type":["string","null"]}},"required":["row_no","counterparty_name","chain_raw","wallet_address"]}고객사가 보낸 자산 마스터 시트입니다. decimals 누락·심볼 중복·활성 표기 혼재처럼 금액 환산과 자산 식별을 막는 결함을 담습니다.
| row_no | asset_symbol | asset_name | chain_raw | contract_address | decimals | issuer | is_active |
|---|---|---|---|---|---|---|---|
| 3 | USDC | USD Coin | Cosmos EVM | 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606… | 6 | Circle | Y |
| 4 | USDC | USD Coin (Canton) | Canton | — | 6 | Circle | 활성 |
| 5 | USDT | Tether USD | Cosmos EVM | 0xdAC17F958D2ee523a2206206994597C13D83… | — | Tether | Y |
| 6 | KRWS | 원화 스테이블 | Cosmos EVM | 0x77Ab12Cd34Ef56Ab78Cd90Ef12Ab34Cd56Ef… | 6자리 | — | Y |
| 7 | KRWS | 원화 스테이블(구) | Cosmos EVM | 0x99Cd34Ef56Ab78Cd90Ef12Ab34Cd56Ef7890… | 6 | — |
다음 JSON Schema 에 맞는 고객사 자산 마스터 행을 추가로 생성하십시오: {"type":"object","properties":{"row_no":{"type":"integer"},"asset_symbol":{"type":"string"},"asset_name":{"type":["string","null"]},"chain_raw":{"type":"string"},"contract_address":{"type":["string","null"]},"decimals":{"type":["integer","string","null"]},"issuer":{"type":["string","null"]},"is_active":{"type":["string","null"]}},"required":["row_no","asset_symbol","chain_raw"]}. 쉬운 데이터만 만들지 마십시오. 다음 하드 케이스를 의도적으로 섞으십시오: decimals 가 null 이거나 '6자리' 같은 문자열인 행, 같은 심볼이 체인만 달리해 두 번 나오는 행, 같은 심볼과 같은 계약 주소인데 decimals 가 서로 다른 모순 행, 대소문자만 다른 심볼 표기, contract_address 가 비어 있는 Canton 자산, issuer 나 asset_name 이 비어 있는 행, is_active 가 'Y'·'활성'·빈 문자열·null 로 섞인 행. 형식을 일부러 깨뜨리는 시도 3건(필수 열 누락·타입 위반)은 데이터가 아니라 파서 거부 테스트로 별도 표기하십시오.{"type":"object","properties":{"row_no":{"type":"integer"},"asset_symbol":{"type":"string"},"asset_name":{"type":["string","null"]},"chain_raw":{"type":"string"},"contract_address":{"type":["string","null"]},"decimals":{"type":["integer","string","null"]},"issuer":{"type":["string","null"]},"is_active":{"type":["string","null"]}},"required":["row_no","asset_symbol","chain_raw"]}고객사가 첫 정산 배치로 보낸 요청 시트입니다. 주소록·자산 마스터에 없는 값을 참조하거나 금액 표기가 흔들리는 행을 담아 참조 무결성 결함을 만듭니다.
| row_no | request_id | counterparty_name | asset_symbol | amount_raw | chain_raw | value_date | note |
|---|---|---|---|---|---|---|---|
| 3 | RQ-2601 | Meridian Capital | USDC | 25,000.00 | Cosmos EVM | 2026-07-13 | — |
| 4 | RQ-2602 | Northbridge Trust | USDT | 12,000 | Cosmos EVM | 2026-07-13 | — |
| 5 | RQ-2603 | Halcyon Asset | GLDT | 3.123456789012 | Canton | 07/14/2026 | 금 토큰 소수 자리 확인 필요 |
| 6 | RQ-2604 | Solaris Bank | USDC.e | 8,500.00 | evm-1 | 2026-07-14 | — |
| 7 | RQ-2605 | Vantage Partners | USDC | 40,000.00 | Cosmos EVM | 2026-07-15 | 신규 상대 |
다음 JSON Schema 에 맞는 고객사 정산 배치 요청 행을 추가로 생성하십시오: {"type":"object","properties":{"row_no":{"type":"integer"},"request_id":{"type":"string"},"counterparty_name":{"type":"string"},"asset_symbol":{"type":"string"},"amount_raw":{"type":["string","null"]},"chain_raw":{"type":["string","null"]},"value_date":{"type":["string","null"]},"note":{"type":["string","null"]}},"required":["row_no","request_id","counterparty_name","asset_symbol"]}. 쉬운 데이터만 만들지 마십시오. 다음 하드 케이스를 의도적으로 섞으십시오: 주소록에 없는 상대 이름, 자산 마스터에 없는 심볼(대소문자만 다른 것 포함), 자산 decimals 보다 소수 자리가 많은 금액, 콤마나 통화기호가 붙은 금액 문자열, '-' 나 빈 값인 금액, 같은 request_id 가 두 번 나오는 중복 행, chain_raw 나 value_date 가 비어 있는 행, 'MM/DD/YYYY' 형식 날짜, 표 맨 아래 '합계' 잡행. 형식을 일부러 깨뜨리는 시도 3건(필수 열 누락·타입 위반)은 데이터가 아니라 파서 거부 테스트로 별도 표기하십시오.{"type":"object","properties":{"row_no":{"type":"integer"},"request_id":{"type":"string"},"counterparty_name":{"type":"string"},"asset_symbol":{"type":"string"},"amount_raw":{"type":["string","null"]},"chain_raw":{"type":["string","null"]},"value_date":{"type":["string","null"]},"note":{"type":["string","null"]}},"required":["row_no","request_id","counterparty_name","asset_symbol"]}| Golang | CLI 본체입니다. 엑셀 3종 파싱, 결함 규칙 엔진, 담당 팀별 질문 목록 마크다운 렌더가 한 바이너리 안에 들어갑니다. |
| Rust | 지갑 주소와 금액 정규화 모듈에 씁니다. EIP-55 체크섬 검증, 주소 길이·전각 문자 정리, 자산 decimals 기준 고정소수 환산으로 절삭이 생기는 행을 잡습니다. |
| TypeScript | 질문 문안 템플릿과 출력 JSON Schema 검증기를 작성해 CI 에서 회귀로 돌립니다. 화면은 만들지 않고 검증 스크립트로만 씁니다. |
| integration layer | 고객사별 열 이름·체인 표기·담당 팀 구분을 담은 매핑 프로파일입니다. 다음 현장에 붙일 때 코드가 아니라 이 파일만 바꾸는 통합 지점입니다. |
✓ pass → 여기서 멈춰도 착수 질문 목록 도구로 완결품입니다. 더 키우려면 2주차에서 질문 문안을 국문·영문으로 다듬고 가정 문장을 붙입니다.
✓ pass → 여기서 멈춰도 고객사에 바로 보낼 수 있는 질문지로 완결입니다. 더 키우려면 3주차에서 다른 고객사 프로파일과 회신 반영 재실행을 붙입니다.
규칙 엔진이 잡은 결함 하나를 고객사 담당 팀이 그대로 회신할 수 있는 질문 한 건으로 바꾼 출력입니다. 근거 셀 좌표와 원본 값을 반드시 인용하고, 답을 못 받았을 때 두고 갈 가정을 함께 답니다.
{"type":"object","properties":{"question_id":{"type":"string"},"defect_code":{"type":"string","enum":["address_checksum_invalid","address_length_invalid","address_conflict","asset_decimals_missing","asset_symbol_duplicated","asset_not_registered","counterparty_not_registered","amount_precision_overflow","amount_format_ambiguous","chain_label_unknown","date_format_mixed","duplicate_request_id"]},"severity":{"type":"string","enum":["blocking","clarify","fyi"]},"owner_team":{"type":"string","enum":["asset_ops","settlement","wallet_security","legal"]},"source_refs":{"type":"array","items":{"type":"object","properties":{"file":{"type":"string"},"sheet":{"type":"string"},"row_no":{"type":"integer"},"column":{"type":"string"},"value":{"type":["string","number","null"]}},"required":["file","row_no","column"]}},"question_ko":{"type":"string"},"question_en":{"type":"string"},"assumption_if_no_answer":{"type":"string"},"hedge":{"type":"string"}},"required":["question_id","defect_code","severity","owner_team","source_refs","question_ko","question_en"]}[
{
"question_id": "Q-014",
"defect_code": "address_conflict",
"severity": "blocking",
"owner_team": "wallet_security",
"source_refs": [
{
"file": "counterparty_wallets.xlsx",
"sheet": "wallets",
"row_no": 5,
"column": "wallet_address",
"value": "0x9C2fa1B7d0E4a6C8fF31b2D45Ae67C09b1234Abc"
},
{
"file": "counterparty_wallets.xlsx",
"sheet": "wallets",
"row_no": 6,
"column": "wallet_address",
"value": "0x9C2fa1B7d0E4a6C8fF31b2D45Ae67C09b1234Abc"
}
],
"question_ko": "5행과 6행이 같은 주소를 Cosmos EVM 과 Canton 두 체인에 함께 등록했습니다. 두 체인 모두 이 주소로 수취하는 것이 맞는지, 아니면 한쪽이 잘못 복사된 것인지 알려 주십시오.",
"question_en": "Rows 5 and 6 register the same address for both the Cosmos EVM and Canton chains. Please confirm whether both chains really settle to this address, or whether one of the rows was copied by mistake.",
"assumption_if_no_answer": "회신이 없으면 Canton 행을 오입력으로 보고 통합 대상에서 제외한 뒤 착수 회의에서 다시 확인하겠습니다.",
"hedge": "체인별 주소 체계가 실제로 겹칠 수 있는지는 고객사 지갑 운영 방식에 따라 달라집니다."
},
{
"question_id": "Q-021",
"defect_code": "asset_decimals_missing",
"severity": "blocking",
"owner_team": "asset_ops",
"source_refs": [
{
"file": "asset_master.xlsx",
"sheet": "assets",
"row_no": 5,
"column": "decimals",
"value": null
}
],
"question_ko": "USDT(Cosmos EVM) 행의 decimals 가 비어 있어 정산 금액을 온체인 단위로 환산할 수 없습니다. 이 자산의 decimals 값을 알려 주십시오.",
"question_en": "The decimals field is empty for USDT on Cosmos EVM, so settlement amounts cannot be converted to on-chain units. Please provide the decimals value for this asset.",
"assumption_if_no_answer": "회신이 없으면 같은 심볼의 다른 체인 행과 동일한 6 으로 가정하되, 환산 결과에 확인 필요 표시를 남기겠습니다.",
"hedge": "다른 체인 행에서 값을 빌려오는 가정이라 실제 발행 계약과 다를 수 있습니다."
},
{
"question_id": "Q-033",
"defect_code": "amount_precision_overflow",
"severity": "clarify",
"owner_team": "settlement",
"source_refs": [
{
"file": "settlement_batch_rows.xlsx",
"sheet": "batch_2607",
"row_no": 5,
"column": "amount_raw",
"value": "3.123456789012"
},
{
"file": "asset_master.xlsx",
"sheet": "assets",
"row_no": 8,
"column": "decimals",
"value": 18
}
],
"question_ko": "GLDT 요청 금액의 소수 자리가 자산 마스터의 decimals 기준과 달라 절삭이 생깁니다. 절삭 후 금액으로 처리해도 되는지, 아니면 요청 금액을 다시 받아야 하는지 알려 주십시오.",
"question_en": "The decimal places in the GLDT request amount do not line up with the decimals in the asset master, so the value would be truncated. Please tell us whether we may settle the truncated amount or should request a corrected figure.",
"assumption_if_no_answer": "회신이 없으면 해당 행을 배치에서 빼고 나머지만 처리하겠습니다.",
"hedge": "절삭 허용 여부는 고객사 회계 정책에 달려 있어 도구가 대신 정할 수 없습니다."
}
][자동 검증 (코드로 거름)] 1. defect_code 와 severity 는 enum 안에 있어야 하며, 규칙 엔진이 산출한 값과 정확히 같아야 합니다. LLM 이 바꾸면 그 질문은 버리고 규칙 값으로 다시 생성합니다. 2. source_refs 의 file·sheet·row_no·column 조합은 입력 파일에 실제로 존재하는 셀 좌표 화이트리스트에만 속해야 하고, value 는 그 셀의 원본 값과 일치해야 합니다. 없는 셀을 지어내면 형식 통과로 보지 않고 거릅니다. 3. severity 가 blocking 이면 assumption_if_no_answer 가 비어 있으면 안 됩니다. 4. question_ko 와 question_en 은 같은 결함을 가리켜야 하며, 두 문장 중 하나만 채워진 출력은 거릅니다. [수동 검증 (사람이 봄)] 1. 질문 문장이 담당 팀이 추가 설명 없이 답할 수 있을 만큼 구체적인지 표본으로 확인합니다. 2. 영문 문안이 고객사에 그대로 보낼 수 있는 어투인지 봅니다.
근거: 자산, 거래, 금융 데이터를 온/오프체인에 걸쳐 모델링하고 통합하여