diff --git a/docs/design/smilegate-identity-administration/README.md b/docs/design/smilegate-identity-administration/README.md new file mode 100644 index 0000000..f95e8fa --- /dev/null +++ b/docs/design/smilegate-identity-administration/README.md @@ -0,0 +1,35 @@ +# Smilegate Backoffice Identity Administration + +## Goal + +Keep `admin` as the backoffice control-plane login. Provide an administrator-facing +model for managing Smilegate PoC tool users, groups, roles, and their assignments. +These users are tool operators (for example a Data & AI TF lead or member), not +game-service players. + +## Scope + +* `SG_APP_USER`, `SG_APP_GROUP`, and `SG_APP_ROLE` are the application masters. +* `SG_USER_ROLE`, `SG_USER_GROUP`, and `SG_GROUP_ROLE` express normalized + user/group/role assignments. +* Every change is recorded in `SG_AUDIT_EVENT` by the backoffice audit service. +* Existing `/users`, `/groups`, and `/roles` pages use only the `SG_*` identity + model. They must not require the legacy VPD/permission objects to render. + +## Seed data + +| Type | Code | Purpose | +| --- | --- | --- | +| User | `sg-teamlead` | Data & AI TF team lead demo operator | +| User | `sg-member` | Data & AI TF member demo operator | +| Group | `DATA_AI_TF` | Smilegate Data & AI TF | +| Role | `DATA_AI_TEAM_LEAD` | Team lead operational role | +| Role | `DATA_AI_TEAM_MEMBER` | Team member operational role | + +## Acceptance checks + +1. An authenticated `admin` can open `/users`, `/groups`, and `/roles`. +2. The seed users, group, and roles appear; assignments can be added and removed. +3. Create, activation, role, and group changes are committed atomically and leave + an `SG_AUDIT_EVENT` row. +4. The pages do not call the legacy effective VPD permission matrix. diff --git a/sql/adb/71_sg_identity_administration.sql b/sql/adb/71_sg_identity_administration.sql new file mode 100644 index 0000000..f2a049c --- /dev/null +++ b/sql/adb/71_sg_identity_administration.sql @@ -0,0 +1,119 @@ +-- Smilegate PoC backoffice identity administration model. +-- Tool operators are distinct from game-service users and from the admin login. + +set define off + +declare + procedure create_if_missing(p_sql varchar2) is + begin + execute immediate p_sql; + exception + when others then + if sqlcode != -955 then raise; end if; + end; +begin + create_if_missing('create table sg_app_user ( + user_id number primary key, + login_id varchar2(100) not null unique, + user_name varchar2(200) not null, + employee_no varchar2(100), + dept_code varchar2(100), + can_read_contents char(1) default ''N'' not null, + active char(1) default ''Y'' not null, + created_at timestamp default systimestamp not null, + updated_at timestamp default systimestamp not null, + constraint sg_app_user_active_ck check (active in (''Y'', ''N'')) + )'); + create_if_missing('create table sg_app_group ( + group_id number primary key, + group_code varchar2(100) not null unique, + group_name varchar2(200) not null, + description varchar2(500), + active_yn char(1) default ''Y'' not null, + created_at timestamp default systimestamp not null, + updated_at timestamp default systimestamp not null, + constraint sg_app_group_active_ck check (active_yn in (''Y'', ''N'')) + )'); + create_if_missing('create table sg_app_role ( + role_id number primary key, + role_name varchar2(100) not null unique, + description varchar2(500), + max_sensitivity_level varchar2(30) default ''INTERNAL'' not null, + created_at timestamp default systimestamp not null, + updated_at timestamp default systimestamp not null, + constraint sg_app_role_sensitivity_ck check (max_sensitivity_level in (''PUBLIC'', ''INTERNAL'', ''CONFIDENTIAL'', ''RESTRICTED'')) + )'); + create_if_missing('create table sg_user_role ( + user_id number not null, + role_id number not null, + created_at timestamp default systimestamp not null, + constraint sg_user_role_pk primary key (user_id, role_id), + constraint sg_user_role_user_fk foreign key (user_id) references sg_app_user(user_id), + constraint sg_user_role_role_fk foreign key (role_id) references sg_app_role(role_id) + )'); + create_if_missing('create table sg_user_group ( + group_id number not null, + user_id number not null, + created_at timestamp default systimestamp not null, + constraint sg_user_group_pk primary key (group_id, user_id), + constraint sg_user_group_group_fk foreign key (group_id) references sg_app_group(group_id), + constraint sg_user_group_user_fk foreign key (user_id) references sg_app_user(user_id) + )'); + create_if_missing('create table sg_group_role ( + group_id number not null, + role_id number not null, + created_at timestamp default systimestamp not null, + constraint sg_group_role_pk primary key (group_id, role_id), + constraint sg_group_role_group_fk foreign key (group_id) references sg_app_group(group_id), + constraint sg_group_role_role_fk foreign key (role_id) references sg_app_role(role_id) + )'); + create_if_missing('create table sg_audit_event ( + audit_id number primary key, + event_type varchar2(100) not null, + key_id number, + object_id number, + status varchar2(30) not null, + row_count number, + error_code varchar2(100), + message varchar2(2000), + created_at timestamp default systimestamp not null + )'); + create_if_missing('create sequence sg_audit_event_seq start with 1 increment by 1 nocache'); +end; +/ + +merge into sg_app_user t +using ( + select 1001 user_id, 'sg-teamlead' login_id, 'SG Demo Team Lead' user_name, 'SG-001' employee_no, 'DATA_AI' dept_code from dual + union all + select 1002, 'sg-member', 'SG Demo Team Member', 'SG-002', 'DATA_AI' from dual +) s on (t.user_id = s.user_id) +when matched then update set t.login_id=s.login_id, t.user_name=s.user_name, t.employee_no=s.employee_no, t.dept_code=s.dept_code, t.active='Y', t.updated_at=systimestamp +when not matched then insert (user_id, login_id, user_name, employee_no, dept_code, can_read_contents, active) +values (s.user_id, s.login_id, s.user_name, s.employee_no, s.dept_code, 'N', 'Y'); + +merge into sg_app_group t +using (select 2001 group_id, 'DATA_AI_TF' group_code, 'Data & AI TF' group_name, 'Smilegate Data and AI proof-of-concept operators' description from dual) s +on (t.group_id = s.group_id) +when matched then update set t.group_code=s.group_code, t.group_name=s.group_name, t.description=s.description, t.active_yn='Y', t.updated_at=systimestamp +when not matched then insert (group_id, group_code, group_name, description, active_yn) values (s.group_id, s.group_code, s.group_name, s.description, 'Y'); + +merge into sg_app_role t +using ( + select 3001 role_id, 'DATA_AI_TEAM_LEAD' role_name, 'Data and AI TF lead' description, 'CONFIDENTIAL' max_sensitivity_level from dual + union all + select 3002, 'DATA_AI_TEAM_MEMBER', 'Data and AI TF member', 'INTERNAL' from dual +) s on (t.role_id=s.role_id) +when matched then update set t.role_name=s.role_name, t.description=s.description, t.max_sensitivity_level=s.max_sensitivity_level, t.updated_at=systimestamp +when not matched then insert (role_id, role_name, description, max_sensitivity_level) values (s.role_id, s.role_name, s.description, s.max_sensitivity_level); + +merge into sg_user_group t using (select 2001 group_id, 1001 user_id from dual union all select 2001, 1002 from dual) s +on (t.group_id=s.group_id and t.user_id=s.user_id) when not matched then insert (group_id, user_id) values (s.group_id, s.user_id); + +merge into sg_user_role t using (select 1001 user_id, 3001 role_id from dual union all select 1002, 3002 from dual) s +on (t.user_id=s.user_id and t.role_id=s.role_id) when not matched then insert (user_id, role_id) values (s.user_id, s.role_id); + +merge into sg_group_role t using (select 2001 group_id, 3002 role_id from dual) s +on (t.group_id=s.group_id and t.role_id=s.role_id) when not matched then insert (group_id, role_id) values (s.group_id, s.role_id); + +commit; diff --git a/src/main/resources/mapper/AuditMapper.xml b/src/main/resources/mapper/AuditMapper.xml index 342310a..306c78c 100644 --- a/src/main/resources/mapper/AuditMapper.xml +++ b/src/main/resources/mapper/AuditMapper.xml @@ -3,10 +3,10 @@ "https://mybatis.org/dtd/mybatis-3-mapper.dtd"> - INSERT INTO cb_ords_probe_audit ( + INSERT INTO sg_audit_event ( audit_id, event_type, key_id, object_id, status, row_count, error_code, message, created_at ) VALUES ( - cb_ords_probe_audit_seq.NEXTVAL, + sg_audit_event_seq.NEXTVAL, #{eventType,jdbcType=VARCHAR}, #{keyId,jdbcType=NUMERIC}, #{objectId,jdbcType=NUMERIC}, diff --git a/src/main/resources/mapper/GroupMapper.xml b/src/main/resources/mapper/GroupMapper.xml index 6a52f48..d6c0000 100644 --- a/src/main/resources/mapper/GroupMapper.xml +++ b/src/main/resources/mapper/GroupMapper.xml @@ -8,7 +8,7 @@ group_name, description, active_yn - FROM cb_app_group + FROM sg_app_group ORDER BY group_code @@ -18,9 +18,9 @@ g.group_name, u.user_id, u.user_name AS username - FROM cb_user_group ug - JOIN cb_app_group g ON g.group_id = ug.group_id - JOIN cb_app_user u ON u.user_id = ug.user_id + FROM sg_user_group ug + JOIN sg_app_group g ON g.group_id = ug.group_id + JOIN sg_app_user u ON u.user_id = ug.user_id ORDER BY g.group_code, u.user_name @@ -30,18 +30,18 @@ g.group_name, r.role_id, r.role_name - FROM cb_group_role gr - JOIN cb_app_group g ON g.group_id = gr.group_id - JOIN cb_app_role r ON r.role_id = gr.role_id + FROM sg_group_role gr + JOIN sg_app_group g ON g.group_id = gr.group_id + JOIN sg_app_role r ON r.role_id = gr.role_id ORDER BY g.group_code, r.role_name - INSERT INTO cb_app_group ( + INSERT INTO sg_app_group ( group_id, group_code, group_name, description, active_yn ) VALUES ( #{groupId,jdbcType=NUMERIC}, @@ -53,29 +53,29 @@ - UPDATE cb_app_group + UPDATE sg_app_group SET active_yn = #{activeYn,jdbcType=VARCHAR} WHERE group_id = #{groupId,jdbcType=NUMERIC} - INSERT INTO cb_user_group (group_id, user_id) + INSERT INTO sg_user_group (group_id, user_id) VALUES (#{groupId,jdbcType=NUMERIC}, #{userId,jdbcType=NUMERIC}) - DELETE FROM cb_user_group + DELETE FROM sg_user_group WHERE group_id = #{groupId,jdbcType=NUMERIC} AND user_id = #{userId,jdbcType=NUMERIC} - INSERT INTO cb_group_role (group_id, role_id) + INSERT INTO sg_group_role (group_id, role_id) VALUES (#{groupId,jdbcType=NUMERIC}, #{roleId,jdbcType=NUMERIC}) - DELETE FROM cb_group_role + DELETE FROM sg_group_role WHERE group_id = #{groupId,jdbcType=NUMERIC} AND role_id = #{roleId,jdbcType=NUMERIC} diff --git a/src/main/resources/mapper/PermissionMapper.xml b/src/main/resources/mapper/PermissionMapper.xml index a18bc5e..8b9ef68 100644 --- a/src/main/resources/mapper/PermissionMapper.xml +++ b/src/main/resources/mapper/PermissionMapper.xml @@ -5,132 +5,77 @@ - INSERT INTO cb_app_role (role_id, role_name, max_sensitivity_level) + INSERT INTO sg_app_role (role_id, role_name, description, max_sensitivity_level) VALUES ( #{roleId,jdbcType=NUMERIC}, UPPER(#{roleName,jdbcType=VARCHAR}), + #{description,jdbcType=VARCHAR}, #{maxSensitivityLevel,jdbcType=VARCHAR} ) - UPDATE cb_app_role + UPDATE sg_app_role SET max_sensitivity_level = #{maxSensitivityLevel,jdbcType=VARCHAR} WHERE role_id = #{roleId,jdbcType=NUMERIC} - DELETE FROM cb_app_role + DELETE FROM sg_app_role WHERE role_id = #{roleId,jdbcType=NUMERIC} @@ -20,7 +20,7 @@ dept_code, can_read_contents, active AS active_yn - FROM cb_app_user + FROM sg_app_user WHERE user_id = #{userId} @@ -29,18 +29,18 @@ u.user_name AS username, r.role_id, r.role_name - FROM cb_user_role ur - JOIN cb_app_user u ON u.user_id = ur.user_id - JOIN cb_app_role r ON r.role_id = ur.role_id + FROM sg_user_role ur + JOIN sg_app_user u ON u.user_id = ur.user_id + JOIN sg_app_role r ON r.role_id = ur.role_id ORDER BY u.user_name, r.role_name - INSERT INTO cb_app_user ( + INSERT INTO sg_app_user ( user_id, user_name, employee_no, dept_code, can_read_contents, active ) VALUES ( #{userId}, @@ -53,18 +53,18 @@ - UPDATE cb_app_user + UPDATE sg_app_user SET active = #{activeYn} WHERE user_id = #{userId} - INSERT INTO cb_user_role (user_id, role_id) + INSERT INTO sg_user_role (user_id, role_id) VALUES (#{userId}, #{roleId}) - DELETE FROM cb_user_role + DELETE FROM sg_user_role WHERE user_id = #{userId} AND role_id = #{roleId} diff --git a/src/main/resources/templates/fragments/layout.html b/src/main/resources/templates/fragments/layout.html index eac7101..f88ee08 100644 --- a/src/main/resources/templates/fragments/layout.html +++ b/src/main/resources/templates/fragments/layout.html @@ -5,7 +5,7 @@ - 데이터 접근 제어 + SMILEGATE DATA & AI POC @@ -15,9 +15,9 @@