wing-ops/database/schema/01_auth_tables.sql
htlee 13d6ca69e2 refactor(db): DDL 스크립트 현행화 + wing_auth→auth 스키마 문서 전면 수정
- database/schema/ 14개 DDL 파일 신규 생성 (운영 DB pg_dump 기반)
- database/seed/ 14개 초기 데이터 파일 분리
- database/_deprecated/로 구 init.sql, auth_init.sql 이동
- database/README.md 신규 작성 (DB 아키텍처, 설치 절차)
- docs/ 6개 가이드 문서 wing_auth→auth 스키마 구조로 수정
- README.md, CLAUDE.md wing 단일 DB 구조 반영

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 15:16:38 +09:00

253 lines
10 KiB
SQL

-- WING-OPS Database Schema: Auth Tables
-- auth 스키마 9개 테이블 (인증/인가/감사)
-- ============================================================
-- 1. auth_role — 역할 (FK 없음, 최상위)
-- ============================================================
CREATE TABLE auth.auth_role (
role_sn integer NOT NULL,
role_cd character varying(20) NOT NULL,
role_nm character varying(50) NOT NULL,
role_dc character varying(200),
dflt_yn character(1) DEFAULT 'N'::bpchar NOT NULL,
reg_dtm timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT pk_auth_role PRIMARY KEY (role_sn),
CONSTRAINT uk_auth_role_cd UNIQUE (role_cd),
CONSTRAINT ck_auth_role_dflt CHECK ((dflt_yn = ANY (ARRAY['Y'::bpchar, 'N'::bpchar])))
);
CREATE SEQUENCE auth.auth_role_role_sn_seq
AS integer
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE auth.auth_role_role_sn_seq OWNED BY auth.auth_role.role_sn;
ALTER TABLE ONLY auth.auth_role ALTER COLUMN role_sn SET DEFAULT nextval('auth.auth_role_role_sn_seq'::regclass);
-- ============================================================
-- 2. auth_org — 조직 (자기참조 FK)
-- ============================================================
CREATE TABLE auth.auth_org (
org_sn integer NOT NULL,
org_nm character varying(100) NOT NULL,
org_abbr_nm character varying(20) NOT NULL,
org_tp_cd character varying(20) NOT NULL,
upper_org_sn integer,
reg_dtm timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT pk_auth_org PRIMARY KEY (org_sn)
);
CREATE SEQUENCE auth.auth_org_org_sn_seq
AS integer
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE auth.auth_org_org_sn_seq OWNED BY auth.auth_org.org_sn;
ALTER TABLE ONLY auth.auth_org ALTER COLUMN org_sn SET DEFAULT nextval('auth.auth_org_org_sn_seq'::regclass);
-- ============================================================
-- 3. auth_user — 사용자 (FK: auth_org)
-- ============================================================
CREATE TABLE auth.auth_user (
user_id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
user_acnt character varying(50) NOT NULL,
pswd_hash character varying(255),
user_nm character varying(50) NOT NULL,
rnkp_nm character varying(30),
org_sn integer,
user_stts_cd character varying(20) DEFAULT 'ACTIVE'::character varying NOT NULL,
fail_cnt integer DEFAULT 0 NOT NULL,
last_login_dtm timestamp with time zone,
reg_dtm timestamp with time zone DEFAULT now() NOT NULL,
mdfcn_dtm timestamp with time zone DEFAULT now() NOT NULL,
oauth_provider character varying(20),
oauth_sub character varying(255),
email character varying(255),
CONSTRAINT pk_auth_user PRIMARY KEY (user_id),
CONSTRAINT uk_auth_user_acnt UNIQUE (user_acnt),
CONSTRAINT ck_auth_user_stts CHECK (((user_stts_cd)::text = ANY (ARRAY[('ACTIVE'::character varying)::text, ('LOCKED'::character varying)::text, ('INACTIVE'::character varying)::text])))
);
-- 조건부 유니크 인덱스 (NULL 값 제외)
CREATE UNIQUE INDEX uk_auth_user_email ON auth.auth_user USING btree (email) WHERE (email IS NOT NULL);
CREATE UNIQUE INDEX uk_auth_user_oauth ON auth.auth_user USING btree (oauth_provider, oauth_sub) WHERE (oauth_provider IS NOT NULL);
-- ============================================================
-- 4. auth_user_role — 사용자-역할 매핑 (FK: auth_user, auth_role)
-- ============================================================
CREATE TABLE auth.auth_user_role (
user_id uuid NOT NULL,
role_sn integer NOT NULL,
reg_dtm timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT pk_auth_user_role PRIMARY KEY (user_id, role_sn)
);
-- ============================================================
-- 5. auth_perm_tree — 권한 트리 (자기참조 FK)
-- ============================================================
CREATE TABLE auth.auth_perm_tree (
rsrc_cd character varying(50) NOT NULL,
parent_cd character varying(50),
rsrc_nm character varying(100) NOT NULL,
rsrc_desc character varying(200),
icon character varying(20),
rsrc_level smallint DEFAULT 0 NOT NULL,
sort_ord smallint DEFAULT 0 NOT NULL,
use_yn character(1) DEFAULT 'Y'::bpchar NOT NULL,
CONSTRAINT pk_perm_tree PRIMARY KEY (rsrc_cd)
);
-- ============================================================
-- 6. auth_perm — 역할별 권한 (FK: auth_role)
-- ============================================================
CREATE TABLE auth.auth_perm (
perm_sn integer NOT NULL,
role_sn integer NOT NULL,
rsrc_cd character varying(50) NOT NULL,
grant_yn character(1) DEFAULT 'Y'::bpchar NOT NULL,
reg_dtm timestamp with time zone DEFAULT now() NOT NULL,
oper_cd character varying(20) NOT NULL,
CONSTRAINT pk_auth_perm PRIMARY KEY (perm_sn),
CONSTRAINT uk_auth_perm UNIQUE (role_sn, rsrc_cd, oper_cd),
CONSTRAINT ck_auth_perm_grant CHECK ((grant_yn = ANY (ARRAY['Y'::bpchar, 'N'::bpchar]))),
CONSTRAINT ck_auth_perm_oper CHECK (((oper_cd)::text = ANY (ARRAY[('READ'::character varying)::text, ('CREATE'::character varying)::text, ('UPDATE'::character varying)::text, ('DELETE'::character varying)::text, ('MANAGE'::character varying)::text, ('EXPORT'::character varying)::text])))
);
CREATE SEQUENCE auth.auth_perm_perm_sn_seq
AS integer
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE auth.auth_perm_perm_sn_seq OWNED BY auth.auth_perm.perm_sn;
ALTER TABLE ONLY auth.auth_perm ALTER COLUMN perm_sn SET DEFAULT nextval('auth.auth_perm_perm_sn_seq'::regclass);
-- ============================================================
-- 7. auth_setting — 시스템 설정
-- ============================================================
CREATE TABLE auth.auth_setting (
setting_key character varying(100) NOT NULL,
setting_val text NOT NULL,
setting_dc character varying(500),
mdfcn_dtm timestamp without time zone DEFAULT now(),
CONSTRAINT auth_setting_pkey PRIMARY KEY (setting_key)
);
-- ============================================================
-- 8. auth_login_hist — 로그인 이력 (FK: auth_user)
-- ============================================================
CREATE TABLE auth.auth_login_hist (
hist_sn integer NOT NULL,
user_id uuid NOT NULL,
login_dtm timestamp with time zone DEFAULT now() NOT NULL,
ip_addr character varying(45),
user_agent character varying(500),
success_yn character(1) DEFAULT 'Y'::bpchar NOT NULL,
CONSTRAINT pk_auth_login_hist PRIMARY KEY (hist_sn),
CONSTRAINT ck_alh_success CHECK ((success_yn = ANY (ARRAY['Y'::bpchar, 'N'::bpchar])))
);
CREATE SEQUENCE auth.auth_login_hist_hist_sn_seq
AS integer
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE auth.auth_login_hist_hist_sn_seq OWNED BY auth.auth_login_hist.hist_sn;
ALTER TABLE ONLY auth.auth_login_hist ALTER COLUMN hist_sn SET DEFAULT nextval('auth.auth_login_hist_hist_sn_seq'::regclass);
-- ============================================================
-- 9. auth_audit_log — 감사 로그
-- ============================================================
CREATE TABLE auth.auth_audit_log (
log_sn integer NOT NULL,
user_id uuid,
action_cd character varying(30) NOT NULL,
action_dtl character varying(100),
http_method character varying(10),
crud_type character varying(10),
req_url character varying(500),
req_dtm timestamp with time zone DEFAULT now() NOT NULL,
res_dtm timestamp with time zone,
res_status smallint,
res_size integer,
ip_addr character varying(45),
user_agent character varying(500),
extra jsonb,
CONSTRAINT pk_auth_audit_log PRIMARY KEY (log_sn)
);
CREATE SEQUENCE auth.auth_audit_log_log_sn_seq
AS integer
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE auth.auth_audit_log_log_sn_seq OWNED BY auth.auth_audit_log.log_sn;
ALTER TABLE ONLY auth.auth_audit_log ALTER COLUMN log_sn SET DEFAULT nextval('auth.auth_audit_log_log_sn_seq'::regclass);
-- ============================================================
-- FK 제약조건
-- ============================================================
ALTER TABLE ONLY auth.auth_org
ADD CONSTRAINT fk_auth_org_upper FOREIGN KEY (upper_org_sn) REFERENCES auth.auth_org(org_sn);
ALTER TABLE ONLY auth.auth_user
ADD CONSTRAINT fk_auth_user_org FOREIGN KEY (org_sn) REFERENCES auth.auth_org(org_sn);
ALTER TABLE ONLY auth.auth_user_role
ADD CONSTRAINT fk_aur_user FOREIGN KEY (user_id) REFERENCES auth.auth_user(user_id) ON DELETE CASCADE;
ALTER TABLE ONLY auth.auth_user_role
ADD CONSTRAINT fk_aur_role FOREIGN KEY (role_sn) REFERENCES auth.auth_role(role_sn) ON DELETE CASCADE;
ALTER TABLE ONLY auth.auth_perm_tree
ADD CONSTRAINT fk_perm_tree_parent FOREIGN KEY (parent_cd) REFERENCES auth.auth_perm_tree(rsrc_cd);
ALTER TABLE ONLY auth.auth_perm
ADD CONSTRAINT fk_ap_role FOREIGN KEY (role_sn) REFERENCES auth.auth_role(role_sn) ON DELETE CASCADE;
ALTER TABLE ONLY auth.auth_login_hist
ADD CONSTRAINT fk_alh_user FOREIGN KEY (user_id) REFERENCES auth.auth_user(user_id) ON DELETE CASCADE;
-- ============================================================
-- 인덱스
-- ============================================================
CREATE INDEX idx_auth_user_org ON auth.auth_user USING btree (org_sn);
CREATE INDEX idx_auth_user_stts ON auth.auth_user USING btree (user_stts_cd);
CREATE INDEX idx_auth_perm_role ON auth.auth_perm USING btree (role_sn);
CREATE INDEX idx_auth_perm_rsrc ON auth.auth_perm USING btree (rsrc_cd);
CREATE INDEX idx_auth_perm_oper ON auth.auth_perm USING btree (oper_cd);
CREATE INDEX idx_perm_tree_parent ON auth.auth_perm_tree USING btree (parent_cd);
CREATE INDEX idx_auth_login_user ON auth.auth_login_hist USING btree (user_id);
CREATE INDEX idx_auth_login_dtm ON auth.auth_login_hist USING btree (login_dtm);
CREATE INDEX idx_audit_log_user ON auth.auth_audit_log USING btree (user_id);
CREATE INDEX idx_audit_log_action ON auth.auth_audit_log USING btree (action_cd);
CREATE INDEX idx_audit_log_dtm ON auth.auth_audit_log USING btree (req_dtm);