20. Lifecycle Events (Add / Edit)

User · Device · Owner identity 의 생성·수정·역할변경·삭제·재인증·이전

핵심 비대칭

Add/Edit vs Delete 의 거버넌스 비대칭

Add / Edit: 모바일 기반 비동기 승인 (Q = Owner + Admin Quorum), 7-day expiry
Delete: 기본 Owner-only, 즉시, mobile approval 없음

User Lifecycle

EventActor승인비고
Add (Console / API)본문: O / A / NSA
권한표: + SecAdmin (불일치)
Q (Owner + Admin Quorum), 7-day expiryOwner counting rule 적용
Add (signing role)위 + Owner위 + Owner 가 MPC key share derivation 별도 승인두 승인 모두 받아야 active
Edit (name/email)"Admin-level users"Q (Approval groups 로 customize 가능)workspace 내 email UNIQUE. Owner 본인은 name/email 변경 불가 → Transfer 절차
Role changeConsole 직접 변경 ✗Option A: delete + re-add / Option B: Fireblocks Support 요청
Delete (default)Owner즉시, mobile approval 불요access 즉시 박탈. Policy/Quorum 의존성 사전 검증 필요
Delete (위임)Admin (AG)Settings > Quorums > Approval groups 에서 Owner 요구 토글 OFF

Device Lifecycle

EventActor승인비고
Re-enroll mobile deviceOwner / Admin / NSA / Security AdminOwner approval (2-day window) + 사용자 재등록 (2-day window)signing role 의 경우 MPC key share 재승인 추가
Device migration사용자 본인 self-service관리자 승인 없이 PIN + passphrase + biometric 3중(Stage 5)
2FA reset (타인)Owner (+ Security Admin per 권한표)본인 reset 불가
2FA reset (Owner 본인)Fireblocks Support영상 통화 신원 확인Console 불가
Recovery passphrase reset (Admin/Signer)본인Mobile app self-reset (PIN + new passphrase + biometric)
Recovery passphrase reset (Owner)본인 + Fireblocks Support+ 기존 recovery package 파기 + 새 package 요청Offline backup / Third-party DRS 분기

Workspace Lifecycle

EventActor비고
FreezeOwner / Admin / NSA / Security Admin모든 role 이 Viewer 로 강제 변경, transfer / whitelisting / connection 차단. Incoming transfer 는 계속 수신
UnfreezeOwner only via Fireblocks SupportConsole 불가, 영상 통화 신원 확인 필수
Transfer Owner (current Owner 참여)Fireblocks Support양 Owner 영상 통화, 신임 Owner 의 recovery passphrase verify, 3-5 영업일
Transfer Owner (current Owner 부재)Board resolution + stakeholder quorum이사회 결의로 신임 Owner 지명

DB Schema

-- ★ append-only — lifecycle 이력은 audit-grade
CREATE TABLE lifecycle_events (
  id                BINARY(16) PRIMARY KEY,
  workspace_id      BINARY(16) NOT NULL,
  event_type        VARCHAR(64) NOT NULL,              -- 'user-add', 'user-edit', 'user-delete',
                                                       --  'device-re-enroll', 'device-migration',
                                                       --  '2fa-reset', 'passphrase-reset',
                                                       --  'workspace-freeze', 'workspace-unfreeze',
                                                       --  'owner-transfer'
  target_aggregate_type VARCHAR(64) NOT NULL,          -- 'user', 'device', 'workspace'
  target_aggregate_id BINARY(16) NOT NULL,
  actor_user_id     BINARY(16),                        -- self-service 면 target 와 같음
  via_support_ticket VARCHAR(64),                       -- Fireblocks Support 경유 증빙
  approval_request_id BINARY(16),                       -- Q / Q+O 흐름의 approval
  signing_role_extra_approval BOOLEAN NOT NULL DEFAULT FALSE,   -- MPC derivation 별도 승인 여부
  initiated_at      DATETIME(6) NOT NULL,
  completed_at      DATETIME(6),                       -- ★ set-once
  KEY (workspace_id, event_type, initiated_at),
  KEY (target_aggregate_id)
);

CREATE TABLE user_setup_progress (
  user_id           BINARY(16) PRIMARY KEY,
  invited_at        DATETIME(6) NOT NULL,
  mobile_paired_at  DATETIME(6),
  mpc_key_approved_at DATETIME(6),                     -- ★ Owner 의 별도 승인
  activated_at      DATETIME(6),                       -- ★ set-once
  expires_at        DATETIME(6) NOT NULL                -- 7-day expiry
);

Status 전이

users.status:
  pending → active        (initial setup 완료)
  active  → deleted       (즉시 박탈, row 유지)
  active  → frozen-viewer (workspace freeze 시 implicit)
  frozen-viewer → active  (Owner unfreeze via Support)