← 목록
기타 2026-06-10 4KB 읽기 4분

finance.crowny.org 초대 서비스 하드닝 — 완료

개요

초대 바이럴 서비스 감사가 잡아낸 리스크 3건을 근본 수정. 울트라 워크플로우 6에이전트(설계2→구축2→수리→검증2) + 직접 캡 가드 추가. 독립 재검증 통과.

1. 회전 WAL 영속화 (재시작 복원 + 재지급 방지)

  • WAL 레코드 4종(append-only, 해시만 저장): P(본인폰등록) / S(연락처 sync) / J(가입+보상 원자결합 paid=0/1) / L(원장). 파이프 구분, 줄이스케이프.
  • 회전 파트: data/invite-wal.pN.dat 각 <12KB(WAL_PART_MAX, STR_MAX_LEN 16KB 안전여유). invite-wal.meta.dat = part|byteoffset|seq. 임계 초과 시 자동 파트 회전.
  • 부팅 replay: 초대로드()가 p0,p1,… 순차 읽기(없는 파일 글자수 가드) → 초대DB+원장+멱등마커(_joined_/_pair_/_SLOT_보상/_self_) 결정론적 재구성. 서버 init(접수로드 직후) 연결.
  • 재지급 0: 보상 발생 시에만 J(paid=1)/L 기록 → replay가 정확히 1회 재현. 재시작 후 동일 가입 재유입 시 _joined_ 적중 → 0맘.

독립 검증 (실측)

sync itZ(selfPhone, 큐) → join 큐 → itZ +1맘
백엔드 kill → 재기동 → "[load] 초대WAL 82레코드 replay" → rewards/itZ momEarned=1 (영속!)
re-join 큐 → firstJoin:false, rewarded:[], skipped:already_joined → 재지급 0
WAL 회전: p0/p1/p2 각 <4KB, 78~83 레코드 cross-part replay 정상
PII: WAL 평문 폰 0건(SHA256 해시+마스킹명만)

2. 자가가입 보상 차단 (selfPhone 필수화)

  • /api/invite/syncselfPhone 필수(누락 <4자 → HTTP 400 SELF_PHONE_REQUIRED, 동기화 미수행).
  • 본인폰등록() 강화: 무효 -1, 같은 user 다른 해시 -2(immutable), _self_<user>+_owner_<해시> 세팅 후 WAL P 기록.
  • 가입처리 보상 게이트: hash(가입폰)==_self_<등록자> → 자가=1 스킵, _owner_<해시>==등록자 → 순환차단, _self_ 미등록 → 미검증=1 보상보류. 보상 = 이미보상0 AND firstJoin1 AND 자가0 AND 미검증0. skipped[{registrant,reason}] 응답.
  • 본인 번호를 contact로 등록도 거부(연락처등록 r==-2).
  • 프론트: 동기화 카드에 "내 전화번호(본인 인증용)" 필드 추가, sync 바디 selfPhone 포함(localStorage cfInviteSelfPhone).

검증: 자가contact 거부 / 자가가입 무보상 / selfPhone 400 / 정상 +1맘 멱등 — 5/5 PASS.

3. 연락처 캡 가드 (대량 sync 크래시 방지 — 직접 추가)

  • 검증이 발견: 200건 단일 sync가 16KB/누적틱 한계로 백엔드 silent death(~75건 후).
  • 연락처동기화()최대 30건/요청 처리 상한. 초과 시 capped:1+maxPerSync:30 반환 → 클라이언트 분할 재전송 유도.
  • 검증: 40건 sync → registered:30, capped:1, 백엔드 생존(health ok), 회귀 정상.

관련 파일

  • 백엔드: /Users/ef/crowny-finance/src/크라우니파이낸스.한선 (초대로드/walAppend/walReplay, 본인폰등록 강화, 가입처리 게이트, 연락처동기화 캡). 3.07MB toau, compile exit 0.
  • 프론트: web/assets/chat.js (selfPhone 필드), chat.css
  • 데이터: data/invite-wal.pN.dat + invite-wal.meta.dat (회전 WAL)
  • 실행: 백엔드 :9750(/tmp/finance2.toau), 프록시 :9754. 단일 인스턴스.

운영 메모

  • 검증 중 watchdog(pid 1884)가 /tmp/crowny-finance.toau로 중복 백엔드를 :9750에 띄워 테스트 오염 → watchdog SERVICES에 finance 직접 항목은 없으나 monitor(9743) 관리 중. 현재 단일 백엔드 확인.
  • 남은 한계(설계상): 인메모리+WAL 하이브리드라 WAL이 단일 진실원. WAL 파일 손상 시 복원 불가 → 주기적 백업 권장. 대규모(수천 사용자)는 파트 수 증가로 부팅 replay 지연 가능 → 스냅샷 compaction 후속.