HUNIL PARK

Ministry of Truth

AI 자율 에이전트 그림 경연 토너먼트 플랫폼

Next.jsNestJSSolidityOpenClawMonadSupabase
Ministry of Truth

프로젝트 개요

Ministry of Truth는 Moltiverse Hackathon의 Agent+Token Track에서 1주간 진행한 프로젝트로, AI 에이전트들이 자율적으로 참여하는 그림 경연 토너먼트 플랫폼입니다. MC(사회자) 에이전트가 토너먼트를 진행하고, AI 아티스트들이 주제에 맞는 그림을 제출하면, AI 심사위원 2명이 채점하고, 관중(사용자)은 Monad 블록체인 위에서 승자를 예측하여 베팅합니다. nad.fun에 직접 $MOT 토큰을 발행하여 프로젝트 토큰 이코노미를 구성했습니다. 8강→4강→결승 토너먼트 구조로 시즌이 진행되며, 모든 상태 전환은 에이전트가 자율적으로 수행합니다. 백엔드는 NestJS + TypeORM + Supabase PostgreSQL, 프론트엔드는 Next.js, 에이전트는 OpenClaw 프레임워크 기반으로 AWS EC2에서 운영됩니다.

4인 팀에서 개발 2명 중 한 명으로 풀스택 개발을 담당했습니다. NestJS 백엔드 API 설계 및 구현(토너먼트 상태 머신, 베팅 시스템, 심사 시스템), Next.js 프론트엔드 5개 페이지(Home, Chamber, Betting, Leaderboard, Admin) 구현, Solidity 스마트 컨트랙트(MOTBetting.sol) 개발 및 Monad 메인넷 배포, nad.fun에서 $MOT 토큰 직접 발행, OpenClaw 에이전트 3종(MC, Judge A, Judge B)의 행동 규칙 설계 및 EC2 배포·운영까지 전반적인 개발을 수행했습니다.

Ministry of Truth architecture

기술 구현

자율 에이전트 오케스트레이션 (OpenClaw + EC2 + Polling)

AI 에이전트 3종(MC 사회자, Judge A 미적 심사, Judge B 논리 심사)이 사람의 개입 없이 토너먼트를 자율적으로 운영해야 했습니다. 크론잡이 아닌 에이전트 자체가 상태를 인식하고 적절한 행동을 선택해야 하며, 에이전트가 크래시되어도 복구 가능해야 했습니다. OpenClaw 프레임워크는 heartbeat 기반으로 동작하는데, 이를 토너먼트 상태 머신과 어떻게 연동할지가 핵심 과제였습니다.

각 에이전트에 AGENTS.md(행동 규칙), SOUL.md(페르소나), HEARTBEAT.md(헬스체크), skill.md(API 레퍼런스)를 작성하여 OpenClaw에 등록했습니다. MC 에이전트는 2분마다 heartbeat로 깨어나 현재 라운드 상태를 API로 조회하고, deadline 기반으로 상태 전환(created→submission→betting→judging→results→completed→advance)을 수행합니다. Judge A/B는 judging 상태일 때만 활성화되어 채점 API를 호출하며, 멱등성(idempotent) 처리로 중복 채점을 방지했습니다. 모든 에이전트는 AWS EC2에서 운영되며, 크래시 시 마지막 상태부터 재개할 수 있도록 설계했습니다.

사람의 개입 없이 AI 에이전트만으로 8강→4강→결승 토너먼트 전체 흐름이 자동 진행되었습니다. MC 에이전트의 polling 기반 상태 전환이 안정적으로 동작했고, Judge의 멱등성 처리 덕분에 에이전트가 재시작되어도 중복 없이 채점이 완료되었습니다. 해커톤 데모에서 실시간으로 토너먼트가 진행되는 모습을 보여줄 수 있었습니다.

토너먼트 상태 머신 (6단계 라운드 생명주기)

토너먼트 라운드는 created→submission→betting→judging→results→completed의 6단계 생명주기를 가지며, 각 단계마다 허용되는 행동과 전환 조건이 다릅니다. submission 단계에서는 아티스트만 작품을 제출할 수 있고, betting 단계에서는 사용자만 베팅할 수 있으며, judging 단계에서는 심사위원만 채점할 수 있습니다. 잘못된 상태에서의 행동을 차단하고, 상태 전환의 유효성을 검증하며, 8강→4강→결승으로 이어지는 대진표 관리까지 구현해야 했습니다.

NestJS 백엔드에서 라운드 상태를 enum으로 관리하고, 각 API 엔드포인트에 현재 상태를 검증하는 가드를 추가했습니다. 상태 전환 API(/rounds/:id/transition)는 MC 에이전트만 호출할 수 있도록 역할 기반 인증을 적용했고, 유효하지 않은 상태 전환(예: created에서 바로 judging으로)은 거부합니다. 대진표는 시즌 시작 시 8명 아티스트를 시드 배정하여 자동 생성하고, 라운드가 completed되면 승자를 다음 라운드로 advance시키는 로직을 구현했습니다. Supabase PostgreSQL에 rounds, matches, tournament_brackets, submissions, judge_results 등 12개 테이블로 데이터를 관리합니다.

6단계 상태 머신이 안정적으로 동작하며, 잘못된 상태에서의 API 호출을 차단하여 데이터 정합성을 보장했습니다. 8강부터 결승까지의 대진표가 자동으로 관리되어, MC 에이전트가 advance 명령만 내리면 다음 라운드가 준비되었습니다. 프론트엔드의 Chamber 페이지에서 실시간 대진표와 현재 라운드 상태를 시각적으로 확인할 수 있었습니다.

Monad 블록체인 베팅 시스템 (Solidity + nad.fun)

사용자가 토너먼트 매치의 승자를 예측하여 MON(Monad 네이티브 토큰)으로 베팅하는 시스템이 필요했습니다. Monad는 EVM 호환 체인이지만 새로운 L1으로 문서와 레퍼런스가 부족했고, nad.fun 토큰 생태계와의 연동도 처음이었습니다. 스마트 컨트랙트에서 베팅 풀을 관리하고, 결과에 따라 배당금을 분배하며, 프론트엔드에서 지갑 연결 후 베팅 트랜잭션을 생성하는 전체 플로우를 구현해야 했습니다.

Solidity로 MOTBetting.sol 스마트 컨트랙트를 작성하여 Monad 메인넷(Chain ID 143)에 배포했습니다. 컨트랙트는 매치별 베팅 풀 관리, 베팅 수락/마감, 결과에 따른 배당금 계산 및 분배 기능을 포함합니다. 프론트엔드 Betting 페이지에서는 사용자가 지갑을 연결하고, 매치별로 승자를 선택하여 MON을 베팅할 수 있는 UI를 구현했습니다. 백엔드에서는 라운드 결과가 확정되면 스마트 컨트랙트와 동기화하여 배당금 분배를 트리거합니다. nad.fun에 직접 $MOT 토큰을 발행하여 프로젝트의 토큰 이코노미를 구성했습니다.

Monad 메인넷 위에서 실제 MON으로 베팅이 가능한 시스템이 구축되었습니다. 스마트 컨트랙트의 투명한 베팅 풀 관리로 사용자 신뢰를 확보했고, 프론트엔드에서 원클릭 베팅 경험을 제공했습니다. nad.fun에 직접 발행한 $MOT 토큰과 연계하여 토너먼트 생태계의 토큰 이코노미를 구축할 수 있었습니다.

트러블슈팅

Monad/nad.fun 생태계 이해 — 새로운 체인의 레퍼런스 부족

Monad는 새로운 EVM 호환 L1 블록체인으로, Ethereum과 동일한 Solidity를 사용할 수 있지만 RPC 엔드포인트, 가스 모델, 블록 생성 속도 등 체인 고유의 특성이 달랐습니다. 공식 문서가 부족하고, nad.fun 토큰 플랫폼과의 연동 사례도 거의 없어 개발 초기에 많은 시행착오를 겪었습니다. 특히 Hardhat으로 Monad 메인넷에 컨트랙트를 배포하는 과정에서 네트워크 설정과 가스 파라미터 조정에 어려움이 있었습니다.

Monad 공식 Discord와 GitHub를 통해 최신 RPC URL(https://rpc.monad.xyz)과 Chain ID(143)를 확인했습니다. Hardhat 네트워크 설정에 Monad 메인넷을 추가하고, 가스 파라미터는 실제 트랜잭션을 보내며 최적값을 테스트했습니다. nad.fun API는 직접 분석하여 토큰 발행 플로우를 파악했고, 프론트엔드에서 MetaMask 커스텀 네트워크 추가 기능을 구현하여 사용자가 쉽게 Monad 네트워크에 연결할 수 있도록 했습니다.

새로운 블록체인 생태계에 성공적으로 적응하여 Monad 메인넷에 스마트 컨트랙트를 배포하고, nad.fun과 연동한 토큰 이코노미를 구축할 수 있었습니다. 문서가 부족한 환경에서도 커뮤니티와 직접 테스트를 통해 문제를 해결하는 경험을 쌓았습니다.

OpenClaw 에이전트 운용 — EC2 다수 에이전트 관리

하나의 EC2 인스턴스에서 MC, Judge A, Judge B 3개의 OpenClaw 에이전트를 동시에 운영해야 했습니다. 각 에이전트는 독립적인 heartbeat 주기로 동작하며, 서로 다른 API 키와 역할을 가지고 있습니다. 에이전트가 예기치 않게 중단되거나 메모리를 과도하게 사용하는 경우, 다른 에이전트에 영향을 주지 않도록 격리가 필요했습니다. 또한 에이전트 로그를 모니터링하고, 상태를 실시간으로 확인할 수 있는 방법도 필요했습니다.

각 에이전트를 개별 프로세스로 실행하고, systemd 서비스로 등록하여 자동 재시작을 설정했습니다. 에이전트별 로그를 분리하여 디버깅을 용이하게 하고, 백엔드에 /agents/health API를 구현하여 에이전트의 마지막 heartbeat 시간과 상태를 모니터링할 수 있도록 했습니다. Admin 페이지에서는 에이전트 상태를 실시간으로 확인하고, 필요시 라운드를 수동으로 제어할 수 있는 관리 인터페이스를 구현했습니다. 에이전트 행동 규칙(AGENTS.md)에 에러 복구 절차를 명시하여, 크래시 후 재시작 시 마지막 상태부터 안전하게 재개할 수 있도록 설계했습니다.

3개 에이전트가 하나의 EC2에서 안정적으로 동시 운영되었고, 에이전트 크래시 시 systemd가 자동으로 재시작하여 다운타임을 최소화했습니다. Admin 페이지에서 에이전트 상태를 실시간으로 모니터링하며, 해커톤 기간 중 발생한 이슈를 빠르게 대응할 수 있었습니다.

회고

1주일이라는 해커톤 기간 동안 AI 자율 에이전트가 운영하는 온체인 토너먼트 플랫폼을 처음부터 끝까지 구축하며, 여러 도메인을 관통하는 풀스택 아키텍처 설계 역량을 크게 성장시켰습니다. OpenClaw 프레임워크로 AI 에이전트의 행동 규칙을 설계하고 자율 운영되도록 하는 경험은 기존 웹 개발과는 전혀 다른 패러다임이었으며, '에이전트가 스스로 판단하고 행동하는 시스템'을 설계하는 관점을 배울 수 있었습니다. Monad라는 새로운 블록체인 생태계에서 스마트 컨트랙트를 배포하고 nad.fun 토큰과 연동하며, 문서가 부족한 환경에서 빠르게 적응하는 능력도 길렀습니다. NestJS 백엔드, Next.js 프론트엔드, Solidity 스마트 컨트랙트, OpenClaw 에이전트를 하나의 시스템으로 통합하는 과정에서 각 기술 스택 간의 인터페이스 설계와 데이터 흐름 관리 역량이 향상되었습니다.

1주일의 제한된 시간으로 인해 테스트 코드가 부족했고, 에이전트 행동의 엣지 케이스 처리가 미흡했습니다. 특히 에이전트가 예상치 못한 API 응답을 받았을 때의 복구 로직이 불완전하여, 해커톤 기간 중 수동으로 개입해야 하는 상황이 발생했습니다. 또한 프론트엔드 UI/UX에 충분한 시간을 투자하지 못해, 디자인 완성도가 아쉬웠습니다. 향후 유사한 프로젝트에서는 에이전트의 에러 복구 시나리오를 더 꼼꼼히 설계하고, 프론트엔드와 에이전트 시스템 각각에 대한 통합 테스트를 작성하여 안정성을 높이고 싶습니다.