CarboAny / database /migrations /002_organizations_users.sql
Esketch's picture
deploy: [P4] Strangler Pattern API Adapter Release (Orphan Clean Build v2)
daaf9d7
Raw
History Blame Contribute Delete
5.67 kB
-- ============================================================================
-- Carboany Harness System β€” 쑰직 및 μ‚¬μš©μž μŠ€ν‚€λ§ˆ
-- Migration: 002_organizations_users
--
-- 섀계 원칙:
-- 1. UUID PK: λΆ„μ‚° μ‹œμŠ€ν…œ ν™•μž₯μ„± 확보
-- 2. μ—­ν•  기반 μ ‘κ·Ό μ œμ–΄: role 컬럼으둜 Admin/Sponsor/Participant/SME ꡬ뢄
-- 3. OAuth μ†Œμ…œ 둜그인: 별도 ν…Œμ΄λΈ”λ‘œ 닀쀑 ν”„λ‘œλ°”μ΄λ” 지원
-- 4. API ν‚€ ν•΄μ‹œ μ €μž₯: 원본 ν‚€λŠ” λ°œκΈ‰ μ‹œ 1회만 λ…ΈμΆœ
-- ============================================================================
-- ────────────────────────────────────────────────────────────────────────────
-- 1. 쑰직 (Organizations)
-- μ§€μžμ²΄, 곡곡기관, λŒ€κΈ°μ—…(μŠ€ν°μ„œ), μ€‘μ†ŒκΈ°μ—…(SME) 톡합 관리
-- ────────────────────────────────────────────────────────────────────────────
CREATE TABLE organizations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(200) NOT NULL,
type VARCHAR(20) NOT NULL
CHECK (type IN ('municipality', 'public_corp', 'government', 'enterprise', 'sme')),
parent_id UUID REFERENCES organizations(id), -- SME β†’ μŠ€ν°μ„œ 계측 관계 (nullable)
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP NOT NULL,
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP NOT NULL
);
CREATE INDEX idx_org_type ON organizations(type);
CREATE INDEX idx_org_parent ON organizations(parent_id) WHERE parent_id IS NOT NULL;
-- ────────────────────────────────────────────────────────────────────────────
-- 2. μ‚¬μš©μž (Users)
-- 4개 도메인 μ—­ν• : admin, sponsor_mgr, participant, sme_mgr
-- ────────────────────────────────────────────────────────────────────────────
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255), -- OAuth μ „μš© μ‚¬μš©μžλŠ” NULL κ°€λŠ₯
name VARCHAR(100) NOT NULL,
role VARCHAR(20) NOT NULL
CHECK (role IN ('admin', 'sponsor_mgr', 'participant', 'sme_mgr')),
org_id UUID REFERENCES organizations(id),
phone VARCHAR(20), -- 본인 인증용 (λͺ¨λ°”일)
avatar_url VARCHAR(500),
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP NOT NULL,
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP NOT NULL
);
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_org ON users(org_id) WHERE org_id IS NOT NULL;
CREATE INDEX idx_users_role ON users(role);
-- ────────────────────────────────────────────────────────────────────────────
-- 3. OAuth μ†Œμ…œ 둜그인 μ—°κ²° (OAuth Connections)
-- Google, 카카였, 넀이버, μ •λΆ€ SSO 닀쀑 ν”„λ‘œλ°”μ΄λ” 지원
-- ────────────────────────────────────────────────────────────────────────────
CREATE TABLE oauth_connections (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
provider VARCHAR(30) NOT NULL
CHECK (provider IN ('google', 'kakao', 'naver', 'gov_sso')),
provider_id VARCHAR(255) NOT NULL,
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP NOT NULL,
UNIQUE (provider, provider_id)
);
CREATE INDEX idx_oauth_user ON oauth_connections(user_id);
-- ────────────────────────────────────────────────────────────────────────────
-- 4. API ν‚€ (API Keys)
-- μ™ΈλΆ€ μ‹œμŠ€ν…œ μ—°λ™μš©, ν•΄μ‹œ μ €μž₯, 레이트 리밋 관리
-- ────────────────────────────────────────────────────────────────────────────
CREATE TABLE api_keys (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
org_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
key_hash VARCHAR(255) NOT NULL, -- SHA-256 ν•΄μ‹œ (원본 λ―Έμ €μž₯)
prefix VARCHAR(20) NOT NULL, -- μ‹λ³„μš© 접두사 (예: "cbny_live_")
label VARCHAR(100), -- μš©λ„ 라벨 (예: "μ„Έμ’…μ‹œ 연동킀")
rate_limit INT DEFAULT 10000, -- 일일 호좜 ν•œλ„
expires_at TIMESTAMPTZ, -- NULL이면 λ¬΄κΈ°ν•œ
is_active BOOLEAN DEFAULT true NOT NULL,
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP NOT NULL
);
CREATE INDEX idx_apikeys_org ON api_keys(org_id);
CREATE INDEX idx_apikeys_prefix ON api_keys(prefix);