← 목록
기타 2026-06-25 5KB 읽기 5분

subscribe.crowny.org — 크라우니달러 구독 플랫폼

개요

take.crowny.org 아키텍처를 응용해, "상품구매"가 아니라 구독신청 서비스로 만든 크라우니달러(CD) 기반 구독 플랫폼. 가입 시 2,000 CD 지급 + 매월 150 CD 자동 적립. 그 CD로 서비스를 구독하고, 3개월치(월비용×3)가 있으면 자동 구독 진행, 매월 자동 정산, 잔고 소진 시 회원·운영자 상호 알림.

  • 도메인: https://subscribe.crowny.org (포트 9946, 전용 cert, stunnel 직결)
  • 디렉토리: /Users/ef/crowny-subscribe
  • 순수 Node stdlib(의존성 0) · 밝은 명품 디자인(take style.css 응용)

정책 (SSOT: 구독판정.한선)

  • 가입 보너스 2,000 CD, 매월 150 CD(월키 멱등, 1회 상한 6개월·나머지 이월).
  • 구독 자동진행 조건: 잔고 ≥ 월비용 × 3(3개월치). 신청 시 첫 달 즉시 정산.
  • 월 정산: 한 주기(30일)에 1개월 청구. 같은 달 중복청구 가드(월키). 서버 다운기간은 미과금(사용자 보호).
  • 잔고 소진 → 구독 일시중단(paused) + 상호 알림(회원: 충전요청 / 운영자: 회원 소진). 충전 후 재개(resume).
  • 저잔고(3개월치 미만) 사전 경고(1회).

구성

  • 한선씨 판정 구독판정.한선 — 자동구독판정(3개월버퍼)·월정산판정(소진=음9)·저잔고경고·월지급총액 4상. 8/8 검증. JS 미러.
  • 백엔드 server.js(독립서버) — 지갑 원장(append-only ledger + balance), 매월 자동지급(ensureMonthlyCredit 멱등), 플랜 CRUD, 구독 신청/해지/재개, 정산 엔진(processCycle, 1시간 cron + 수동 run-cycle), 알림(회원+__admin 상호), scrypt 인증·owner 스코핑.
  • 고객 SPA public/index·app·style — 지갑(잔고+거래내역), 구독신청(플랜 카드, 3개월치 안내), 내 구독(상태·다음정산·해지/재개), 알림(벨+미읽음), 회원 게이트.
  • 관리자 public/admin·admin.js — 플랜 관리, 회원·지갑(CD 수동 가감), 구독 현황, 운영 알림, 정산 실행.

검증 (E2E)

  • 1차(8/8): 가입2000·자동구독+첫정산1950·중복409·월700→3개월치2100부족402·내구독active.
  • 2차(8/8): 정산 월차감·소진paused+상호알림·재개·월지급 미수령분 일괄·멱등.
  • 공개 https 200 / 유효 cert.

울트라 적대 감사 (Workflow, 31 에이전트)

5렌즈(원장·권한·경제·멱등·입력) 병렬 리뷰 → 발견 26건 → 독립검증 → 확인 16건. 수정 완료:
  • [HIGH] 관리자 구독목록 owner 비밀토큰 유출 → owner 필드 strip (IDOR 차단). ✅
  • [MED] null 역참조 크래시(삭제계정) → userByOwner null가드 + process uncaughtException. ✅
  • [MED] 정산 catch-up 다중청구(서버다운) → 한 주기 1청구 + now+주기 재설정(다운 미과금). ✅
  • [LOW] 월키 이중청구(스냅샷/시계) → lastBilledMonth 가드. ✅
  • [MED] 월지급 24개월 폭증/소실 → 1회 상한 6 + advanceMonthKey 이월(소실 없음). ✅
  • [MED] 관리자 readBody 전 인증 → adminTok 검사를 readBody 앞으로(plans/credit). ✅
  • [LOW] 해지 알림 누락 → notify(owner) 추가. ✅
  • [LOW] plan.id 무검증/0원 데드플랜 → safeId + 0원 active:false. ✅
  • [HIGH] Sybil(무제한 가입 보너스) → 이메일 중복 차단(부분 완화). CD는 내부통화·환전없음으로 피해 한정. IP 레이트리밋은 향후.

관련 파일

  • /Users/ef/crowny-subscribe/{server.js, 구독판정.한선, public/*}
  • /Users/ef/Library/LaunchAgents/org.crowny.subscribe.plist
  • gateway.yaml(crowny-subscribe) + stunnel-live.conf(s-subscribe-crowny.org, 9946 직결) + cert live/subscribe.crowny.org

잔여 / 운영 메모

  • 관리자 기본 admin/subscribe1004 (plist env SUB_ADMIN_ID/PW) — 반드시 변경.
  • 라이브 게이트웨이(gwhealth 워치독 소유)가 일반 kickstart로 라우트 리로드 안 됨 → subscribe는 take처럼 stunnel 직결로 공개(게이트웨이 8080 라우트는 미반영이나 무관).
  • resume는 일시중단 기간 미과금(정책). 향후: owner 토큰 만료/회전, IP 레이트리밋, 구독별 결제일 알림.

이용권(entitlement) 개발 — "각각의 서비스를 사용할 수 있는 플랫폼" 실현 (2026-06-27)

구독이 실제로 어떤 서비스를 열어주는지 + 다른 크라우니 서비스가 회원 이용권을 확인하는 경로 구축.
  • 한선씨 이용권판정.한선(서비스이용판정 4상: 티 이용가능/옴 일시중단-충전/타 구독없음/음 계정없음, 5/5).
  • 플랜에 services[](여는 서비스, 관리자 쉼표입력) → 구독 시 sub에 스냅샷.
  • 고객: GET /api/me/entitlements(active/paused/subs), GET /api/entitlement?service=(내 세션). 플랜카드·내구독에 서비스 칩 + "내 이용권" 요약.
  • 서비스간 검증: POST /api/entitlement/verify(헤더 X-Service-Key, body {memberId,service}) → {entitled,status,planName,until}. SERVICE_KEY=env SUB_SERVICE_KEY 또는 data/service-key.txt 자동생성.
  • 연동 가이드: 이용권연동.md(JS 헬퍼 포함).
  • E2E 10/10: 서비스저장·콤마파싱·내이용권·서비스체크·서비스간검증(±plan)·없는회원·키불일치403·소진→paused.