Phase 3: Membloc Publisher Portal — 외부 사업체 온보딩
외부 사업체(퍼블리셔)가 모듈을 등록하고, 심사를 거쳐 마켓플레이스에 게시할 수 있는 전체 파이프라인을 구축한다.
1. 목표
- Publisher 등록/인증 플로우
- Publisher Dashboard (웹 관리 도구)
- 모듈 심사 시스템 (Admin)
- Webhook 시스템
- Module SDK 문서 사이트
- API 키 관리
2. 퍼블리셔 온보딩 플로우
사업체 개발자
│
▼
[1] developer.membloc.com 접속
│
▼
[2] Firebase Auth 로그인 (Google/Email)
│
▼
[3] 퍼블리셔 등록 신청
├── 사업체명
├── 사업자등록번호 (선택)
├── 담당자 이메일
├── 웹사이트
└── 개발 목적 설명
│
▼
[4] Membloc 팀 심사 (1~3 영업일)
├── 승인 → status: approved
└── 반려 → 사유 안내 이메일
│
▼
[5] 승인 후 Publisher Dashboard 접근
├── 모듈 등록
├── API 키 발급
├── 버전 관리
└── 분석 대시보드
3. Publisher Dashboard
3.1 기술 스택
프레임워크: Next.js (App Router)
UI: Tailwind CSS + shadcn/ui
인증: Firebase Auth (Google 로그인)
API: Membloc backend REST API
호스팅: Vercel 또는 Cloudflare Pages
경로: developer.membloc.com
3.2 화면 구성
developer.membloc.com
├── / ─────────────────── 랜딩 (문서 + 시작하기)
├── /login ────────────── Firebase Auth 로그인
├── /register ─────────── 퍼블리셔 등록 신청
├── /dashboard ────────── 대시보드 홈
│ ├── 총 설치 수
│ ├── 활성 모듈 수
│ ├── 평균 평점
│ └── 최근 7일 설치 추이 차트
├── /modules ──────────── 내 모듈 목록
│ ├── [생성] 버튼
│ └── 모듈 카드 (상태 배지: draft/review/published)
├── /modules/new ──────── 모듈 생성
│ ├── Step 1: 기본 정보 (name, key, description, category)
│ ├── Step 2: 기술 설정 (type, entry_url, permissions)
│ ├── Step 3: 스크린샷 + 상세 설명
│ └── Step 4: 확인 + 심사 제출
├── /modules/:key ─────── 모듈 상세/수정
│ ├── 기본 정보 편집
│ ├── 버전 관리 탭
│ │ ├── 현재 버전
│ │ ├── 버전 히스토리
│ │ └── [새 버전 제출]
│ ├── 분석 탭
│ │ ├── 일별 설치/해제 차트
│ │ ├── 활성 설치 수
│ │ ├── API 호출 통계
│ │ └── 에러율
│ ├── API 키 탭
│ │ ├── 키 목록
│ │ ├── [발급] / [폐기]
│ │ └── 마지막 사용 시간
│ └── Webhook 탭
│ ├── 등록된 이벤트
│ ├── [추가] / [삭제]
│ └── 발송 로그
├── /docs ─────────────── SDK 문서 (임베디드)
└── /settings ─────────── 퍼블리셔 설정
├── 프로필 수정
├── 팀 멤버 관리
└── 알림 설정
3.3 모듈 생성 플로우 상세
Step 1: 기본 정보
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
| Module Key | text | O | 역도메인 형식 (com.company.module-name) |
| Display Name | text | O | 한국어 모듈명 (최대 30자) |
| Description | text | O | 한 줄 설명 (최대 100자) |
| Long Description | markdown | - | 상세 설명 |
| Category | select | O | 카테고리 선택 |
| Tags | chips | - | 검색용 태그 (최대 5개) |
Step 2: 기술 설정
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
| Module Type | radio | O | WebView / Server |
| Entry URL | url | WebView만 | 모듈 진입 URL |
| Permissions | checkbox | O | 요청할 권한 목록 |
| Min Membloc Version | semver | - | 최소 앱 버전 |
| Settings Schema | JSON editor | - | 모듈 설정 스키마 |
| Webhook Events | checkbox | - | 구독할 이벤트 |
Step 3: 에셋
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
| Icon | image upload | O | 512x512 PNG |
| Screenshots | image upload | O | 최소 2장, 최대 8장 |
| Privacy Policy URL | url | O | 개인정보처리방침 |
| Support URL | url | O | 고객지원 페이지 |
4. 심사 시스템
4.1 심사 기준
| 카테고리 | 체크 항목 |
|---|---|
| 기능 | entry_url 접근 가능, 주요 기능 정상 동작 |
| 보안 | HTTPS 필수, 불필요한 권한 요청 없음, 데이터 수집 범위 적정 |
| 콘텐츠 | 불법/유해 콘텐츠 없음, 광고 과다 아님 |
| UX | Membloc 앱 내에서 자연스러운 UI, 로딩 속도 5초 이내 |
| 메타데이터 | 스크린샷과 실제 화면 일치, 설명 정확 |
| 개인정보 | privacy_policy_url 유효, 수집 항목 명시 |
4.2 심사 상태 흐름
draft ──[제출]──▶ review ──[승인]──▶ published
│ │
│ [반려] │ [정지]
▼ ▼
rejected suspended
│ │
│ [재제출] │ [해제]
▼ ▼
review published
4.3 Admin Dashboard
Membloc 팀이 심사에 사용하는 내부 도구.
admin.membloc.com (또는 developer.membloc.com/admin)
├── /admin/reviews ──────── 심사 대기 목록
│ ├── 모듈별 상세 보기
│ │ ├── manifest 내용
│ │ ├── 스크린샷
│ │ ├── entry_url 프리뷰 (iframe)
│ │ ├── 요청 권한 목록
│ │ └── 퍼블리셔 정보
│ ├── [승인] + 코멘트
│ └── [반려] + 사유
├── /admin/modules ──────── 전체 모듈 관리
│ ├── 상태별 필터
│ ├── [정지] / [해제]
│ └── 강제 버전 롤백
├── /admin/publishers ───── 퍼블리셔 관리
│ ├── 승인 대기 목록
│ ├── [승인] / [반려]
│ └── [정지]
└── /admin/stats ────────── 플랫폼 통계
├── 총 모듈 수 / 퍼블리셔 수
├── 일별 설치 추이
└── 카테고리별 분포
5. 백엔드 확장
5.1 데이터베이스 마이그레이션
migrations/005_publisher_portal.up.sql
-- 퍼블리셔 팀 멤버
CREATE TABLE publisher_members (
id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
publisher_id TEXT NOT NULL REFERENCES publishers(id) ON DELETE CASCADE,
firebase_uid TEXT NOT NULL,
email TEXT NOT NULL,
role TEXT NOT NULL DEFAULT 'member'
CHECK (role IN ('owner','admin','member')),
invited_at TIMESTAMPTZ NOT NULL DEFAULT now(),
accepted_at TIMESTAMPTZ,
UNIQUE(publisher_id, firebase_uid)
);
-- 모듈 스크린샷
CREATE TABLE module_screenshots (
id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
module_id TEXT NOT NULL REFERENCES modules(id) ON DELETE CASCADE,
image_url TEXT NOT NULL,
sort_order INTEGER NOT NULL DEFAULT 0,
caption TEXT
);
-- 심사 로그
CREATE TABLE module_review_logs (
id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
module_id TEXT NOT NULL REFERENCES modules(id),
version_id TEXT REFERENCES module_versions(id),
reviewer_uid TEXT NOT NULL,
action TEXT NOT NULL CHECK (action IN ('submitted','approved','rejected','suspended','unsuspended')),
comment TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- Webhook 구독
CREATE TABLE module_webhooks (
id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
module_key TEXT NOT NULL,
event_type TEXT NOT NULL,
target_url TEXT NOT NULL,
secret TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'active'
CHECK (status IN ('active','disabled')),
failure_count INTEGER NOT NULL DEFAULT 0,
last_triggered_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX idx_webhooks_module ON module_webhooks(module_key);
CREATE INDEX idx_webhooks_event ON module_webhooks(module_key, event_type);
-- Webhook 발송 로그
CREATE TABLE webhook_delivery_logs (
id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
webhook_id TEXT NOT NULL REFERENCES module_webhooks(id),
event_type TEXT NOT NULL,
payload JSONB NOT NULL,
response_status INTEGER,
response_body TEXT,
delivered_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- 모듈 일별 통계
CREATE TABLE module_daily_stats (
module_key TEXT NOT NULL,
stat_date DATE NOT NULL,
installs INTEGER NOT NULL DEFAULT 0,
uninstalls INTEGER NOT NULL DEFAULT 0,
api_calls INTEGER NOT NULL DEFAULT 0,
errors INTEGER NOT NULL DEFAULT 0,
PRIMARY KEY (module_key, stat_date)
);
5.2 새로운 API 엔드포인트
# === Publisher API ===
# 인증: Firebase Auth (퍼블리셔 계정)
POST /api/publisher/register # 퍼블리셔 등록 신청
GET /api/publisher/profile # 내 퍼블리셔 정보
PUT /api/publisher/profile # 프로필 수정
# 팀 관리
GET /api/publisher/members # 팀 멤버 목록
POST /api/publisher/members/invite # 멤버 초대
DELETE /api/publisher/members/:uid # 멤버 제거
# 모듈 관리
GET /api/publisher/modules # 내 모듈 목록
POST /api/publisher/modules # 모듈 생성 (draft)
PUT /api/publisher/modules/:key # 모듈 수정
DELETE /api/publisher/modules/:key # 모듈 삭제 (draft만)
POST /api/publisher/modules/:key/submit # 심사 제출
# 버전
GET /api/publisher/modules/:key/versions # 버전 목록
POST /api/publisher/modules/:key/versions # 새 버전 제출
GET /api/publisher/modules/:key/versions/:ver # 버전 상세
# API 키
GET /api/publisher/modules/:key/api-keys # 키 목록
POST /api/publisher/modules/:key/api-keys # 키 발급
DELETE /api/publisher/modules/:key/api-keys/:id # 키 폐기
# Webhook
GET /api/publisher/modules/:key/webhooks # 구독 목록
POST /api/publisher/modules/:key/webhooks # 구독 추가
DELETE /api/publisher/modules/:key/webhooks/:id # 구독 삭제
GET /api/publisher/modules/:key/webhooks/:id/logs # 발송 로그
# 분석
GET /api/publisher/modules/:key/analytics # 통계 요약
GET /api/publisher/modules/:key/analytics/daily # 일별 통계
?from=2026-03-01&to=2026-04-01
# === Admin API ===
# 인증: Firebase Auth (Membloc 팀 — admin role)
GET /api/admin/publishers/pending # 승인 대기 퍼블리셔
POST /api/admin/publishers/:id/approve # 퍼블리셔 승인
POST /api/admin/publishers/:id/reject # 퍼블리셔 반려
GET /api/admin/modules/pending # 심사 대기 모듈
POST /api/admin/modules/:key/approve # 모듈 승인
POST /api/admin/modules/:key/reject # 모듈 반려
POST /api/admin/modules/:key/suspend # 모듈 정지
POST /api/admin/modules/:key/unsuspend # 모듈 정지 해제
GET /api/admin/stats # 플랫폼 통계
5.3 Webhook 시스템
지원 이벤트:
| 이벤트 | 트리거 시점 |
|---|---|
module.installed | 가족이 모듈을 설치했을 때 |
module.uninstalled | 가족이 모듈을 제거했을 때 |
module.settings_changed | 모듈 설정이 변경됐을 때 |
family.member_joined | 가족에 새 멤버가 추가됐을 때 |
family.member_left | 가족에서 멤버가 나갔을 때 |
발송 프로토콜:
POST {target_url}
Content-Type: application/json
X-Membloc-Signature: sha256={HMAC-SHA256(payload, secret)}
X-Membloc-Event: module.installed
X-Membloc-Delivery: {delivery_id}
{
"event": "module.installed",
"timestamp": "2026-04-10T12:00:00Z",
"data": {
"moduleKey": "com.example.budget",
"familyId": "fam_xxx",
"installedBy": "uid_xxx",
"version": "1.2.0"
}
}
X-Membloc-*를 primary로 문서화하고, alias 기간 동안 X-Homb-*도 함께 송신한다.
재시도 정책:
- 실패 시 3회 재시도 (10초, 60초, 300초 간격)
- 연속 10회 실패 → webhook status를
disabled로 변경 - 퍼블리셔에게 이메일 알림
5.4 백엔드 파일 구조 추가
internal/
├── handler/
│ ├── publisher.go # [신규] 퍼블리셔 CRUD
│ ├── publisher_module.go # [신규] 퍼블리셔의 모듈 관리
│ ├── admin.go # [신규] Admin 심사/관리
│ └── webhook.go # [신규] Webhook 관리
├── model/
│ ├── publisher_member.go # [신규]
│ ├── review_log.go # [신규]
│ ├── webhook.go # [신규]
│ └── daily_stats.go # [신규]
├── repository/
│ ├── publisher.go # [신규]
│ ├── review_log.go # [신규]
│ ├── webhook.go # [신규]
│ └── daily_stats.go # [신규]
├── service/
│ ├── publisher.go # [신규]
│ ├── review.go # [신규]
│ ├── webhook_dispatcher.go # [신규] 이벤트 발생 시 webhook 발송
│ └── analytics.go # [신규]
├── auth/
│ └── admin_middleware.go # [신규] admin role 체크
6. SDK 문서 사이트
6.1 호스팅
docs.membloc.com 또는 developer.membloc.com/docs
6.2 문서 구조
시작하기
├── 퍼블리셔 등록
├── 첫 모듈 만들기 (튜토리얼)
└── 개발 환경 설정
모듈 타입
├── WebView 모듈
│ ├── 구조
│ ├── JS Bridge SDK
│ └── 로컬 개발 & 테스트
└── Server 모듈
├── REST API
├── Webhook
└── API 키 관리
JS Bridge API 레퍼런스
├── homb.auth
├── homb.family
├── homb.data
├── homb.storage
├── homb.notifications
├── homb.activity
├── homb.ui
└── homb.settings
REST API 레퍼런스
├── 인증
├── 모듈 데이터 CRUD
├── 액티비티
└── 알림
가이드
├── 권한 모델
├── 데이터 샌드박싱
├── 에러 처리
├── Rate Limiting
└── 심사 가이드라인
변경 로그
6.3 기술 스택
VitePress 또는 Docusaurus
Markdown + OpenAPI spec
코드 예제: TypeScript (WebView), cURL (REST)
7. 작업 목록
7.1 백엔드
| # | 작업 | 의존성 | 예상 |
|---|---|---|---|
| B1 | 005_publisher_portal.up.sql 마이그레이션 | Phase 2 완료 | 0.5d |
| B2 | Publisher CRUD (model, repo, service, handler) | B1 | 2d |
| B3 | Publisher 인증 미들웨어 (Firebase UID → publisher 매핑) | B2 | 0.5d |
| B4 | Publisher 모듈 관리 API | B3 | 2d |
| B5 | 버전 관리 API | B4 | 1d |
| B6 | Admin 미들웨어 + 심사 API | B1 | 2d |
| B7 | 심사 로그 기록 | B6 | 0.5d |
| B8 | API 키 발급/검증/폐기 | B1 | 1d |
| B9 | Webhook 등록/삭제 API | B1 | 1d |
| B10 | Webhook dispatcher (비동기 발송 + 재시도) | B9 | 2d |
| B11 | 모듈 설치/제거 시 webhook 트리거 연동 | B10 | 0.5d |
| B12 | 일별 통계 집계 (cron 또는 트리거) | B1 | 1d |
| B13 | 분석 API | B12 | 0.5d |
| B14 | 스크린샷 업로드 (Firebase Storage 연동) | - | 1d |
7.2 Publisher Dashboard (웹)
| # | 작업 | 의존성 | 예상 |
|---|---|---|---|
| W1 | Next.js 프로젝트 scaffolding + Firebase Auth | - | 0.5d |
| W2 | 로그인 / 퍼블리셔 등록 페이지 | W1, B2 | 1d |
| W3 | 대시보드 홈 (통계 카드 + 차트) | W1, B13 | 1d |
| W4 | 모듈 목록 페이지 | W1, B4 | 0.5d |
| W5 | 모듈 생성 위저드 (4 step) | W1, B4 | 2d |
| W6 | 모듈 상세/수정 페이지 | W5 | 1d |
| W7 | 버전 관리 탭 | W6, B5 | 1d |
| W8 | API 키 관리 탭 | W6, B8 | 0.5d |
| W9 | Webhook 관리 탭 | W6, B9 | 1d |
| W10 | 분석 탭 (차트) | W6, B13 | 1d |
| W11 | Admin 심사 페이지 | W1, B6 | 1.5d |
| W12 | Admin 퍼블리셔 관리 | W1, B6 | 0.5d |
7.3 SDK 문서
| # | 작업 | 예상 |
|---|---|---|
| D1 | VitePress 프로젝트 셋업 | 0.5d |
| D2 | 시작하기 가이드 | 1d |
| D3 | JS Bridge API 레퍼런스 | 1d |
| D4 | REST API 레퍼런스 (OpenAPI) | 1d |
| D5 | 튜토리얼: 첫 WebView 모듈 만들기 | 1d |
| D6 | 권한 / 샌드박싱 / Rate Limiting 가이드 | 0.5d |
| D7 | 심사 가이드라인 | 0.5d |
8. 완료 기준
- 외부 개발자가
developer.membloc.com에서 퍼블리셔 등록 가능 - 퍼블리셔가 모듈을 생성하고 심사에 제출 가능
- Membloc 팀이 Admin에서 모듈을 승인/반려 가능
- 승인된 모듈이 마켓플레이스에 자동 게시
- API 키 발급 후 Server Module이 Runtime API 호출 가능
- Webhook 등록 후 모듈 설치 시 이벤트 수신 확인
- 퍼블리셔 대시보드에서 설치 통계 확인 가능
- SDK 문서 사이트에서 API 레퍼런스 열람 가능