wing-ops/database/auth_init.sql
Nan Kyung Lee ce80e620c1 feat(admin): 관리자 화면 고도화 — 사용자/권한/게시판/선박신호 패널
- UsersPanel: 테이블+페이징+등록모달+상세모달(비밀번호초기화/잠금해제)
- PermissionsPanel: 사용자별 역할 할당 탭 추가
- BoardMgmtPanel: 공지사항/게시판/QNA 관리자 일괄 삭제
- VesselSignalPanel: VTS/VTS-AIS/V-PASS/E-NAVI/S&P AIS 타임라인 모니터링
- AdminSidebar/AdminPlaceholder/adminMenuConfig 신규
- 권한 미들웨어 부모 리소스 fallback 로직 추가
- 조직 목록 API, 관리자 삭제 API 추가

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 16:30:55 +09:00

388 lines
22 KiB
SQL
Raw Blame 히스토리

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- ================================================================
-- WING 인증 시스템 데이터베이스 (wing_auth)
-- 공공데이터베이스 표준화 관리 매뉴얼(2021.06) 기준 적용
-- PostgreSQL 16
-- ================================================================
-- ============================================================
-- 1. 사용자 및 데이터베이스 생성
-- ============================================================
CREATE USER wing_auth WITH PASSWORD 'WingAuth!2026';
CREATE DATABASE wing_auth OWNER wing_auth;
-- wing_auth 데이터베이스로 전환
\c wing_auth
-- ============================================================
-- 2. 확장 설치
-- ============================================================
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS pgcrypto;
GRANT ALL ON SCHEMA public TO wing_auth;
-- ============================================================
-- 3. 조직 (AUTH_ORG)
-- ============================================================
CREATE TABLE AUTH_ORG (
ORG_SN SERIAL NOT NULL,
ORG_NM VARCHAR(100) NOT NULL,
ORG_ABBR_NM VARCHAR(20) NOT NULL,
ORG_TP_CD VARCHAR(20) NOT NULL,
UPPER_ORG_SN INTEGER,
REG_DTM TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT PK_AUTH_ORG PRIMARY KEY (ORG_SN),
CONSTRAINT FK_AUTH_ORG_UPPER FOREIGN KEY (UPPER_ORG_SN) REFERENCES AUTH_ORG(ORG_SN)
);
COMMENT ON TABLE AUTH_ORG IS '인증조직';
COMMENT ON COLUMN AUTH_ORG.ORG_SN IS '조직순번';
COMMENT ON COLUMN AUTH_ORG.ORG_NM IS '조직명';
COMMENT ON COLUMN AUTH_ORG.ORG_ABBR_NM IS '조직약칭명';
COMMENT ON COLUMN AUTH_ORG.ORG_TP_CD IS '조직유형코드 (HEADQUARTERS, REGIONAL, STATION, AGENCY)';
COMMENT ON COLUMN AUTH_ORG.UPPER_ORG_SN IS '상위조직순번';
COMMENT ON COLUMN AUTH_ORG.REG_DTM IS '등록일시';
-- ============================================================
-- 4. 역할 (AUTH_ROLE)
-- ============================================================
CREATE TABLE AUTH_ROLE (
ROLE_SN SERIAL NOT NULL,
ROLE_CD VARCHAR(20) NOT NULL,
ROLE_NM VARCHAR(50) NOT NULL,
ROLE_DC VARCHAR(200),
DFLT_YN CHAR(1) NOT NULL DEFAULT 'N',
REG_DTM TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT PK_AUTH_ROLE PRIMARY KEY (ROLE_SN),
CONSTRAINT UK_AUTH_ROLE_CD UNIQUE (ROLE_CD),
CONSTRAINT CK_AUTH_ROLE_DFLT CHECK (DFLT_YN IN ('Y','N'))
);
COMMENT ON TABLE AUTH_ROLE IS '인증역할';
COMMENT ON COLUMN AUTH_ROLE.ROLE_SN IS '역할순번';
COMMENT ON COLUMN AUTH_ROLE.ROLE_CD IS '역할코드 (ADMIN, MANAGER, USER, VIEWER)';
COMMENT ON COLUMN AUTH_ROLE.ROLE_NM IS '역할명';
COMMENT ON COLUMN AUTH_ROLE.ROLE_DC IS '역할설명';
COMMENT ON COLUMN AUTH_ROLE.DFLT_YN IS '기본여부 (Y:신규 사용자 기본 역할)';
COMMENT ON COLUMN AUTH_ROLE.REG_DTM IS '등록일시';
-- ============================================================
-- 5. 사용자 (AUTH_USER)
-- ============================================================
CREATE TABLE AUTH_USER (
USER_ID UUID NOT NULL DEFAULT uuid_generate_v4(),
USER_ACNT VARCHAR(50) NOT NULL,
PSWD_HASH VARCHAR(255),
USER_NM VARCHAR(50) NOT NULL,
RNKP_NM VARCHAR(30),
ORG_SN INTEGER,
USER_STTS_CD VARCHAR(20) NOT NULL DEFAULT 'PENDING',
FAIL_CNT INTEGER NOT NULL DEFAULT 0,
LAST_LOGIN_DTM TIMESTAMPTZ,
OAUTH_PROVIDER VARCHAR(20),
OAUTH_SUB VARCHAR(255),
EMAIL VARCHAR(255),
REG_DTM TIMESTAMPTZ NOT NULL DEFAULT NOW(),
MDFCN_DTM TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT PK_AUTH_USER PRIMARY KEY (USER_ID),
CONSTRAINT UK_AUTH_USER_ACNT UNIQUE (USER_ACNT),
CONSTRAINT FK_AUTH_USER_ORG FOREIGN KEY (ORG_SN) REFERENCES AUTH_ORG(ORG_SN),
CONSTRAINT CK_AUTH_USER_STTS CHECK (USER_STTS_CD IN ('PENDING','ACTIVE','LOCKED','INACTIVE','REJECTED'))
);
COMMENT ON TABLE AUTH_USER IS '인증사용자';
COMMENT ON COLUMN AUTH_USER.USER_ID IS '사용자아이디 (UUID)';
COMMENT ON COLUMN AUTH_USER.USER_ACNT IS '사용자계정 (로그인 ID)';
COMMENT ON COLUMN AUTH_USER.PSWD_HASH IS '비밀번호해시 (bcrypt)';
COMMENT ON COLUMN AUTH_USER.USER_NM IS '사용자명';
COMMENT ON COLUMN AUTH_USER.RNKP_NM IS '직급명';
COMMENT ON COLUMN AUTH_USER.ORG_SN IS '조직순번';
COMMENT ON COLUMN AUTH_USER.USER_STTS_CD IS '사용자상태코드 (PENDING:승인대기, ACTIVE:활성, LOCKED:잠김, INACTIVE:비활성, REJECTED:거절)';
COMMENT ON COLUMN AUTH_USER.FAIL_CNT IS '로그인실패횟수';
COMMENT ON COLUMN AUTH_USER.LAST_LOGIN_DTM IS '최종로그인일시';
COMMENT ON COLUMN AUTH_USER.REG_DTM IS '등록일시';
COMMENT ON COLUMN AUTH_USER.OAUTH_PROVIDER IS 'OAuth제공자 (GOOGLE 등)';
COMMENT ON COLUMN AUTH_USER.OAUTH_SUB IS 'OAuth고유식별자';
COMMENT ON COLUMN AUTH_USER.EMAIL IS '이메일주소';
COMMENT ON COLUMN AUTH_USER.MDFCN_DTM IS '수정일시';
-- ============================================================
-- 6. 사용자-역할 매핑 (AUTH_USER_ROLE)
-- ============================================================
CREATE TABLE AUTH_USER_ROLE (
USER_ID UUID NOT NULL,
ROLE_SN INTEGER NOT NULL,
REG_DTM TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT PK_AUTH_USER_ROLE PRIMARY KEY (USER_ID, ROLE_SN),
CONSTRAINT FK_AUR_USER FOREIGN KEY (USER_ID) REFERENCES AUTH_USER(USER_ID) ON DELETE CASCADE,
CONSTRAINT FK_AUR_ROLE FOREIGN KEY (ROLE_SN) REFERENCES AUTH_ROLE(ROLE_SN) ON DELETE CASCADE
);
COMMENT ON TABLE AUTH_USER_ROLE IS '사용자역할매핑';
COMMENT ON COLUMN AUTH_USER_ROLE.USER_ID IS '사용자아이디';
COMMENT ON COLUMN AUTH_USER_ROLE.ROLE_SN IS '역할순번';
COMMENT ON COLUMN AUTH_USER_ROLE.REG_DTM IS '등록일시';
-- ============================================================
-- 7. 역할별 권한 (AUTH_PERM)
-- ============================================================
CREATE TABLE AUTH_PERM (
PERM_SN SERIAL NOT NULL,
ROLE_SN INTEGER NOT NULL,
RSRC_CD VARCHAR(50) NOT NULL,
OPER_CD VARCHAR(20) NOT NULL,
GRANT_YN CHAR(1) NOT NULL DEFAULT 'Y',
REG_DTM TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT PK_AUTH_PERM PRIMARY KEY (PERM_SN),
CONSTRAINT FK_AP_ROLE FOREIGN KEY (ROLE_SN) REFERENCES AUTH_ROLE(ROLE_SN) ON DELETE CASCADE,
CONSTRAINT UK_AUTH_PERM UNIQUE (ROLE_SN, RSRC_CD, OPER_CD),
CONSTRAINT CK_AUTH_PERM_GRANT CHECK (GRANT_YN IN ('Y','N')),
CONSTRAINT CK_AUTH_PERM_OPER CHECK (OPER_CD IN ('READ','CREATE','UPDATE','DELETE','MANAGE','EXPORT'))
);
COMMENT ON TABLE AUTH_PERM IS '역할별권한';
COMMENT ON COLUMN AUTH_PERM.PERM_SN IS '권한순번';
COMMENT ON COLUMN AUTH_PERM.ROLE_SN IS '역할순번';
COMMENT ON COLUMN AUTH_PERM.RSRC_CD IS '리소스코드 (탭 ID: prediction, hns, rescue 등)';
COMMENT ON COLUMN AUTH_PERM.OPER_CD IS '오퍼레이션코드 (READ, CREATE, UPDATE, DELETE, MANAGE, EXPORT)';
COMMENT ON COLUMN AUTH_PERM.GRANT_YN IS '부여여부 (Y:허용, N:거부)';
COMMENT ON COLUMN AUTH_PERM.REG_DTM IS '등록일시';
-- ============================================================
-- 8. 로그인 이력 (AUTH_LOGIN_HIST)
-- ============================================================
CREATE TABLE AUTH_LOGIN_HIST (
HIST_SN SERIAL NOT NULL,
USER_ID UUID NOT NULL,
LOGIN_DTM TIMESTAMPTZ NOT NULL DEFAULT NOW(),
IP_ADDR VARCHAR(45),
USER_AGENT VARCHAR(500),
SUCCESS_YN CHAR(1) NOT NULL DEFAULT 'Y',
CONSTRAINT PK_AUTH_LOGIN_HIST PRIMARY KEY (HIST_SN),
CONSTRAINT FK_ALH_USER FOREIGN KEY (USER_ID) REFERENCES AUTH_USER(USER_ID) ON DELETE CASCADE,
CONSTRAINT CK_ALH_SUCCESS CHECK (SUCCESS_YN IN ('Y','N'))
);
COMMENT ON TABLE AUTH_LOGIN_HIST IS '로그인이력';
COMMENT ON COLUMN AUTH_LOGIN_HIST.HIST_SN IS '이력순번';
COMMENT ON COLUMN AUTH_LOGIN_HIST.USER_ID IS '사용자아이디';
COMMENT ON COLUMN AUTH_LOGIN_HIST.LOGIN_DTM IS '로그인일시';
COMMENT ON COLUMN AUTH_LOGIN_HIST.IP_ADDR IS 'IP주소';
COMMENT ON COLUMN AUTH_LOGIN_HIST.USER_AGENT IS '유저에이전트';
COMMENT ON COLUMN AUTH_LOGIN_HIST.SUCCESS_YN IS '성공여부 (Y:성공, N:실패)';
-- ============================================================
-- 8-1. 시스템 설정 (AUTH_SETTING)
-- ============================================================
CREATE TABLE AUTH_SETTING (
SETTING_KEY VARCHAR(100) NOT NULL,
SETTING_VAL TEXT NOT NULL,
SETTING_DC VARCHAR(200),
MDFCN_DTM TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT PK_AUTH_SETTING PRIMARY KEY (SETTING_KEY)
);
COMMENT ON TABLE AUTH_SETTING IS '시스템설정';
COMMENT ON COLUMN AUTH_SETTING.SETTING_KEY IS '설정키';
COMMENT ON COLUMN AUTH_SETTING.SETTING_VAL IS '설정값';
COMMENT ON COLUMN AUTH_SETTING.SETTING_DC IS '설정설명';
COMMENT ON COLUMN AUTH_SETTING.MDFCN_DTM IS '수정일시';
-- ============================================================
-- 8-2. 감사 로그 (AUTH_AUDIT_LOG)
-- ============================================================
CREATE TABLE AUTH_AUDIT_LOG (
LOG_SN SERIAL NOT NULL,
USER_ID UUID,
ACTION_CD VARCHAR(30) NOT NULL,
ACTION_DTL VARCHAR(100),
HTTP_METHOD VARCHAR(10),
CRUD_TYPE VARCHAR(10),
REQ_URL VARCHAR(500),
REQ_DTM TIMESTAMPTZ NOT NULL DEFAULT NOW(),
RES_DTM TIMESTAMPTZ,
RES_STATUS SMALLINT,
RES_SIZE INTEGER,
IP_ADDR VARCHAR(45),
USER_AGENT VARCHAR(500),
EXTRA JSONB,
CONSTRAINT PK_AUTH_AUDIT_LOG PRIMARY KEY (LOG_SN)
);
COMMENT ON TABLE AUTH_AUDIT_LOG IS '감사로그';
COMMENT ON COLUMN AUTH_AUDIT_LOG.LOG_SN IS '로그순번';
COMMENT ON COLUMN AUTH_AUDIT_LOG.USER_ID IS '사용자아이디';
COMMENT ON COLUMN AUTH_AUDIT_LOG.ACTION_CD IS '액션코드 (TAB_VIEW, API_CALL, LOGIN, LOGOUT, ADMIN_ACTION)';
COMMENT ON COLUMN AUTH_AUDIT_LOG.ACTION_DTL IS '액션상세 (탭ID, API경로, 관리자작업명)';
COMMENT ON COLUMN AUTH_AUDIT_LOG.HTTP_METHOD IS 'HTTP메소드 (GET, POST, PUT, DELETE)';
COMMENT ON COLUMN AUTH_AUDIT_LOG.CRUD_TYPE IS 'CRUD구분 (SELECT, INSERT, UPDATE, DELETE)';
COMMENT ON COLUMN AUTH_AUDIT_LOG.REQ_URL IS '요청URL';
COMMENT ON COLUMN AUTH_AUDIT_LOG.REQ_DTM IS '요청일시';
COMMENT ON COLUMN AUTH_AUDIT_LOG.RES_DTM IS '응답일시';
COMMENT ON COLUMN AUTH_AUDIT_LOG.RES_STATUS IS '응답HTTP상태코드';
COMMENT ON COLUMN AUTH_AUDIT_LOG.RES_SIZE IS '응답데이터크기(bytes)';
COMMENT ON COLUMN AUTH_AUDIT_LOG.IP_ADDR IS 'IP주소';
COMMENT ON COLUMN AUTH_AUDIT_LOG.USER_AGENT IS '유저에이전트';
COMMENT ON COLUMN AUTH_AUDIT_LOG.EXTRA IS '추가메타데이터(JSON)';
-- ============================================================
-- 9. 인덱스
-- ============================================================
CREATE INDEX IDX_AUTH_USER_STTS ON AUTH_USER (USER_STTS_CD);
CREATE INDEX IDX_AUTH_USER_ORG ON AUTH_USER (ORG_SN);
CREATE UNIQUE INDEX UK_AUTH_USER_OAUTH ON AUTH_USER(OAUTH_PROVIDER, OAUTH_SUB) WHERE OAUTH_PROVIDER IS NOT NULL;
CREATE UNIQUE INDEX UK_AUTH_USER_EMAIL ON AUTH_USER(EMAIL) WHERE EMAIL IS NOT NULL;
CREATE INDEX IDX_AUTH_PERM_ROLE ON AUTH_PERM (ROLE_SN);
CREATE INDEX IDX_AUTH_PERM_RSRC ON AUTH_PERM (RSRC_CD);
CREATE INDEX IDX_AUTH_PERM_OPER ON AUTH_PERM (OPER_CD);
CREATE INDEX IDX_AUTH_LOGIN_USER ON AUTH_LOGIN_HIST (USER_ID);
CREATE INDEX IDX_AUTH_LOGIN_DTM ON AUTH_LOGIN_HIST (LOGIN_DTM);
CREATE INDEX IDX_AUDIT_LOG_USER ON AUTH_AUDIT_LOG (USER_ID);
CREATE INDEX IDX_AUDIT_LOG_ACTION ON AUTH_AUDIT_LOG (ACTION_CD);
CREATE INDEX IDX_AUDIT_LOG_DTM ON AUTH_AUDIT_LOG (REQ_DTM);
-- ============================================================
-- 10. 초기 데이터: 역할
-- ============================================================
INSERT INTO AUTH_ROLE (ROLE_CD, ROLE_NM, ROLE_DC, DFLT_YN) VALUES
('ADMIN', '관리자', '시스템 전체 관리 권한', 'N'),
('HQ_CLEANUP', '본청방제과', '본청 방제 업무 관리 권한', 'N'),
('MANAGER', '운영자', '운영 및 사용자 관리 권한', 'N'),
('USER', '일반사용자', '기본 업무 기능 접근 권한', 'Y'),
('VIEWER', '뷰어', '조회 전용 접근 권한', 'N');
-- ============================================================
-- 11. 초기 데이터: 역할별 권한 (리소스 × 오퍼레이션 매트릭스)
-- OPER_CD: READ(조회), CREATE(생성), UPDATE(수정), DELETE(삭제)
-- ============================================================
-- ADMIN (ROLE_SN=1): 모든 탭 × 모든 오퍼레이션 허용
INSERT INTO AUTH_PERM (ROLE_SN, RSRC_CD, OPER_CD, GRANT_YN) VALUES
(1, 'prediction', 'READ', 'Y'), (1, 'prediction', 'CREATE', 'Y'), (1, 'prediction', 'UPDATE', 'Y'), (1, 'prediction', 'DELETE', 'Y'),
(1, 'hns', 'READ', 'Y'), (1, 'hns', 'CREATE', 'Y'), (1, 'hns', 'UPDATE', 'Y'), (1, 'hns', 'DELETE', 'Y'),
(1, 'rescue', 'READ', 'Y'), (1, 'rescue', 'CREATE', 'Y'), (1, 'rescue', 'UPDATE', 'Y'), (1, 'rescue', 'DELETE', 'Y'),
(1, 'reports', 'READ', 'Y'), (1, 'reports', 'CREATE', 'Y'), (1, 'reports', 'UPDATE', 'Y'), (1, 'reports', 'DELETE', 'Y'),
(1, 'aerial', 'READ', 'Y'), (1, 'aerial', 'CREATE', 'Y'), (1, 'aerial', 'UPDATE', 'Y'), (1, 'aerial', 'DELETE', 'Y'),
(1, 'assets', 'READ', 'Y'), (1, 'assets', 'CREATE', 'Y'), (1, 'assets', 'UPDATE', 'Y'), (1, 'assets', 'DELETE', 'Y'),
(1, 'scat', 'READ', 'Y'), (1, 'scat', 'CREATE', 'Y'), (1, 'scat', 'UPDATE', 'Y'), (1, 'scat', 'DELETE', 'Y'),
(1, 'incidents', 'READ', 'Y'), (1, 'incidents', 'CREATE', 'Y'), (1, 'incidents', 'UPDATE', 'Y'), (1, 'incidents', 'DELETE', 'Y'),
(1, 'board', 'READ', 'Y'), (1, 'board', 'CREATE', 'Y'), (1, 'board', 'UPDATE', 'Y'), (1, 'board', 'DELETE', 'Y'),
(1, 'weather', 'READ', 'Y'), (1, 'weather', 'CREATE', 'Y'), (1, 'weather', 'UPDATE', 'Y'), (1, 'weather', 'DELETE', 'Y'),
(1, 'admin', 'READ', 'Y'), (1, 'admin', 'CREATE', 'Y'), (1, 'admin', 'UPDATE', 'Y'), (1, 'admin', 'DELETE', 'Y');
-- HQ_CLEANUP (ROLE_SN=2): 방제 관련 탭 RCUD + 기타 탭 READ/CREATE, admin 제외
INSERT INTO AUTH_PERM (ROLE_SN, RSRC_CD, OPER_CD, GRANT_YN) VALUES
(2, 'prediction', 'READ', 'Y'), (2, 'prediction', 'CREATE', 'Y'), (2, 'prediction', 'UPDATE', 'Y'), (2, 'prediction', 'DELETE', 'Y'),
(2, 'hns', 'READ', 'Y'), (2, 'hns', 'CREATE', 'Y'), (2, 'hns', 'UPDATE', 'Y'), (2, 'hns', 'DELETE', 'Y'),
(2, 'rescue', 'READ', 'Y'), (2, 'rescue', 'CREATE', 'Y'), (2, 'rescue', 'UPDATE', 'Y'), (2, 'rescue', 'DELETE', 'Y'),
(2, 'reports', 'READ', 'Y'), (2, 'reports', 'CREATE', 'Y'), (2, 'reports', 'UPDATE', 'Y'), (2, 'reports', 'DELETE', 'Y'),
(2, 'aerial', 'READ', 'Y'), (2, 'aerial', 'CREATE', 'Y'), (2, 'aerial', 'UPDATE', 'Y'), (2, 'aerial', 'DELETE', 'Y'),
(2, 'assets', 'READ', 'Y'), (2, 'assets', 'CREATE', 'Y'), (2, 'assets', 'UPDATE', 'Y'), (2, 'assets', 'DELETE', 'Y'),
(2, 'scat', 'READ', 'Y'), (2, 'scat', 'CREATE', 'Y'), (2, 'scat', 'UPDATE', 'Y'), (2, 'scat', 'DELETE', 'Y'),
(2, 'incidents', 'READ', 'Y'), (2, 'incidents', 'CREATE', 'Y'), (2, 'incidents', 'UPDATE', 'Y'), (2, 'incidents', 'DELETE', 'Y'),
(2, 'board', 'READ', 'Y'), (2, 'board', 'CREATE', 'Y'), (2, 'board', 'UPDATE', 'Y'),
(2, 'weather', 'READ', 'Y'), (2, 'weather', 'CREATE', 'Y'),
(2, 'admin', 'READ', 'N');
-- MANAGER (ROLE_SN=3): admin 탭 제외, RCUD 허용
INSERT INTO AUTH_PERM (ROLE_SN, RSRC_CD, OPER_CD, GRANT_YN) VALUES
(3, 'prediction', 'READ', 'Y'), (3, 'prediction', 'CREATE', 'Y'), (3, 'prediction', 'UPDATE', 'Y'), (3, 'prediction', 'DELETE', 'Y'),
(3, 'hns', 'READ', 'Y'), (3, 'hns', 'CREATE', 'Y'), (3, 'hns', 'UPDATE', 'Y'), (3, 'hns', 'DELETE', 'Y'),
(3, 'rescue', 'READ', 'Y'), (3, 'rescue', 'CREATE', 'Y'), (3, 'rescue', 'UPDATE', 'Y'), (3, 'rescue', 'DELETE', 'Y'),
(3, 'reports', 'READ', 'Y'), (3, 'reports', 'CREATE', 'Y'), (3, 'reports', 'UPDATE', 'Y'), (3, 'reports', 'DELETE', 'Y'),
(3, 'aerial', 'READ', 'Y'), (3, 'aerial', 'CREATE', 'Y'), (3, 'aerial', 'UPDATE', 'Y'), (3, 'aerial', 'DELETE', 'Y'),
(3, 'assets', 'READ', 'Y'), (3, 'assets', 'CREATE', 'Y'), (3, 'assets', 'UPDATE', 'Y'), (3, 'assets', 'DELETE', 'Y'),
(3, 'scat', 'READ', 'Y'), (3, 'scat', 'CREATE', 'Y'), (3, 'scat', 'UPDATE', 'Y'), (3, 'scat', 'DELETE', 'Y'),
(3, 'incidents', 'READ', 'Y'), (3, 'incidents', 'CREATE', 'Y'), (3, 'incidents', 'UPDATE', 'Y'), (3, 'incidents', 'DELETE', 'Y'),
(3, 'board', 'READ', 'Y'), (3, 'board', 'CREATE', 'Y'), (3, 'board', 'UPDATE', 'Y'), (3, 'board', 'DELETE', 'Y'),
(3, 'weather', 'READ', 'Y'), (3, 'weather', 'CREATE', 'Y'), (3, 'weather', 'UPDATE', 'Y'), (3, 'weather', 'DELETE', 'Y'),
(3, 'admin', 'READ', 'N');
-- USER (ROLE_SN=4): assets/admin 제외, 허용 탭은 READ/CREATE/UPDATE, DELETE 없음
INSERT INTO AUTH_PERM (ROLE_SN, RSRC_CD, OPER_CD, GRANT_YN) VALUES
(4, 'prediction', 'READ', 'Y'), (4, 'prediction', 'CREATE', 'Y'), (4, 'prediction', 'UPDATE', 'Y'),
(4, 'hns', 'READ', 'Y'), (4, 'hns', 'CREATE', 'Y'), (4, 'hns', 'UPDATE', 'Y'),
(4, 'rescue', 'READ', 'Y'), (4, 'rescue', 'CREATE', 'Y'), (4, 'rescue', 'UPDATE', 'Y'),
(4, 'reports', 'READ', 'Y'), (4, 'reports', 'CREATE', 'Y'), (4, 'reports', 'UPDATE', 'Y'),
(4, 'aerial', 'READ', 'Y'), (4, 'aerial', 'CREATE', 'Y'), (4, 'aerial', 'UPDATE', 'Y'),
(4, 'assets', 'READ', 'N'),
(4, 'scat', 'READ', 'Y'), (4, 'scat', 'CREATE', 'Y'), (4, 'scat', 'UPDATE', 'Y'),
(4, 'incidents', 'READ', 'Y'), (4, 'incidents', 'CREATE', 'Y'), (4, 'incidents', 'UPDATE', 'Y'),
(4, 'board', 'READ', 'Y'), (4, 'board', 'CREATE', 'Y'), (4, 'board', 'UPDATE', 'Y'),
(4, 'weather', 'READ', 'Y'),
(4, 'admin', 'READ', 'N');
-- VIEWER (ROLE_SN=5): 제한적 탭의 READ만 허용
INSERT INTO AUTH_PERM (ROLE_SN, RSRC_CD, OPER_CD, GRANT_YN) VALUES
(5, 'prediction', 'READ', 'Y'),
(5, 'hns', 'READ', 'Y'),
(5, 'rescue', 'READ', 'Y'),
(5, 'reports', 'READ', 'N'),
(5, 'aerial', 'READ', 'Y'),
(5, 'assets', 'READ', 'N'),
(5, 'scat', 'READ', 'N'),
(5, 'incidents', 'READ', 'Y'),
(5, 'board', 'READ', 'Y'),
(5, 'weather', 'READ', 'Y'),
(5, 'admin', 'READ', 'N');
-- ============================================================
-- 12. 초기 데이터: 조직
-- ============================================================
INSERT INTO AUTH_ORG (ORG_NM, ORG_ABBR_NM, ORG_TP_CD) VALUES
('해양경찰청', '해경청', 'HEADQUARTERS'),
('남해지방해양경찰청', '남해청', 'REGIONAL'),
('제주지방해양경찰청', '제주청', 'REGIONAL'),
('여수해양경찰서', '여수서', 'STATION'),
('서귀포해양경찰서', '서귀포서', 'STATION'),
('제주해양경찰서', '제주서', 'STATION');
UPDATE AUTH_ORG SET UPPER_ORG_SN = 1 WHERE ORG_SN IN (2, 3);
UPDATE AUTH_ORG SET UPPER_ORG_SN = 2 WHERE ORG_SN = 4;
UPDATE AUTH_ORG SET UPPER_ORG_SN = 3 WHERE ORG_SN IN (5, 6);
-- ============================================================
-- 13. 초기 데이터: 관리자 계정 (admin / admin1234)
-- ============================================================
INSERT INTO AUTH_USER (USER_ACNT, PSWD_HASH, USER_NM, RNKP_NM, ORG_SN, USER_STTS_CD)
VALUES ('admin', crypt('admin1234', gen_salt('bf', 10)), '관리자', '경정', 1, 'ACTIVE');
-- admin 사용자에 ADMIN 역할 할당
INSERT INTO AUTH_USER_ROLE (USER_ID, ROLE_SN)
SELECT USER_ID, 1 FROM AUTH_USER WHERE USER_ACNT = 'admin';
-- ============================================================
-- 14. 초기 데이터: 시스템 설정
-- ============================================================
INSERT INTO AUTH_SETTING (SETTING_KEY, SETTING_VAL, SETTING_DC) VALUES
('registration.auto-approve', 'true', '신규 사용자 자동 승인 여부 (true: 즉시 ACTIVE, false: PENDING 대기)'),
('registration.default-role', 'true', '신규 사용자에게 기본 역할(DFLT_YN=Y) 자동 할당 여부'),
('oauth.auto-approve-domains', 'gcsc.co.kr', 'OAuth 자동 승인 도메인 (쉼표 구분)'),
('menu.config', '[{"id":"prediction","label":"유출유 확산예측","icon":"🛢️","enabled":true,"order":1},{"id":"hns","label":"HNS·대기확산","icon":"🧪","enabled":true,"order":2},{"id":"rescue","label":"긴급구난","icon":"🚨","enabled":true,"order":3},{"id":"reports","label":"보고자료","icon":"📊","enabled":true,"order":4},{"id":"aerial","label":"항공탐색","icon":"✈️","enabled":true,"order":5},{"id":"assets","label":"방제자산 관리","icon":"🚢","enabled":true,"order":6},{"id":"scat","label":"해안평가","icon":"🏖️","enabled":true,"order":7},{"id":"board","label":"게시판","icon":"📌","enabled":true,"order":8},{"id":"weather","label":"기상정보","icon":"⛅","enabled":true,"order":9},{"id":"incidents","label":"통합조회","icon":"🔍","enabled":true,"order":10}]', '메뉴 표시 여부 및 순서 설정 (JSON 배열)');
-- ============================================================
-- 15. 권한 부여
-- ============================================================
GRANT ALL ON ALL TABLES IN SCHEMA public TO wing_auth;
GRANT ALL ON ALL SEQUENCES IN SCHEMA public TO wing_auth;
-- ============================================================
-- 데이터베이스 코멘트
-- ============================================================
COMMENT ON DATABASE wing_auth IS 'WING 인증 시스템 - 사용자 인증, 역할, 권한 관리';