SCHEMA.md: NFT 서버 (Corporate Edition) MongoDB 스키마
현재 코드베이스(server/src/common/schemas/*.schema.ts)에서 사용 중인 Mongoose 스키마를 정리했습니다. 모든 주문/배포/전송 데이터는 corporateId로 샤딩되어 있으며, X-CORPORATE-ID 헤더를 통한 데이터 격리가 가정됩니다.
1. CorporateAccount (corporateAccounts)
| 필드 |
타입 |
필수 |
인덱스/제약 |
설명 |
_id |
ObjectId |
자동 |
|
MongoDB 기본 키 |
corporateId |
String |
✅ |
Unique + Index |
X-CORPORATE-ID 헤더 값. 전 API 스코프 키 |
corporateName |
String |
✅ |
|
표시용 이름 |
secretManagerKeyId |
String |
✅ |
|
AWS Secrets Manager Secret ID (or local key alias) |
walletAddress |
String |
✅ |
|
기업 전용 지갑 주소(참조/검증용) |
walletLinkType |
Enum(DEDICATED,SHARED) |
✅ |
Default DEDICATED |
지갑 사용 전략 |
metadata |
Object |
❌ |
|
자유 형식 메모/옵션 |
status |
Enum(ACTIVE,DISABLED) |
✅ |
Default ACTIVE |
비활성화 시 Guard 단계에서 차단 |
createdAt/updatedAt |
Date |
자동 |
|
@Schema({ timestamps: true }) |
이 컬렉션은 Auth Guard에서 글로벌 로드되며, 존재하지 않거나 DISABLED 상태면 모든 보호 API가 거부됩니다.
| 필드 |
타입 |
필수 |
인덱스/제약 |
설명 |
_id |
ObjectId |
자동 |
|
Metadata 문서 ID (metadataId) |
chainId |
String |
✅ |
Index |
사용 예정 체인 |
contractAddress |
String |
❌ |
Sparse Index |
민팅 성공 후 채워짐 |
tokenId |
String |
❌ |
Sparse Index |
민팅 성공 후 채워짐 |
standardFields |
Object |
✅ |
|
OpenSea 호환 필드 |
├ name |
String |
✅ |
|
NFT 이름 |
├ description |
String |
❌ |
|
설명 |
├ image |
String |
✅ |
|
공개 URL (S3/CDN 등) |
├ externalUrl |
String |
❌ |
|
상세 페이지 |
└ attributes |
Attribute[] |
❌ |
|
{ traitType, value } 배열 |
utility |
Object |
✅ |
|
DApp 고유 데이터 |
├ type |
String |
✅ |
|
Ticket, Coupon 등 |
├ validationUrl |
String |
❌ |
|
검증용 Webhook |
└ data |
Mixed |
✅ |
|
{ status, ... } 형태, 원본 데이터 |
currentStatus |
String |
✅ |
Index |
utility.data.status 복제본(빠른 조회용) |
createdAt/updatedAt |
Date |
자동 |
|
상태 변경 추적 |
복합 인덱스: { contractAddress: 1, tokenId: 1 } Unique + Sparse (민팅된 토큰 중복 방지 및 빠른 tokenURI 서빙)
3. DeployedContract (deployedContracts)
| 필드 |
타입 |
필수 |
인덱스/제약 |
설명 |
_id |
ObjectId |
자동 |
|
배포 요청 ID |
chainId |
String |
✅ |
Index |
배포 체인 |
corporateId |
String |
✅ |
Index |
어떤 기업이 배포했는지 |
name / symbol |
String |
✅ |
|
컨트랙트 메타 |
ercStandard |
String ('721' \| '1155') |
✅ |
|
배포 표준 |
contractAddress |
String |
❌ |
Unique + Sparse |
배포 완료 후 채워짐 |
status |
Enum(DEPLOYING,ACTIVE,FAILED) |
✅ |
Index |
Processor 결과 |
currentOwnerAddress |
String |
✅ |
|
초기 owner |
deploymentTxHash |
String |
❌ |
Unique + Sparse |
배포 Tx 해시 |
deploymentGasUsed |
String |
❌ |
|
Wei 단위 |
deploymentGasUsd |
Number |
❌ |
|
당시 USD 환산 |
totalFeeAvax |
String |
❌ |
|
가스 사용량 문자열 |
avaxPriceUsd/avaxPriceKrw |
Number |
❌ |
|
CoinGecko 시세 |
totalFeeUsd/totalFeeKrw |
Number |
❌ |
|
정산 금액 |
royaltyReceiver |
String |
❌ |
|
EIP-2981 설정 |
royaltyFeeBps |
Number |
❌ |
|
Basis Point |
metadataBaseUri |
String |
❌ |
|
배포 직후 설정되는 Base URI |
errorMessage |
String |
❌ |
|
실패 사유 |
createdAt/updatedAt |
Date |
자동 |
|
배포 요청∙갱신 시각 |
4. MintingOrder (mintingOrders)
| 필드 |
타입 |
필수 |
인덱스/제약 |
설명 |
_id |
ObjectId |
자동 |
|
주문 ID |
chainId |
String |
✅ |
Index |
민팅 체인 |
corporateId |
String |
✅ |
Index |
주문 소유 기업 |
contractAddress |
String |
✅ |
Index |
대상 컨트랙트 |
receiverAddress |
String |
✅ |
Index |
수신 지갑 |
tokenId |
String |
❌ |
|
ERC‑721/1155 공통 ID |
amount |
Number |
✅ |
|
기본값 1 (ERC‑1155 수량) |
metadataId |
ObjectId (ref: Metadata) |
✅ |
Index |
민팅에 사용될 Metadata |
status |
Enum(PENDING,PROCESSING,SENT,CONFIRMED,FAILED) |
✅ |
Index |
Bull Processor 단계 |
txHash |
String |
❌ |
Index |
민팅 Tx |
errorMessage |
String |
❌ |
|
실패 사유 |
mintingGasUsed |
String |
❌ |
|
Wei |
mintingGasUsd |
Number |
❌ |
|
USD 환산 |
totalFeeAvax |
String |
❌ |
|
정산용 문자열 |
avaxPriceUsd/avaxPriceKrw |
Number |
❌ |
|
CoinGecko 가격 |
totalFeeUsd/totalFeeKrw |
Number |
❌ |
|
금액 환산 |
createdAt |
Date |
자동(Index) |
|
주문 생성 시각 (잔고 정렬) |
completedAt |
Date |
❌ |
|
CONFIRMED/FAILED 시각 |
updatedAt |
Date |
자동 |
|
상태 변경 추적 |
5. TransferOrder (transferOrders)
| 필드 |
타입 |
필수 |
인덱스/제약 |
설명 |
_id |
ObjectId |
자동 |
|
주문 ID |
chainId |
String |
✅ |
|
체인 |
corporateId |
String |
✅ |
Index |
기업 스코프 |
contractAddress |
String |
✅ |
Index |
NFT 컨트랙트 |
from / to |
String |
✅ |
|
전송 지갑 / 수신 지갑 |
tokenId |
String |
⚠️ |
|
ERC-721 필수, 1155 옵션 |
amount |
Number |
❌ |
|
ERC-1155 수량 (기본 1) |
ercStandard |
'721' \| '1155' |
✅ |
|
프로세서 분기 |
status |
Enum(PENDING,PROCESSING,SENT,CONFIRMED,FAILED) |
✅ |
Index |
Bull Processor 단계 |
txHash |
String |
❌ |
Index |
Forwarder 트랜잭션 |
errorMessage |
String |
❌ |
|
실패 사유 |
forwardRequest |
Object |
❌ |
|
EIP-712 요청 데이터 |
signature |
String |
❌ |
|
eth_signTypedData_v4 결과 |
forwarderAddress |
String |
❌ |
|
실행에 사용된 Forwarder |
gasLimit |
Number |
❌ |
|
Forwarder 실행 가스 한도 |
transferGasUsed |
String |
❌ |
|
Wei |
transferGasUsd |
Number |
❌ |
|
USD 환산 |
totalFeeAvax |
String |
❌ |
|
정산용 문자열 |
avaxPriceUsd/avaxPriceKrw |
Number |
❌ |
|
가격 스냅샷 |
totalFeeUsd/totalFeeKrw |
Number |
❌ |
|
금액 환산 |
completedAt |
Date |
❌ |
|
CONFIRMED/FAILED 시각 |
createdAt/updatedAt |
Date |
자동 |
|
타임스탬프 |
Silent failure 감지를 위해 Processor는 Tx Receipt 내 Transfer 이벤트 유무를 검사하고, 없으면 FAILED 상태와 에러 메시지를 기록합니다.
6. WebhookLog (webhookLogs)
| 필드 |
타입 |
필수 |
인덱스/제약 |
설명 |
_id |
ObjectId |
자동 |
|
웹훅 로그 ID |
eventType |
String |
✅ |
Index |
transfer.success 등 |
targetUrl |
String |
✅ |
|
발송 대상 |
relatedOrderId |
ObjectId (ref: MintingOrder) |
❌ |
Index |
민팅/트랜스퍼 주문 참조 |
relatedContractId |
ObjectId (ref: DeployedContract) |
❌ |
Index |
배포 건 참조 |
payloadSent |
Mixed |
✅ |
|
실제 전송 Body |
status |
Enum(SUCCESS,FAILED,RETRYING) |
✅ |
Index |
Bull 재시도 상태 |
responseStatusCode |
Number |
❌ |
|
수신 서버 HTTP 코드 |
responseBody |
String |
❌ |
|
수신 서버 본문 (트러블슈팅용) |
attempt |
Number |
✅ |
|
재시도 횟수 (기본 1) |
createdAt/updatedAt |
Date |
자동 |
|
@Schema({ timestamps: true }) |
참고
- 모든 주문/컨트랙트 컬렉션에
corporateId가 존재하여 멀티 테넌시를 보장합니다.
- 가스/정산 필드는 Processor가 CoinGecko 시세와 Tx Receipt를 바탕으로 비동기 계산 후 채웁니다.
- Schema 정의는
server/src/common/schemas/ 경로에서 직접 확인할 수 있으며, 변경 시 본 문서를 함께 업데이트해야 합니다.