크라우니메일 v3 백엔드 (모듈 M1)
개요
/Users/ef/crowny-mail/크라우니메일서버.한선 v2.0.0(1115줄, 해시체인 원장)을 v3.0.0(2138줄)으로
확장. 작업계획-v3.md "API 계약 v3"의 전 API + 보안 게이트 서버측 강제 +
/demo(무인증) 구현.
기존 v2 API·데이터 구조는 전부 하위호환 유지(추가만, 삭제/변경 없음).
무엇을 했는지
- DB 확장: 메일 레코드에 gate/tier스냅/mam/canvas/외부/when 6개 배열 추가(병렬 인덱스).
연락처(전사 공유 주소록, 오너 컬럼 없음 — 크라우니네임 실연동 전 로컬 근사) / 맘 지갑
(기본값 함수형: kps=120, 나머지 0, 실제 잔고만 배열 저장) / 감사 로그 / 사용자별 설정
4개 신규 DB를 배열로 추가.
- 원장 이벤트 11종 신규: CONTACT_SET/GATE_ACCEPT/GATE_BLOCK/MAM_CREDIT/MAM_DEBIT/OPENED/
AUDIT/SETTING_SET/PURGE/DRAFT/SCHEDULE. 기존 MAIL_SEND(6필드)는 필드수 분기로 신 12필드
포맷과 공존(리플레이시 신필드는 기본값). 전부 리플레이 가능하게
_적용_* 함수로 순수
상태변경 로직 분리(라이브/리플레이 공용).
- 게이트 상태머신: 미연결 크라우니 발신자→gate=waiting, accept(tier)→해당 발신자
waiting 전량 inbox 편입+연락처 upsert, block→차단(이후 수신 자동 폐기, AUDIT만).
waiting 발신자에게 먼저 답장 시도→403(서버측 강제).
- 맘: 발송시 보유검사+MAM_DEBIT, 수신자 최초 열람시 MAM_CREDIT(읽음 플래그로 멱등 —
재열람 재적립 없음, 실측 확인).
- API 전체 구현: /api/mail/list(box/tier/filter+counts), /api/mail/read(확장,
chainBlock/chainTx/tierAtReceipt), /api/mail/send(mam/canvas/mode send|draft|schedule),
/api/mail/delete(1차 trash·2차 PURGE), /api/contacts(+tier+memo),
/api/gate/accept·block, /api/relationship, /api/wallet, /api/audit, /api/policy(Tier
표), /api/settings(GET/POST), /api/setup/status·setup, /demo.
- 핵심 함정 발견·수리:
/demo가 서빙할 pages/앱v3.html이 113KB로 hanseonc_high의
읽기()/문자열 65535B 캡(STR_MAX_LEN)을 초과 — 최초 구현은 65457B에서 조용히 절단된
깨진 HTML을 서빙하고 있었음(에러 없음, curl로 바이트수 대조해 발견).
체계("wc -c ...")로
실파일 크기를 먼저 판정하고, 60000B 초과시 헤더만 문자열로 쓰고 본문은
파일소켓전송(클라,경로)(원시 바이트, 문자열 계층 우회)으로 스트리밍하도록 수리.
이를 위해
처리(요청) →
처리(요청, 클라)로 시그니처 확장, 메인루프는 빈 문자열
반환시(이미 소켓에 직접 씀) 재전송 안 하도록 가드 추가. 수리 후 113429B byte-perfect
스트리밍 실측 확인(diff 무차이).
관련 파일
/Users/ef/crowny-mail/크라우니메일서버.한선 (v3.0.0, 2138줄) — 유일 수정 파일
- 컴파일 산출물:
/tmp/메일v3.toau (라이브 미배포, /Users/ef/crowny-mail/크라우니메일서버.toau는 무접촉)
- 참조:
/Users/ef/crowny-mail/설계/작업계획-v3.md, /Users/ef/Downloads/design_handoff_크라우니메일/docs/11-크라우니메일-개발자문서.md
검증 결과
CROWNY_STRICT=1 hanseonc_high 컴파일 경고 0.
- 빈 원장 기동(
/tmp/mail-v3-test/): 시드 5계정 정상 생성.
- 라이브 원장 하위호환 리허설(
/tmp/mail-v3-compat/, 라이브 디렉토리 사본, 원본 무접촉):
유저5·메일2 리플레이 성공, kps 로그인 OK, chain/verify OK, 레거시
/api/mail/inbox·
/api/users·mail-bridge 스타일 단순
/api/mail/send 전부 정상.
- 신규 API 전수 curl E2E: list(box/tier/filter 조합) PASS, send(일반/맘동봉/외부/draft/
schedule) PASS, 미연결 크라우니 시나리오(신규유저→waiting→accept→inbox편입+counts
재계산) PASS, block 시나리오(폐기+AUDIT만) PASS, 맘 열람 적립 멱등(2회 열람 잔고 불변)
PASS, contacts(tier/memo) PASS, audit/policy/settings/setup/relationship/wallet PASS,
/demo 200(113429B byte-perfect) PASS.
- 보안 게이트 3종: waiting 발신자 답장 403 PASS, 맘 부족 400 PASS, 세션 없음 401 PASS.
- 리부트 리플레이: kill→재기동, 지갑잔고·연락처·게이트·설정·purge 상태 전부 복원 확인,
chain/verify ok(height 38) 유지.
- 부수 발견 버그 1건 자체 수정:
/api/relationship·/api/contacts의 mamReceived가
발신자 자신의 sent/drafts/scheduled 사본까지 집계해 이중계상되던 것을 폴더 필터로 수정.
잔여 이슈 / 알려진 한계
- 연락처(관계) DB가 "오너 컬럼 없음"(전사 공유 글로벌 주소록)으로 단순화됨 — API 계약에
email별 owner 필드가 없어 이렇게 설계했으나, 차후 진짜 크라우니네임 연동 시(계약에도
"로컬 계산; 크라우니네임 연동은 후속" 명시) 사용자별 관계 스코프로 갈라야 할 수 있음.
- 첨부파일 업로드 API가 계약에 없어
attach 필드는 항상 0 고정, waiting 게이트의
"첨부 거부" 규칙은 답장 403만 구현(첨부 자체가 없어 N/A).
- 메일 배열은 v2와 동일하게 1023 요소 상한(hanseonc_high 배열 캡) 상속 — 대량 운영시
샤딩 필요(이번 범위 밖).
읽기() 64KB 캡 함정은 /demo 한 곳만 수리. /(app.html)·/login(login.html)은
현재 각 11.5KB/2.4KB로 안전하나, 향후 커지면 동일 패턴(
_대용량HTML전송) 적용 필요.
크라우니코드
lookup HIT 0건 / MISS(직접생성) 다수(신규 게이트/맘/원장 로직) / learn 추가 2건
(
fn_메일게이트_웨이팅편입,
fn_메일게이트_맘멱등적립).