diff --git a/apps/user-service/src/main/java/com/gltkorea/icebang/domain/department/dto/DepartmentsCardDto.java b/apps/user-service/src/main/java/com/gltkorea/icebang/domain/department/dto/DepartmentCardDo.java similarity index 87% rename from apps/user-service/src/main/java/com/gltkorea/icebang/domain/department/dto/DepartmentsCardDto.java rename to apps/user-service/src/main/java/com/gltkorea/icebang/domain/department/dto/DepartmentCardDo.java index 5f50fabd..e891e966 100644 --- a/apps/user-service/src/main/java/com/gltkorea/icebang/domain/department/dto/DepartmentsCardDto.java +++ b/apps/user-service/src/main/java/com/gltkorea/icebang/domain/department/dto/DepartmentCardDo.java @@ -9,7 +9,7 @@ @Data @Builder @AllArgsConstructor -public class DepartmentsCardDto { +public class DepartmentCardDo { private BigInteger id; private String name; } diff --git a/apps/user-service/src/main/java/com/gltkorea/icebang/domain/organization/controller/OrganizationController.java b/apps/user-service/src/main/java/com/gltkorea/icebang/domain/organization/controller/OrganizationController.java index ff3567b9..7375fcbe 100644 --- a/apps/user-service/src/main/java/com/gltkorea/icebang/domain/organization/controller/OrganizationController.java +++ b/apps/user-service/src/main/java/com/gltkorea/icebang/domain/organization/controller/OrganizationController.java @@ -11,7 +11,7 @@ import com.gltkorea.icebang.common.dto.ApiResponse; import com.gltkorea.icebang.domain.organization.dto.OrganizationCardDto; -import com.gltkorea.icebang.domain.organization.dto.OrganizationOptionsDto; +import com.gltkorea.icebang.domain.organization.dto.OrganizationOptionDto; import com.gltkorea.icebang.domain.organization.service.OrganizationService; import lombok.RequiredArgsConstructor; @@ -28,7 +28,7 @@ public ResponseEntity>> getOrganizations() } @GetMapping("/{id}/options") - public ResponseEntity> getOrganizationDetails( + public ResponseEntity> getOrganizationDetails( @PathVariable BigInteger id) { return ResponseEntity.ok(ApiResponse.success(organizationService.getOrganizationOptions(id))); } diff --git a/apps/user-service/src/main/java/com/gltkorea/icebang/domain/organization/dto/OrganizationOptionsDto.java b/apps/user-service/src/main/java/com/gltkorea/icebang/domain/organization/dto/OrganizationOptionDto.java similarity index 55% rename from apps/user-service/src/main/java/com/gltkorea/icebang/domain/organization/dto/OrganizationOptionsDto.java rename to apps/user-service/src/main/java/com/gltkorea/icebang/domain/organization/dto/OrganizationOptionDto.java index c416d811..d31534eb 100644 --- a/apps/user-service/src/main/java/com/gltkorea/icebang/domain/organization/dto/OrganizationOptionsDto.java +++ b/apps/user-service/src/main/java/com/gltkorea/icebang/domain/organization/dto/OrganizationOptionDto.java @@ -2,9 +2,9 @@ import java.util.List; -import com.gltkorea.icebang.domain.department.dto.DepartmentsCardDto; +import com.gltkorea.icebang.domain.department.dto.DepartmentCardDo; import com.gltkorea.icebang.domain.position.dto.PositionCardDto; -import com.gltkorea.icebang.domain.roles.dto.RolesCardDto; +import com.gltkorea.icebang.domain.roles.dto.RoleCardDto; import lombok.AllArgsConstructor; import lombok.Builder; @@ -13,8 +13,8 @@ @Builder @Data @AllArgsConstructor -public class OrganizationOptionsDto { - List departments; +public class OrganizationOptionDto { + List departments; List positions; - List roles; + List roles; } diff --git a/apps/user-service/src/main/java/com/gltkorea/icebang/domain/organization/service/OrganizationService.java b/apps/user-service/src/main/java/com/gltkorea/icebang/domain/organization/service/OrganizationService.java index 4cebdfe5..84bcc54c 100644 --- a/apps/user-service/src/main/java/com/gltkorea/icebang/domain/organization/service/OrganizationService.java +++ b/apps/user-service/src/main/java/com/gltkorea/icebang/domain/organization/service/OrganizationService.java @@ -6,11 +6,11 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import com.gltkorea.icebang.domain.department.dto.DepartmentsCardDto; +import com.gltkorea.icebang.domain.department.dto.DepartmentCardDo; import com.gltkorea.icebang.domain.organization.dto.OrganizationCardDto; -import com.gltkorea.icebang.domain.organization.dto.OrganizationOptionsDto; +import com.gltkorea.icebang.domain.organization.dto.OrganizationOptionDto; import com.gltkorea.icebang.domain.position.dto.PositionCardDto; -import com.gltkorea.icebang.domain.roles.dto.RolesCardDto; +import com.gltkorea.icebang.domain.roles.dto.RoleCardDto; import com.gltkorea.icebang.mapper.OrganizationMapper; import lombok.RequiredArgsConstructor; @@ -25,12 +25,12 @@ public List getAllOrganizationList() { return organizationMapper.findAllOrganizations(); } - public OrganizationOptionsDto getOrganizationOptions(BigInteger id) { - List departments = organizationMapper.findDepartmentsByOrganizationId(id); + public OrganizationOptionDto getOrganizationOptions(BigInteger id) { + List departments = organizationMapper.findDepartmentsByOrganizationId(id); List positions = organizationMapper.findPositionsByOrganizationId(id); - List roles = organizationMapper.findRolesByOrganizationId(id); + List roles = organizationMapper.findRolesByOrganizationId(id); - return OrganizationOptionsDto.builder() + return OrganizationOptionDto.builder() .departments(departments) .positions(positions) .roles(roles) diff --git a/apps/user-service/src/main/java/com/gltkorea/icebang/domain/roles/dto/RolesCardDto.java b/apps/user-service/src/main/java/com/gltkorea/icebang/domain/roles/dto/RoleCardDto.java similarity index 92% rename from apps/user-service/src/main/java/com/gltkorea/icebang/domain/roles/dto/RolesCardDto.java rename to apps/user-service/src/main/java/com/gltkorea/icebang/domain/roles/dto/RoleCardDto.java index 709a08ff..5d468be5 100644 --- a/apps/user-service/src/main/java/com/gltkorea/icebang/domain/roles/dto/RolesCardDto.java +++ b/apps/user-service/src/main/java/com/gltkorea/icebang/domain/roles/dto/RoleCardDto.java @@ -11,7 +11,7 @@ @Builder @AllArgsConstructor @NoArgsConstructor -public class RolesCardDto { +public class RoleCardDto { private BigInteger id; private String name; private String description; diff --git a/apps/user-service/src/main/java/com/gltkorea/icebang/mapper/OrganizationMapper.java b/apps/user-service/src/main/java/com/gltkorea/icebang/mapper/OrganizationMapper.java index 2643af9f..a7624bc6 100644 --- a/apps/user-service/src/main/java/com/gltkorea/icebang/mapper/OrganizationMapper.java +++ b/apps/user-service/src/main/java/com/gltkorea/icebang/mapper/OrganizationMapper.java @@ -6,20 +6,20 @@ import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; -import com.gltkorea.icebang.domain.department.dto.DepartmentsCardDto; +import com.gltkorea.icebang.domain.department.dto.DepartmentCardDo; import com.gltkorea.icebang.domain.organization.dto.OrganizationCardDto; import com.gltkorea.icebang.domain.position.dto.PositionCardDto; -import com.gltkorea.icebang.domain.roles.dto.RolesCardDto; +import com.gltkorea.icebang.domain.roles.dto.RoleCardDto; @Mapper public interface OrganizationMapper { List findAllOrganizations(); - List findDepartmentsByOrganizationId( + List findDepartmentsByOrganizationId( @Param("organizationId") BigInteger organizationId); List findPositionsByOrganizationId( @Param("organizationId") BigInteger organizationId); - List findRolesByOrganizationId(@Param("organizationId") BigInteger organizationId); + List findRolesByOrganizationId(@Param("organizationId") BigInteger organizationId); } diff --git a/apps/user-service/src/main/resources/application-develop.yml b/apps/user-service/src/main/resources/application-develop.yml index 773a7333..6d9a8ea3 100644 --- a/apps/user-service/src/main/resources/application-develop.yml +++ b/apps/user-service/src/main/resources/application-develop.yml @@ -26,7 +26,9 @@ spring: sql: init: mode: always - schema-locations: classpath:sql/schema.sql + schema-locations: + - classpath:sql/00-drop-maria.sql + - classpath:sql/01-schema.sql data-locations: - classpath:sql/00-truncate.sql - classpath:sql/01-insert-internal-users.sql diff --git a/apps/user-service/src/main/resources/application-test-e2e.yml b/apps/user-service/src/main/resources/application-test-e2e.yml index 7703f4a3..8759b298 100644 --- a/apps/user-service/src/main/resources/application-test-e2e.yml +++ b/apps/user-service/src/main/resources/application-test-e2e.yml @@ -6,7 +6,9 @@ spring: sql: init: mode: always - schema-locations: classpath:sql/schema.sql + schema-locations: + - classpath:sql/00-drop-maria.sql + - classpath:sql/01-schema.sql encoding: UTF-8 mybatis: diff --git a/apps/user-service/src/main/resources/application-test-unit.yml b/apps/user-service/src/main/resources/application-test-unit.yml index fec65f43..4b36c77f 100644 --- a/apps/user-service/src/main/resources/application-test-unit.yml +++ b/apps/user-service/src/main/resources/application-test-unit.yml @@ -37,7 +37,9 @@ spring: sql: init: mode: always - schema-locations: classpath:sql/schema.sql + schema-locations: + - classpath:sql/00-drop-h2.sql + - classpath:sql/01-schema.sql encoding: UTF-8 mybatis: diff --git a/apps/user-service/src/main/resources/mybatis/mapper/AuthMapper.xml b/apps/user-service/src/main/resources/mybatis/mapper/AuthMapper.xml index 0c36cc21..c503e76e 100644 --- a/apps/user-service/src/main/resources/mybatis/mapper/AuthMapper.xml +++ b/apps/user-service/src/main/resources/mybatis/mapper/AuthMapper.xml @@ -4,34 +4,30 @@ - - - INSERT INTO users (name, email, password) + INSERT INTO user (name, email, password) VALUES (#{name}, #{email}, #{password}); - - INSERT INTO user_organizations (user_id, organization_id, department_id, position_id, status) - VALUES (#{id}, #{orgId}, #{deptId}, #{positionId}, #{status}); + INSERT INTO user_organization (user_id, organization_id, department_id, position_id, status) + VALUES (#{id}, #{organizationId}, #{departmentId}, #{positionId}, #{status}); - - INSERT INTO user_roles (user_organization_id, role_id) + INSERT INTO user_role (user_organization_id, role_id) VALUES (#{userOrgId}, #{roleId}) - + \ No newline at end of file diff --git a/apps/user-service/src/main/resources/mybatis/mapper/OrganizationMapper.xml b/apps/user-service/src/main/resources/mybatis/mapper/OrganizationMapper.xml index cdc403fb..6a8201b8 100644 --- a/apps/user-service/src/main/resources/mybatis/mapper/OrganizationMapper.xml +++ b/apps/user-service/src/main/resources/mybatis/mapper/OrganizationMapper.xml @@ -14,7 +14,7 @@ diff --git a/apps/user-service/src/main/resources/sql/00-drop-h2.sql b/apps/user-service/src/main/resources/sql/00-drop-h2.sql new file mode 100644 index 00000000..d0c7bda3 --- /dev/null +++ b/apps/user-service/src/main/resources/sql/00-drop-h2.sql @@ -0,0 +1,6 @@ +SET FOREIGN_KEY_CHECKS = 0; + +-- H2에서 모든 테이블과 객체를 삭제하는 올바른 구문 +DROP ALL OBJECTS; + +SET FOREIGN_KEY_CHECKS = 1; \ No newline at end of file diff --git a/apps/user-service/src/main/resources/sql/00-drop-maria.sql b/apps/user-service/src/main/resources/sql/00-drop-maria.sql new file mode 100644 index 00000000..d93b57b4 --- /dev/null +++ b/apps/user-service/src/main/resources/sql/00-drop-maria.sql @@ -0,0 +1,18 @@ +SET FOREIGN_KEY_CHECKS = 0; +SET @tables = NULL; + +-- 1. 데이터베이스 내 모든 테이블 목록을 가져와 변수에 저장 +-- 백틱(`)을 사용하여 테이블 이름에 공백이나 특수 문자가 있어도 안전하게 처리합니다. +SELECT GROUP_CONCAT(CONCAT('`', table_name, '`')) INTO @tables +FROM information_schema.tables +WHERE table_schema = DATABASE(); + +-- 2. 변수 값이 NULL인 경우를 대비하여 조건문 추가 및 DROP TABLE 구문 생성 +SET @drop_tables_sql = IFNULL(CONCAT('DROP TABLE ', @tables), 'SELECT "No tables to drop";'); + +-- 3. 동적 SQL 실행 +PREPARE stmt FROM @drop_tables_sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +SET FOREIGN_KEY_CHECKS = 1; \ No newline at end of file diff --git a/apps/user-service/src/main/resources/sql/00-truncate.sql b/apps/user-service/src/main/resources/sql/00-truncate.sql index 93cbfd4a..497b6a4e 100644 --- a/apps/user-service/src/main/resources/sql/00-truncate.sql +++ b/apps/user-service/src/main/resources/sql/00-truncate.sql @@ -1,15 +1,12 @@ --- 데이터 초기화 전에 추가 -SET FOREIGN_KEY_CHECKS = 0; +-- 데이터 초기화 스크립트 (외래 키 제약조건이 없는 스키마용) --- 역순으로 TRUNCATE (참조되는 테이블을 나중에) -TRUNCATE TABLE user_roles; -TRUNCATE TABLE role_permissions; -TRUNCATE TABLE user_organizations; -TRUNCATE TABLE users; -TRUNCATE TABLE positions; -TRUNCATE TABLE departments; -TRUNCATE TABLE roles; -TRUNCATE TABLE permissions; -TRUNCATE TABLE organizations; - -SET FOREIGN_KEY_CHECKS = 1; \ No newline at end of file +-- 사용자 및 조직 관련 테이블 +TRUNCATE TABLE `user_role`; +TRUNCATE TABLE `role_permission`; +TRUNCATE TABLE `user_organization`; +TRUNCATE TABLE `user`; +TRUNCATE TABLE `position`; +TRUNCATE TABLE `department`; +TRUNCATE TABLE `role`; +TRUNCATE TABLE `permission`; +TRUNCATE TABLE `organization`; \ No newline at end of file diff --git a/apps/user-service/src/main/resources/sql/01-insert-internal-users.sql b/apps/user-service/src/main/resources/sql/01-insert-internal-users.sql index 29f1f81a..3a8529c8 100644 --- a/apps/user-service/src/main/resources/sql/01-insert-internal-users.sql +++ b/apps/user-service/src/main/resources/sql/01-insert-internal-users.sql @@ -1,29 +1,31 @@ -- icebang 내부 직원 전체 INSERT -- 1. icebang 조직 -INSERT INTO `organizations` (`name`, `domain_name`) VALUES +INSERT INTO `organization` (`name`, `domain_name`) VALUES ('icebang', 'icebang.site'); -- 2. icebang 부서들 -INSERT INTO `departments` (`organization_id`, `name`) VALUES - ((SELECT id FROM organizations WHERE domain_name = 'icebang.site'), 'AI개발팀'), - ((SELECT id FROM organizations WHERE domain_name = 'icebang.site'), '데이터팀'), - ((SELECT id FROM organizations WHERE domain_name = 'icebang.site'), '콘텐츠팀'), - ((SELECT id FROM organizations WHERE domain_name = 'icebang.site'), '마케팅팀'), - ((SELECT id FROM organizations WHERE domain_name = 'icebang.site'), '운영팀'), - ((SELECT id FROM organizations WHERE domain_name = 'icebang.site'), '기획팀'); +SET @org_id = (SELECT id FROM organization WHERE domain_name = 'icebang.site' LIMIT 1); + +INSERT INTO `department` (`organization_id`, `name`) VALUES + (@org_id, 'AI개발팀'), + (@org_id, '데이터팀'), + (@org_id, '콘텐츠팀'), + (@org_id, '마케팅팀'), + (@org_id, '운영팀'), + (@org_id, '기획팀'); -- 3. icebang 직책들 -INSERT INTO `positions` (`organization_id`, `title`) VALUES - ((SELECT id FROM organizations WHERE domain_name = 'icebang.site'), 'CEO'), - ((SELECT id FROM organizations WHERE domain_name = 'icebang.site'), 'CTO'), - ((SELECT id FROM organizations WHERE domain_name = 'icebang.site'), '팀장'), - ((SELECT id FROM organizations WHERE domain_name = 'icebang.site'), '시니어'), - ((SELECT id FROM organizations WHERE domain_name = 'icebang.site'), '주니어'), - ((SELECT id FROM organizations WHERE domain_name = 'icebang.site'), '인턴'); +INSERT INTO `position` (`organization_id`, `title`) VALUES + (@org_id, 'CEO'), + (@org_id, 'CTO'), + (@org_id, '팀장'), + (@org_id, '시니어'), + (@org_id, '주니어'), + (@org_id, '인턴'); -- 4. 바이럴 콘텐츠 워크플로우 권한들 -INSERT INTO `permissions` (`resource`, `description`) VALUES +INSERT INTO `permission` (`resource`, `description`) VALUES -- 사용자 관리 ('users.create', '사용자 생성'), ('users.read', '사용자 조회'), @@ -117,145 +119,93 @@ INSERT INTO `permissions` (`resource`, `description`) VALUES ('system.backup.restore', '시스템 백업 복원'); -- 5. 시스템 공통 역할 -INSERT INTO `roles` (`organization_id`, `name`, `description`) VALUES - (NULL, 'SUPER_ADMIN', '최고 관리자 - 모든 권한'), - (NULL, 'SYSTEM_ADMIN', '시스템 관리자 - 시스템 설정 및 관리'), - (NULL, 'ORG_ADMIN', '조직 관리자 - 조직 내 모든 권한'), - (NULL, 'USER', '일반 사용자 - 기본 사용 권한'), - (NULL, 'GUEST', '게스트 - 제한된 조회 권한'); +INSERT INTO `role` (`organization_id`, `name`, `description`) VALUES + (NULL, 'SUPER_ADMIN', '최고 관리자 - 모든 권한'), + (NULL, 'SYSTEM_ADMIN', '시스템 관리자 - 시스템 설정 및 관리'), + (NULL, 'ORG_ADMIN', '조직 관리자 - 조직 내 모든 권한'), + (NULL, 'USER', '일반 사용자 - 기본 사용 권한'), + (NULL, 'GUEST', '게스트 - 제한된 조회 권한'); -- 6. icebang 전용 역할 -INSERT INTO `roles` (`organization_id`, `name`, `description`) VALUES - ((SELECT id FROM organizations WHERE domain_name = 'icebang.site'), 'AI_ENGINEER', 'AI 엔지니어 - AI 모델 개발 및 최적화'), - ((SELECT id FROM organizations WHERE domain_name = 'icebang.site'), 'DATA_SCIENTIST', '데이터 사이언티스트 - 데이터 분석 및 인사이트 도출'), - ((SELECT id FROM organizations WHERE domain_name = 'icebang.site'), 'CRAWLING_ENGINEER', '크롤링 엔지니어 - 웹 크롤링 시스템 개발'), - ((SELECT id FROM organizations WHERE domain_name = 'icebang.site'), 'CONTENT_CREATOR', '콘텐츠 크리에이터 - 바이럴 콘텐츠 제작'), - ((SELECT id FROM organizations WHERE domain_name = 'icebang.site'), 'CONTENT_MANAGER', '콘텐츠 매니저 - 콘텐츠 기획 및 관리'), - ((SELECT id FROM organizations WHERE domain_name = 'icebang.site'), 'WORKFLOW_ADMIN', '워크플로우 관리자 - 자동화 프로세스 관리'), - ((SELECT id FROM organizations WHERE domain_name = 'icebang.site'), 'MARKETING_ANALYST', '마케팅 분석가 - 마케팅 성과 분석'), - ((SELECT id FROM organizations WHERE domain_name = 'icebang.site'), 'OPERATIONS_MANAGER', '운영 매니저 - 시스템 운영 및 모니터링'); +INSERT INTO `role` (`organization_id`, `name`, `description`) VALUES + (@org_id, 'AI_ENGINEER', 'AI 엔지니어 - AI 모델 개발 및 최적화'), + (@org_id, 'DATA_SCIENTIST', '데이터 사이언티스트 - 데이터 분석 및 인사이트 도출'), + (@org_id, 'CRAWLING_ENGINEER', '크롤링 엔지니어 - 웹 크롤링 시스템 개발'), + (@org_id, 'CONTENT_CREATOR', '콘텐츠 크리에이터 - 바이럴 콘텐츠 제작'), + (@org_id, 'CONTENT_MANAGER', '콘텐츠 매니저 - 콘텐츠 기획 및 관리'), + (@org_id, 'WORKFLOW_ADMIN', '워크플로우 관리자 - 자동화 프로세스 관리'), + (@org_id, 'MARKETING_ANALYST', '마케팅 분석가 - 마케팅 성과 분석'), + (@org_id, 'OPERATIONS_MANAGER', '운영 매니저 - 시스템 운영 및 모니터링'); -- 7. icebang 직원들 -INSERT INTO `users` (`name`, `email`, `password`, `status`) VALUES - ('김아이스', 'ice.kim@icebang.site', '$2a$10$encrypted_password_hash1', 'ACTIVE'), - ('박방방', 'bang.park@icebang.site', '$2a$10$encrypted_password_hash2', 'ACTIVE'), - ('이트렌드', 'trend.lee@icebang.site', '$2a$10$encrypted_password_hash3', 'ACTIVE'), - ('정바이럴', 'viral.jung@icebang.site', '$2a$10$encrypted_password_hash4', 'ACTIVE'), - ('최콘텐츠', 'content.choi@icebang.site', '$2a$10$encrypted_password_hash5', 'ACTIVE'), - ('홍크롤러', 'crawler.hong@icebang.site', '$2a$10$encrypted_password_hash6', 'ACTIVE'), - ('서데이터', 'data.seo@icebang.site', '$2a$10$encrypted_password_hash7', 'ACTIVE'), - ('윤워크플로', 'workflow.yoon@icebang.site', '$2a$10$encrypted_password_hash8', 'ACTIVE'), - ('시스템관리자', 'admin@icebang.site', '$2a$10$encrypted_password_hash0', 'ACTIVE'); +INSERT INTO `user` (`name`, `email`, `password`, `status`) VALUES + ('김아이스', 'ice.kim@icebang.site', '$2a$10$encrypted_password_hash1', 'ACTIVE'), + ('박방방', 'bang.park@icebang.site', '$2a$10$encrypted_password_hash2', 'ACTIVE'), + ('이트렌드', 'trend.lee@icebang.site', '$2a$10$encrypted_password_hash3', 'ACTIVE'), + ('정바이럴', 'viral.jung@icebang.site', '$2a$10$encrypted_password_hash4', 'ACTIVE'), + ('최콘텐츠', 'content.choi@icebang.site', '$2a$10$encrypted_password_hash5', 'ACTIVE'), + ('홍크롤러', 'crawler.hong@icebang.site', '$2a$10$encrypted_password_hash6', 'ACTIVE'), + ('서데이터', 'data.seo@icebang.site', '$2a$10$encrypted_password_hash7', 'ACTIVE'), + ('윤워크플로', 'workflow.yoon@icebang.site', '$2a$10$encrypted_password_hash8', 'ACTIVE'), + ('시스템관리자', 'admin@icebang.site', '$2a$10$encrypted_password_hash0', 'ACTIVE'); -- 8. icebang 직원-조직 연결 -INSERT INTO `user_organizations` (`user_id`, `organization_id`, `position_id`, `department_id`, `employee_number`, `status`) VALUES --- 김아이스 - CEO, 기획팀 -((SELECT id FROM users WHERE email = 'ice.kim@icebang.site'), - (SELECT id FROM organizations WHERE domain_name = 'icebang.site'), - (SELECT id FROM positions WHERE title = 'CEO' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'icebang.site')), - (SELECT id FROM departments WHERE name = '기획팀' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'icebang.site')), - 'PLN25001', 'ACTIVE'), - --- 박방방 - CTO, AI개발팀 -((SELECT id FROM users WHERE email = 'bang.park@icebang.site'), - (SELECT id FROM organizations WHERE domain_name = 'icebang.site'), - (SELECT id FROM positions WHERE title = 'CTO' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'icebang.site')), - (SELECT id FROM departments WHERE name = 'AI개발팀' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'icebang.site')), - 'AI25001', 'ACTIVE'), - --- 이트렌드 - 팀장, 데이터팀 -((SELECT id FROM users WHERE email = 'trend.lee@icebang.site'), - (SELECT id FROM organizations WHERE domain_name = 'icebang.site'), - (SELECT id FROM positions WHERE title = '팀장' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'icebang.site')), - (SELECT id FROM departments WHERE name = '데이터팀' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'icebang.site')), - 'DAT25001', 'ACTIVE'), - --- 정바이럴 - 팀장, 콘텐츠팀 -((SELECT id FROM users WHERE email = 'viral.jung@icebang.site'), - (SELECT id FROM organizations WHERE domain_name = 'icebang.site'), - (SELECT id FROM positions WHERE title = '팀장' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'icebang.site')), - (SELECT id FROM departments WHERE name = '콘텐츠팀' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'icebang.site')), - 'CON25001', 'ACTIVE'), - -((SELECT id FROM users WHERE email = 'content.choi@icebang.site'), - (SELECT id FROM organizations WHERE domain_name = 'icebang.site'), - (SELECT id FROM positions WHERE title = '시니어' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'icebang.site')), - (SELECT id FROM departments WHERE name = '콘텐츠팀' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'icebang.site')), - 'CON25002', 'ACTIVE'), - --- 홍크롤러 - 시니어, AI개발팀 -((SELECT id FROM users WHERE email = 'crawler.hong@icebang.site'), - (SELECT id FROM organizations WHERE domain_name = 'icebang.site'), - (SELECT id FROM positions WHERE title = '시니어' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'icebang.site')), - (SELECT id FROM departments WHERE name = 'AI개발팀' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'icebang.site')), - 'AI25002', 'ACTIVE'), - --- 서데이터 - 시니어, 데이터팀 -((SELECT id FROM users WHERE email = 'data.seo@icebang.site'), - (SELECT id FROM organizations WHERE domain_name = 'icebang.site'), - (SELECT id FROM positions WHERE title = '시니어' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'icebang.site')), - (SELECT id FROM departments WHERE name = '데이터팀' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'icebang.site')), - 'DAT25002', 'ACTIVE'), - --- 윤워크플로 - 팀장, 운영팀 -((SELECT id FROM users WHERE email = 'workflow.yoon@icebang.site'), - (SELECT id FROM organizations WHERE domain_name = 'icebang.site'), - (SELECT id FROM positions WHERE title = '팀장' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'icebang.site')), - (SELECT id FROM departments WHERE name = '운영팀' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'icebang.site')), - 'OPS25001', 'ACTIVE'), - --- 시스템관리자 - CTO, 운영팀 -((SELECT id FROM users WHERE email = 'admin@icebang.site'), - (SELECT id FROM organizations WHERE domain_name = 'icebang.site'), - (SELECT id FROM positions WHERE title = 'CTO' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'icebang.site')), - (SELECT id FROM departments WHERE name = '운영팀' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'icebang.site')), - 'OPS25000', 'ACTIVE'); +INSERT INTO `user_organization` (`user_id`, `organization_id`, `position_id`, `department_id`, `employee_number`, `status`) VALUES + ((SELECT id FROM user WHERE email = 'ice.kim@icebang.site'), @org_id, (SELECT id FROM position WHERE title = 'CEO' AND organization_id = @org_id), (SELECT id FROM department WHERE name = '기획팀' AND organization_id = @org_id), 'PLN25001', 'ACTIVE'), + ((SELECT id FROM user WHERE email = 'bang.park@icebang.site'), @org_id, (SELECT id FROM position WHERE title = 'CTO' AND organization_id = @org_id), (SELECT id FROM department WHERE name = 'AI개발팀' AND organization_id = @org_id), 'AI25001', 'ACTIVE'), + ((SELECT id FROM user WHERE email = 'trend.lee@icebang.site'), @org_id, (SELECT id FROM position WHERE title = '팀장' AND organization_id = @org_id), (SELECT id FROM department WHERE name = '데이터팀' AND organization_id = @org_id), 'DAT25001', 'ACTIVE'), + ((SELECT id FROM user WHERE email = 'viral.jung@icebang.site'), @org_id, (SELECT id FROM position WHERE title = '팀장' AND organization_id = @org_id), (SELECT id FROM department WHERE name = '콘텐츠팀' AND organization_id = @org_id), 'CON25001', 'ACTIVE'), + ((SELECT id FROM user WHERE email = 'content.choi@icebang.site'), @org_id, (SELECT id FROM position WHERE title = '시니어' AND organization_id = @org_id), (SELECT id FROM department WHERE name = '콘텐츠팀' AND organization_id = @org_id), 'CON25002', 'ACTIVE'), + ((SELECT id FROM user WHERE email = 'crawler.hong@icebang.site'), @org_id, (SELECT id FROM position WHERE title = '시니어' AND organization_id = @org_id), (SELECT id FROM department WHERE name = 'AI개발팀' AND organization_id = @org_id), 'AI25002', 'ACTIVE'), + ((SELECT id FROM user WHERE email = 'data.seo@icebang.site'), @org_id, (SELECT id FROM position WHERE title = '시니어' AND organization_id = @org_id), (SELECT id FROM department WHERE name = '데이터팀' AND organization_id = @org_id), 'DAT25002', 'ACTIVE'), + ((SELECT id FROM user WHERE email = 'workflow.yoon@icebang.site'), @org_id, (SELECT id FROM position WHERE title = '팀장' AND organization_id = @org_id), (SELECT id FROM department WHERE name = '운영팀' AND organization_id = @org_id), 'OPS25001', 'ACTIVE'), + ((SELECT id FROM user WHERE email = 'admin@icebang.site'), @org_id, (SELECT id FROM position WHERE title = 'CTO' AND organization_id = @org_id), (SELECT id FROM department WHERE name = '운영팀' AND organization_id = @org_id), 'OPS25000', 'ACTIVE'); -- 9. 역할별 권한 할당 -- SUPER_ADMIN 모든 권한 -INSERT INTO `role_permissions` (`role_id`, `permission_id`) +INSERT INTO `role_permission` (`role_id`, `permission_id`) SELECT - (SELECT id FROM roles WHERE name = 'SUPER_ADMIN'), + (SELECT id FROM role WHERE name = 'SUPER_ADMIN'), id -FROM permissions; +FROM permission; -- ORG_ADMIN 조직 내 모든 권한 (시스템 권한 제외) -INSERT INTO `role_permissions` (`role_id`, `permission_id`) +INSERT INTO `role_permission` (`role_id`, `permission_id`) SELECT - (SELECT id FROM roles WHERE name = 'ORG_ADMIN'), + (SELECT id FROM role WHERE name = 'ORG_ADMIN'), id -FROM permissions +FROM permission WHERE resource NOT LIKE 'system.%'; -- AI_ENGINEER 권한 -INSERT INTO `role_permissions` (`role_id`, `permission_id`) +INSERT INTO `role_permission` (`role_id`, `permission_id`) SELECT - (SELECT id FROM roles WHERE name = 'AI_ENGINEER' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'icebang.site')), + (SELECT id FROM role WHERE name = 'AI_ENGINEER' AND organization_id = @org_id), id -FROM permissions +FROM permission WHERE resource LIKE 'ai.%' OR resource LIKE 'crawling.%' OR resource LIKE 'workflows.%' OR resource IN ('content.read', 'trends.read', 'analytics.read'); -- DATA_SCIENTIST 권한 -INSERT INTO `role_permissions` (`role_id`, `permission_id`) +INSERT INTO `role_permission` (`role_id`, `permission_id`) SELECT - (SELECT id FROM roles WHERE name = 'DATA_SCIENTIST' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'icebang.site')), + (SELECT id FROM role WHERE name = 'DATA_SCIENTIST' AND organization_id = @org_id), id -FROM permissions +FROM permission WHERE resource LIKE 'trends.%' OR resource LIKE 'analytics.%' OR resource LIKE 'reports.%' OR resource IN ('content.read', 'campaigns.read', 'crawling.read'); -- CONTENT_MANAGER 권한 -INSERT INTO `role_permissions` (`role_id`, `permission_id`) +INSERT INTO `role_permission` (`role_id`, `permission_id`) SELECT - (SELECT id FROM roles WHERE name = 'CONTENT_MANAGER' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'icebang.site')), + (SELECT id FROM role WHERE name = 'CONTENT_MANAGER' AND organization_id = @org_id), id -FROM permissions +FROM permission WHERE resource LIKE 'content.%' OR resource LIKE 'campaigns.%' OR resource LIKE 'trends.%' @@ -263,11 +213,11 @@ WHERE resource LIKE 'content.%' OR resource IN ('users.read.department'); -- WORKFLOW_ADMIN 권한 -INSERT INTO `role_permissions` (`role_id`, `permission_id`) +INSERT INTO `role_permission` (`role_id`, `permission_id`) SELECT - (SELECT id FROM roles WHERE name = 'WORKFLOW_ADMIN' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'icebang.site')), + (SELECT id FROM role WHERE name = 'WORKFLOW_ADMIN' AND organization_id = @org_id), id -FROM permissions +FROM permission WHERE resource LIKE 'workflows.%' OR resource LIKE 'ai.%' OR resource LIKE 'crawling.%' @@ -277,54 +227,54 @@ WHERE resource LIKE 'workflows.%' -- 10. icebang 직원별 역할 할당 -- 김아이스(CEO) - ORG_ADMIN -INSERT INTO `user_roles` (`role_id`, `user_organization_id`) +INSERT INTO `user_role` (`role_id`, `user_organization_id`) SELECT - (SELECT id FROM roles WHERE name = 'ORG_ADMIN'), + (SELECT id FROM role WHERE name = 'ORG_ADMIN'), uo.id -FROM user_organizations uo - JOIN users u ON u.id = uo.user_id +FROM user_organization uo + JOIN user u ON u.id = uo.user_id WHERE u.email = 'ice.kim@icebang.site'; -- 박방방(CTO) - AI_ENGINEER + WORKFLOW_ADMIN -INSERT INTO `user_roles` (`role_id`, `user_organization_id`) +INSERT INTO `user_role` (`role_id`, `user_organization_id`) SELECT - (SELECT id FROM roles WHERE name = 'AI_ENGINEER' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'icebang.site')), + (SELECT id FROM role WHERE name = 'AI_ENGINEER' AND organization_id = @org_id), uo.id -FROM user_organizations uo - JOIN users u ON u.id = uo.user_id +FROM user_organization uo + JOIN user u ON u.id = uo.user_id WHERE u.email = 'bang.park@icebang.site'; -INSERT INTO `user_roles` (`role_id`, `user_organization_id`) +INSERT INTO `user_role` (`role_id`, `user_organization_id`) SELECT - (SELECT id FROM roles WHERE name = 'WORKFLOW_ADMIN' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'icebang.site')), + (SELECT id FROM role WHERE name = 'WORKFLOW_ADMIN' AND organization_id = @org_id), uo.id -FROM user_organizations uo - JOIN users u ON u.id = uo.user_id +FROM user_organization uo + JOIN user u ON u.id = uo.user_id WHERE u.email = 'bang.park@icebang.site'; -- 정바이럴(콘텐츠팀장) - CONTENT_MANAGER -INSERT INTO `user_roles` (`role_id`, `user_organization_id`) +INSERT INTO `user_role` (`role_id`, `user_organization_id`) SELECT - (SELECT id FROM roles WHERE name = 'CONTENT_MANAGER' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'icebang.site')), + (SELECT id FROM role WHERE name = 'CONTENT_MANAGER' AND organization_id = @org_id), uo.id -FROM user_organizations uo - JOIN users u ON u.id = uo.user_id +FROM user_organization uo + JOIN user u ON u.id = uo.user_id WHERE u.email = 'viral.jung@icebang.site'; -- 이트렌드(데이터팀장) - DATA_SCIENTIST -INSERT INTO `user_roles` (`role_id`, `user_organization_id`) +INSERT INTO `user_role` (`role_id`, `user_organization_id`) SELECT - (SELECT id FROM roles WHERE name = 'DATA_SCIENTIST' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'icebang.site')), + (SELECT id FROM role WHERE name = 'DATA_SCIENTIST' AND organization_id = @org_id), uo.id -FROM user_organizations uo - JOIN users u ON u.id = uo.user_id +FROM user_organization uo + JOIN user u ON u.id = uo.user_id WHERE u.email = 'trend.lee@icebang.site'; -- 시스템관리자 - SUPER_ADMIN -INSERT INTO `user_roles` (`role_id`, `user_organization_id`) +INSERT INTO `user_role` (`role_id`, `user_organization_id`) SELECT - (SELECT id FROM roles WHERE name = 'SUPER_ADMIN'), + (SELECT id FROM role WHERE name = 'SUPER_ADMIN'), uo.id -FROM user_organizations uo - JOIN users u ON u.id = uo.user_id +FROM user_organization uo + JOIN user u ON u.id = uo.user_id WHERE u.email = 'admin@icebang.site'; \ No newline at end of file diff --git a/apps/user-service/src/main/resources/sql/01-schema.sql b/apps/user-service/src/main/resources/sql/01-schema.sql new file mode 100644 index 00000000..138425fc --- /dev/null +++ b/apps/user-service/src/main/resources/sql/01-schema.sql @@ -0,0 +1,289 @@ +-- MariaDB 최적화된 스키마 (단수형 테이블 네이밍, 외래 키 제약조건 제거 버전) +CREATE TABLE `permission` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `resource` varchar(100) NULL, + `description` varchar(255) NULL, + `created_at` timestamp DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `is_active` boolean DEFAULT TRUE, + `updated_by` bigint unsigned NULL, + `created_by` bigint unsigned NULL, + PRIMARY KEY (`id`) + ); + +CREATE TABLE `organization` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(150) NULL, + `domain_name` varchar(100) NULL, + `created_at` timestamp DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) + ); + +CREATE TABLE `role` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `organization_id` bigint unsigned NULL, + `name` varchar(100) NULL, + `description` varchar(500) NULL, + PRIMARY KEY (`id`) + ); + +CREATE TABLE `user` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(50) NULL, + `email` varchar(100) NULL, + `password` varchar(255) NULL, + `status` varchar(20) NULL, + `created_at` timestamp DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) + ); + +CREATE TABLE `department` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `organization_id` bigint unsigned NOT NULL, + `name` varchar(100) NULL, + PRIMARY KEY (`id`) + ); + +CREATE TABLE `position` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `organization_id` bigint unsigned NOT NULL, + `title` varchar(100) NULL, + PRIMARY KEY (`id`) + ); + +CREATE TABLE `user_organization` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `user_id` bigint unsigned NOT NULL, + `organization_id` bigint unsigned NOT NULL, + `position_id` bigint unsigned NOT NULL, + `department_id` bigint unsigned NOT NULL, + `employee_number` varchar(50) NULL, + `status` varchar(20) NULL, + `created_at` timestamp DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) + ); + +CREATE TABLE `role_permission` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `role_id` bigint unsigned NOT NULL, + `permission_id` int unsigned NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `uk_role_permission` (`role_id`, `permission_id`) + ); + +CREATE TABLE `user_role` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `role_id` bigint unsigned NOT NULL, + `user_organization_id` bigint unsigned NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `uk_user_role` (`role_id`, `user_organization_id`) + ); + +-- 성능 최적화를 위한 인덱스 +CREATE INDEX `idx_user_email` ON `user` (`email`); +CREATE INDEX `idx_user_status` ON `user` (`status`); +CREATE INDEX `idx_user_organization_user` ON `user_organization` (`user_id`); +CREATE INDEX `idx_user_organization_org` ON `user_organization` (`organization_id`); +CREATE INDEX `idx_user_organization_status` ON `user_organization` (`status`); +CREATE INDEX `idx_role_org` ON `role` (`organization_id`); +CREATE INDEX `idx_permission_resource` ON `permission` (`resource`); +CREATE INDEX `idx_permission_active` ON `permission` (`is_active`); + + + +CREATE TABLE `workflow` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(100) NOT NULL UNIQUE, + `description` text NULL, + `is_enabled` boolean DEFAULT TRUE, + `created_at` timestamp DEFAULT CURRENT_TIMESTAMP, + `created_by` bigint unsigned NULL, + `updated_at` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `updated_by` bigint unsigned NULL, + PRIMARY KEY (`id`) + ); + +CREATE TABLE `schedule` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `workflow_id` bigint unsigned NOT NULL, + `cron_expression` varchar(50) NULL, + `parameters` json NULL, + `is_active` boolean DEFAULT TRUE, + `last_run_status` varchar(20) NULL, + `last_run_at` timestamp NULL, + `created_at` timestamp DEFAULT CURRENT_TIMESTAMP, + `created_by` bigint unsigned NULL, + `updated_at` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `updated_by` bigint unsigned NULL, + PRIMARY KEY (`id`) + ); + +CREATE TABLE `job` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(100) NOT NULL UNIQUE, + `description` text NULL, + `is_enabled` boolean DEFAULT TRUE, + `created_at` timestamp DEFAULT CURRENT_TIMESTAMP, + `created_by` bigint unsigned NULL, + `updated_at` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `updated_by` bigint unsigned NULL, + PRIMARY KEY (`id`) + ); + +CREATE TABLE `task` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(100) NOT NULL UNIQUE, + `type` varchar(50) NULL, + `parameters` json NULL, + `created_at` timestamp DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) + ); + +CREATE TABLE `workflow_job` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `workflow_id` bigint unsigned NOT NULL, + `job_id` bigint unsigned NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `uk_workflow_job` (`workflow_id`, `job_id`) + ); + +CREATE TABLE `job_task` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `job_id` bigint unsigned NOT NULL, + `task_id` bigint unsigned NOT NULL, + `execution_order` int NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `uk_job_task` (`job_id`, `task_id`) + ); + +CREATE TABLE `execution_log` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `execution_type` varchar(20) NULL COMMENT 'task, schedule, job, workflow', + `source_id` bigint unsigned NULL COMMENT '모든 데이터에 대한 ID ex: job_id, schedule_id, task_id, ...', + `log_level` varchar(20) NULL, + `executed_at` timestamp DEFAULT CURRENT_TIMESTAMP, + `log_message` text NULL, + `trace_id` char(36) NULL, + `config_snapshot` json NULL, + PRIMARY KEY (`id`), + INDEX `idx_source_id_type` (`source_id`, `execution_type`) + ); + +CREATE TABLE `task_io_data` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `task_run_id` bigint unsigned NOT NULL, + `io_type` varchar(10) NOT NULL COMMENT 'INPUT, OUTPUT', + `name` varchar(100) NOT NULL COMMENT '파라미터/변수 이름', + `data_type` varchar(50) NOT NULL COMMENT 'string, number, json, file, etc', + `data_value` json NULL COMMENT '실제 데이터 값', + `data_size` bigint NULL COMMENT '데이터 크기 (bytes)', + `created_at` timestamp DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + INDEX `idx_task_io_task_run_id` (`task_run_id`), + INDEX `idx_task_io_type` (`io_type`), + INDEX `idx_task_io_name` (`name`) + ); + +CREATE TABLE `config` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `target_type` varchar(50) NULL COMMENT 'user, job, workflow', + `target_id` bigint unsigned NULL, + `version` int NULL, + `json` json NULL, + `is_active` boolean DEFAULT TRUE, + `created_at` timestamp DEFAULT CURRENT_TIMESTAMP, + `created_by` bigint unsigned NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `uk_config_target` (`target_type`, `target_id`) + ); + +CREATE TABLE `category` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(100) NULL, + `description` text NULL, + `created_at` timestamp DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) + ); + +CREATE TABLE `user_config` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `user_id` bigint unsigned NOT NULL, + `type` varchar(50) NULL, + `name` varchar(100) NULL, + `json` json NULL, + `is_active` boolean DEFAULT TRUE, + `created_at` timestamp DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) + ); + +-- 인덱스 추가 (성능 최적화) +CREATE INDEX `idx_schedule_workflow` ON `schedule` (`workflow_id`); +CREATE INDEX `idx_job_enabled` ON `job` (`is_enabled`); +CREATE INDEX `idx_task_type` ON `task` (`type`); +CREATE INDEX `idx_workflow_enabled` ON `workflow` (`is_enabled`); +CREATE UNIQUE INDEX `uk_schedule_workflow` ON `schedule` (`workflow_id`); +CREATE UNIQUE INDEX `uk_job_name` ON `job` (`name`); +CREATE UNIQUE INDEX `uk_task_name` ON `task` (`name`); +CREATE UNIQUE INDEX `uk_workflow_name` ON `workflow` (`name`); +CREATE INDEX `idx_user_config_user` ON `user_config` (`user_id`); + + + +-- 워크플로우 실행 테이블 +CREATE TABLE `workflow_run` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `workflow_id` bigint unsigned NOT NULL, + `trace_id` char(36) NOT NULL, + `run_number` varchar(20) NULL, + `status` varchar(20) NULL COMMENT 'pending, running, success, failed, cancelled', + `trigger_type` varchar(20) NULL COMMENT 'manual, schedule, push, pull_request', + `started_at` timestamp NULL, + `finished_at` timestamp NULL, + `created_by` bigint unsigned NULL, + `created_at` timestamp DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `uk_workflow_run_trace` (`trace_id`), + INDEX `idx_workflow_run_status` (`status`), + INDEX `idx_workflow_run_workflow_id` (`workflow_id`), + INDEX `idx_workflow_run_created_at` (`created_at`) + ); + +-- Job 실행 테이블 +CREATE TABLE `job_run` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `workflow_run_id` bigint unsigned NOT NULL, + `job_id` bigint unsigned NOT NULL, + `status` varchar(20) NULL COMMENT 'pending, running, success, failed, cancelled, skipped', + `started_at` timestamp NULL, + `finished_at` timestamp NULL, + `execution_order` int NULL, + `created_at` timestamp DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + INDEX `idx_job_run_workflow_run_id` (`workflow_run_id`), + INDEX `idx_job_run_status` (`status`), + INDEX `idx_job_run_job_id` (`job_id`) + ); + +-- Task 실행 테이블 +CREATE TABLE `task_run` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `job_run_id` bigint unsigned NOT NULL, + `task_id` bigint unsigned NOT NULL, + `status` varchar(20) NULL COMMENT 'pending, running, success, failed, cancelled, skipped', + `started_at` timestamp NULL, + `finished_at` timestamp NULL, + `execution_order` int NULL, + `created_at` timestamp DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + INDEX `idx_task_run_job_run_id` (`job_run_id`), + INDEX `idx_task_run_status` (`status`), + INDEX `idx_task_run_task_id` (`task_id`) + ); + +CREATE INDEX `idx_task_io_data_task_run_id` ON `task_io_data` (`task_run_id`); \ No newline at end of file diff --git a/apps/user-service/src/main/resources/sql/02-insert-external-users.sql b/apps/user-service/src/main/resources/sql/02-insert-external-users.sql index f4620bbd..b38f2c47 100644 --- a/apps/user-service/src/main/resources/sql/02-insert-external-users.sql +++ b/apps/user-service/src/main/resources/sql/02-insert-external-users.sql @@ -1,86 +1,92 @@ -- B2B 테스트용 외부 회사 INSERT -- 1. 외부 테스트 회사들 -INSERT INTO `organizations` (`name`, `domain_name`) VALUES - ('테크이노베이션', 'techinnovation.co.kr'), - ('디지털솔루션', 'digitalsolution.com'), - ('크리에이티브웍스', 'creativeworks.net'); +INSERT INTO `organization` (`name`, `domain_name`) VALUES + ('테크이노베이션', 'techinnovation.co.kr'), + ('디지털솔루션', 'digitalsolution.com'), + ('크리에이티브웍스', 'creativeworks.net'); -- 2. 테크이노베이션 부서들 -INSERT INTO `departments` (`organization_id`, `name`) VALUES - ((SELECT id FROM organizations WHERE domain_name = 'techinnovation.co.kr'), '개발팀'), - ((SELECT id FROM organizations WHERE domain_name = 'techinnovation.co.kr'), '디자인팀'), - ((SELECT id FROM organizations WHERE domain_name = 'techinnovation.co.kr'), '인사팀'), - ((SELECT id FROM organizations WHERE domain_name = 'techinnovation.co.kr'), '마케팅팀'), - ((SELECT id FROM organizations WHERE domain_name = 'techinnovation.co.kr'), '영업팀'), - ((SELECT id FROM organizations WHERE domain_name = 'techinnovation.co.kr'), '재무팀'); +SET @tech_org_id = (SELECT id FROM organization WHERE domain_name = 'techinnovation.co.kr' LIMIT 1); + +INSERT INTO `department` (`organization_id`, `name`) VALUES + (@tech_org_id, '개발팀'), + (@tech_org_id, '디자인팀'), + (@tech_org_id, '인사팀'), + (@tech_org_id, '마케팅팀'), + (@tech_org_id, '영업팀'), + (@tech_org_id, '재무팀'); -- 3. 디지털솔루션 부서들 -INSERT INTO `departments` (`organization_id`, `name`) VALUES - ((SELECT id FROM organizations WHERE domain_name = 'digitalsolution.com'), '개발팀'), - ((SELECT id FROM organizations WHERE domain_name = 'digitalsolution.com'), '기획팀'), - ((SELECT id FROM organizations WHERE domain_name = 'digitalsolution.com'), '운영팀'); +SET @digital_org_id = (SELECT id FROM organization WHERE domain_name = 'digitalsolution.com' LIMIT 1); + +INSERT INTO `department` (`organization_id`, `name`) VALUES + (@digital_org_id, '개발팀'), + (@digital_org_id, '기획팀'), + (@digital_org_id, '운영팀'); -- 4. 크리에이티브웍스 부서들 -INSERT INTO `departments` (`organization_id`, `name`) VALUES - ((SELECT id FROM organizations WHERE domain_name = 'creativeworks.net'), '디자인팀'), - ((SELECT id FROM organizations WHERE domain_name = 'creativeworks.net'), '마케팅팀'), - ((SELECT id FROM organizations WHERE domain_name = 'creativeworks.net'), '제작팀'); +SET @creative_org_id = (SELECT id FROM organization WHERE domain_name = 'creativeworks.net' LIMIT 1); + +INSERT INTO `department` (`organization_id`, `name`) VALUES + (@creative_org_id, '디자인팀'), + (@creative_org_id, '마케팅팀'), + (@creative_org_id, '제작팀'); -- 5. 테크이노베이션 직책들 -INSERT INTO `positions` (`organization_id`, `title`) VALUES - ((SELECT id FROM organizations WHERE domain_name = 'techinnovation.co.kr'), '사원'), - ((SELECT id FROM organizations WHERE domain_name = 'techinnovation.co.kr'), '주임'), - ((SELECT id FROM organizations WHERE domain_name = 'techinnovation.co.kr'), '대리'), - ((SELECT id FROM organizations WHERE domain_name = 'techinnovation.co.kr'), '과장'), - ((SELECT id FROM organizations WHERE domain_name = 'techinnovation.co.kr'), '차장'), - ((SELECT id FROM organizations WHERE domain_name = 'techinnovation.co.kr'), '부장'), - ((SELECT id FROM organizations WHERE domain_name = 'techinnovation.co.kr'), '이사'); +INSERT INTO `position` (`organization_id`, `title`) VALUES + (@tech_org_id, '사원'), + (@tech_org_id, '주임'), + (@tech_org_id, '대리'), + (@tech_org_id, '과장'), + (@tech_org_id, '차장'), + (@tech_org_id, '부장'), + (@tech_org_id, '이사'); -- 6. 디지털솔루션 직책들 -INSERT INTO `positions` (`organization_id`, `title`) VALUES - ((SELECT id FROM organizations WHERE domain_name = 'digitalsolution.com'), '사원'), - ((SELECT id FROM organizations WHERE domain_name = 'digitalsolution.com'), '선임'), - ((SELECT id FROM organizations WHERE domain_name = 'digitalsolution.com'), '책임'), - ((SELECT id FROM organizations WHERE domain_name = 'digitalsolution.com'), '수석'), - ((SELECT id FROM organizations WHERE domain_name = 'digitalsolution.com'), '팀장'), - ((SELECT id FROM organizations WHERE domain_name = 'digitalsolution.com'), '본부장'); +INSERT INTO `position` (`organization_id`, `title`) VALUES + (@digital_org_id, '사원'), + (@digital_org_id, '선임'), + (@digital_org_id, '책임'), + (@digital_org_id, '수석'), + (@digital_org_id, '팀장'), + (@digital_org_id, '본부장'); -- 7. 크리에이티브웍스 직책들 -INSERT INTO `positions` (`organization_id`, `title`) VALUES - ((SELECT id FROM organizations WHERE domain_name = 'creativeworks.net'), '주니어'), - ((SELECT id FROM organizations WHERE domain_name = 'creativeworks.net'), '시니어'), - ((SELECT id FROM organizations WHERE domain_name = 'creativeworks.net'), '리드'), - ((SELECT id FROM organizations WHERE domain_name = 'creativeworks.net'), '디렉터'); +INSERT INTO `position` (`organization_id`, `title`) VALUES + (@creative_org_id, '주니어'), + (@creative_org_id, '시니어'), + (@creative_org_id, '리드'), + (@creative_org_id, '디렉터'); -- 8. 외부 회사별 커스텀 역할 -- 테크이노베이션 역할 -INSERT INTO `roles` (`organization_id`, `name`, `description`) VALUES - ((SELECT id FROM organizations WHERE domain_name = 'techinnovation.co.kr'), 'DEPT_MANAGER', '부서 관리자 - 부서 내 관리 권한'), - ((SELECT id FROM organizations WHERE domain_name = 'techinnovation.co.kr'), 'TEAM_LEAD', '팀장 - 팀원 관리 및 프로젝트 리드'), - ((SELECT id FROM organizations WHERE domain_name = 'techinnovation.co.kr'), 'SENIOR_DEV', '시니어 개발자 - 개발 관련 고급 권한'), - ((SELECT id FROM organizations WHERE domain_name = 'techinnovation.co.kr'), 'JUNIOR_DEV', '주니어 개발자 - 개발 관련 기본 권한'), - ((SELECT id FROM organizations WHERE domain_name = 'techinnovation.co.kr'), 'PROJECT_MANAGER', '프로젝트 매니저 - 프로젝트 관리 권한'), - ((SELECT id FROM organizations WHERE domain_name = 'techinnovation.co.kr'), 'DESIGNER', '디자이너 - 디자인 관련 권한'), - ((SELECT id FROM organizations WHERE domain_name = 'techinnovation.co.kr'), 'HR_SPECIALIST', '인사 담당자 - 인사 관리 권한'); +INSERT INTO `role` (`organization_id`, `name`, `description`) VALUES + (@tech_org_id, 'DEPT_MANAGER', '부서 관리자 - 부서 내 관리 권한'), + (@tech_org_id, 'TEAM_LEAD', '팀장 - 팀원 관리 및 프로젝트 리드'), + (@tech_org_id, 'SENIOR_DEV', '시니어 개발자 - 개발 관련 고급 권한'), + (@tech_org_id, 'JUNIOR_DEV', '주니어 개발자 - 개발 관련 기본 권한'), + (@tech_org_id, 'PROJECT_MANAGER', '프로젝트 매니저 - 프로젝트 관리 권한'), + (@tech_org_id, 'DESIGNER', '디자이너 - 디자인 관련 권한'), + (@tech_org_id, 'HR_SPECIALIST', '인사 담당자 - 인사 관리 권한'); -- 디지털솔루션 역할 -INSERT INTO `roles` (`organization_id`, `name`, `description`) VALUES - ((SELECT id FROM organizations WHERE domain_name = 'digitalsolution.com'), 'TECH_LEAD', '기술 리드 - 기술 관련 총괄'), - ((SELECT id FROM organizations WHERE domain_name = 'digitalsolution.com'), 'PRODUCT_OWNER', '프로덕트 오너 - 제품 기획 관리'), - ((SELECT id FROM organizations WHERE domain_name = 'digitalsolution.com'), 'QA_ENGINEER', 'QA 엔지니어 - 품질 보증'), - ((SELECT id FROM organizations WHERE domain_name = 'digitalsolution.com'), 'DEVOPS', 'DevOps 엔지니어 - 인프라 관리'); +INSERT INTO `role` (`organization_id`, `name`, `description`) VALUES + (@digital_org_id, 'TECH_LEAD', '기술 리드 - 기술 관련 총괄'), + (@digital_org_id, 'PRODUCT_OWNER', '프로덕트 오너 - 제품 기획 관리'), + (@digital_org_id, 'QA_ENGINEER', 'QA 엔지니어 - 품질 보증'), + (@digital_org_id, 'DEVOPS', 'DevOps 엔지니어 - 인프라 관리'); -- 크리에이티브웍스 역할 -INSERT INTO `roles` (`organization_id`, `name`, `description`) VALUES - ((SELECT id FROM organizations WHERE domain_name = 'creativeworks.net'), 'CREATIVE_DIRECTOR', '크리에이티브 디렉터 - 창작 총괄'), - ((SELECT id FROM organizations WHERE domain_name = 'creativeworks.net'), 'ART_DIRECTOR', '아트 디렉터 - 예술 감독'), - ((SELECT id FROM organizations WHERE domain_name = 'creativeworks.net'), 'MOTION_DESIGNER', '모션 디자이너 - 영상/애니메이션'), - ((SELECT id FROM organizations WHERE domain_name = 'creativeworks.net'), 'COPYWRITER', '카피라이터 - 콘텐츠 작성'); +INSERT INTO `role` (`organization_id`, `name`, `description`) VALUES + (@creative_org_id, 'CREATIVE_DIRECTOR', '크리에이티브 디렉터 - 창작 총괄'), + (@creative_org_id, 'ART_DIRECTOR', '아트 디렉터 - 예술 감독'), + (@creative_org_id, 'MOTION_DESIGNER', '모션 디자이너 - 영상/애니메이션'), + (@creative_org_id, 'COPYWRITER', '카피라이터 - 콘텐츠 작성'); -- 9. 외부 회사 테스트 사용자들 -INSERT INTO `users` (`name`, `email`, `password`, `status`) VALUES +INSERT INTO `user` (`name`, `email`, `password`, `status`) VALUES -- 테크이노베이션 직원 ('김철수', 'chulsoo.kim@techinnovation.co.kr', '$2a$10$encrypted_password_hash11', 'ACTIVE'), ('이영희', 'younghee.lee@techinnovation.co.kr', '$2a$10$encrypted_password_hash12', 'ACTIVE'), @@ -94,119 +100,80 @@ INSERT INTO `users` (`name`, `email`, `password`, `status`) VALUES ('홍지아', 'jia.hong@creativeworks.net', '$2a$10$encrypted_password_hash16', 'ACTIVE'); -- 10. 외부 회사 사용자-조직 연결 -INSERT INTO `user_organizations` (`user_id`, `organization_id`, `position_id`, `department_id`, `employee_number`, `status`) VALUES +INSERT INTO `user_organization` (`user_id`, `organization_id`, `position_id`, `department_id`, `employee_number`, `status`) VALUES -- 테크이노베이션 직원들 --- 김철수 - 개발팀 과장 -((SELECT id FROM users WHERE email = 'chulsoo.kim@techinnovation.co.kr'), - (SELECT id FROM organizations WHERE domain_name = 'techinnovation.co.kr'), - (SELECT id FROM positions WHERE title = '과장' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'techinnovation.co.kr')), - (SELECT id FROM departments WHERE name = '개발팀' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'techinnovation.co.kr')), - 'DEV25001', 'ACTIVE'), - --- 이영희 - 디자인팀 대리 -((SELECT id FROM users WHERE email = 'younghee.lee@techinnovation.co.kr'), - (SELECT id FROM organizations WHERE domain_name = 'techinnovation.co.kr'), - (SELECT id FROM positions WHERE title = '대리' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'techinnovation.co.kr')), - (SELECT id FROM departments WHERE name = '디자인팀' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'techinnovation.co.kr')), - 'DES25001', 'ACTIVE'), - --- 박민수 - 인사팀 차장 -((SELECT id FROM users WHERE email = 'minsu.park@techinnovation.co.kr'), - (SELECT id FROM organizations WHERE domain_name = 'techinnovation.co.kr'), - (SELECT id FROM positions WHERE title = '차장' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'techinnovation.co.kr')), - (SELECT id FROM departments WHERE name = '인사팀' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'techinnovation.co.kr')), - 'HR25001', 'ACTIVE'), +((SELECT id FROM user WHERE email = 'chulsoo.kim@techinnovation.co.kr'), @tech_org_id, (SELECT id FROM position WHERE title = '과장' AND organization_id = @tech_org_id), (SELECT id FROM department WHERE name = '개발팀' AND organization_id = @tech_org_id), 'DEV25001', 'ACTIVE'), +((SELECT id FROM user WHERE email = 'younghee.lee@techinnovation.co.kr'), @tech_org_id, (SELECT id FROM position WHERE title = '대리' AND organization_id = @tech_org_id), (SELECT id FROM department WHERE name = '디자인팀' AND organization_id = @tech_org_id), 'DES25001', 'ACTIVE'), +((SELECT id FROM user WHERE email = 'minsu.park@techinnovation.co.kr'), @tech_org_id, (SELECT id FROM position WHERE title = '차장' AND organization_id = @tech_org_id), (SELECT id FROM department WHERE name = '인사팀' AND organization_id = @tech_org_id), 'HR25001', 'ACTIVE'), -- 디지털솔루션 직원들 --- 정수연 - 개발팀 팀장 -((SELECT id FROM users WHERE email = 'sooyeon.jung@digitalsolution.com'), - (SELECT id FROM organizations WHERE domain_name = 'digitalsolution.com'), - (SELECT id FROM positions WHERE title = '팀장' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'digitalsolution.com')), - (SELECT id FROM departments WHERE name = '개발팀' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'digitalsolution.com')), - 'DEV25001', 'ACTIVE'), - --- 최현우 - 기획팀 책임 -((SELECT id FROM users WHERE email = 'hyunwoo.choi@digitalsolution.com'), - (SELECT id FROM organizations WHERE domain_name = 'digitalsolution.com'), - (SELECT id FROM positions WHERE title = '책임' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'digitalsolution.com')), - (SELECT id FROM departments WHERE name = '기획팀' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'digitalsolution.com')), - 'PLN25001', 'ACTIVE'), +((SELECT id FROM user WHERE email = 'sooyeon.jung@digitalsolution.com'), @digital_org_id, (SELECT id FROM position WHERE title = '팀장' AND organization_id = @digital_org_id), (SELECT id FROM department WHERE name = '개발팀' AND organization_id = @digital_org_id), 'DEV25001', 'ACTIVE'), +((SELECT id FROM user WHERE email = 'hyunwoo.choi@digitalsolution.com'), @digital_org_id, (SELECT id FROM position WHERE title = '책임' AND organization_id = @digital_org_id), (SELECT id FROM department WHERE name = '기획팀' AND organization_id = @digital_org_id), 'PLN25001', 'ACTIVE'), -- 크리에이티브웍스 직원 --- 홍지아 - 디자인팀 리드 -((SELECT id FROM users WHERE email = 'jia.hong@creativeworks.net'), - (SELECT id FROM organizations WHERE domain_name = 'creativeworks.net'), - (SELECT id FROM positions WHERE title = '리드' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'creativeworks.net')), - (SELECT id FROM departments WHERE name = '디자인팀' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'creativeworks.net')), - 'DES25001', 'ACTIVE'); +((SELECT id FROM user WHERE email = 'jia.hong@creativeworks.net'), @creative_org_id, (SELECT id FROM position WHERE title = '리드' AND organization_id = @creative_org_id), (SELECT id FROM department WHERE name = '디자인팀' AND organization_id = @creative_org_id), 'DES25001', 'ACTIVE'); -- 11. 외부 회사 사용자별 역할 할당 -- 테크이노베이션 --- 김철수에게 DEPT_MANAGER 역할 -INSERT INTO `user_roles` (`role_id`, `user_organization_id`) +INSERT INTO `user_role` (`role_id`, `user_organization_id`) SELECT - (SELECT id FROM roles WHERE name = 'DEPT_MANAGER' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'techinnovation.co.kr')), + (SELECT id FROM role WHERE name = 'DEPT_MANAGER' AND organization_id = @tech_org_id), uo.id -FROM user_organizations uo - JOIN users u ON u.id = uo.user_id +FROM user_organization uo + JOIN user u ON u.id = uo.user_id WHERE u.email = 'chulsoo.kim@techinnovation.co.kr'; --- 이영희에게 DESIGNER 역할 -INSERT INTO `user_roles` (`role_id`, `user_organization_id`) +INSERT INTO `user_role` (`role_id`, `user_organization_id`) SELECT - (SELECT id FROM roles WHERE name = 'DESIGNER' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'techinnovation.co.kr')), + (SELECT id FROM role WHERE name = 'DESIGNER' AND organization_id = @tech_org_id), uo.id -FROM user_organizations uo - JOIN users u ON u.id = uo.user_id +FROM user_organization uo + JOIN user u ON u.id = uo.user_id WHERE u.email = 'younghee.lee@techinnovation.co.kr'; --- 박민수에게 HR_SPECIALIST 역할 -INSERT INTO `user_roles` (`role_id`, `user_organization_id`) +INSERT INTO `user_role` (`role_id`, `user_organization_id`) SELECT - (SELECT id FROM roles WHERE name = 'HR_SPECIALIST' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'techinnovation.co.kr')), + (SELECT id FROM role WHERE name = 'HR_SPECIALIST' AND organization_id = @tech_org_id), uo.id -FROM user_organizations uo - JOIN users u ON u.id = uo.user_id +FROM user_organization uo + JOIN user u ON u.id = uo.user_id WHERE u.email = 'minsu.park@techinnovation.co.kr'; -- 디지털솔루션 --- 정수연에게 TECH_LEAD 역할 -INSERT INTO `user_roles` (`role_id`, `user_organization_id`) +INSERT INTO `user_role` (`role_id`, `user_organization_id`) SELECT - (SELECT id FROM roles WHERE name = 'TECH_LEAD' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'digitalsolution.com')), + (SELECT id FROM role WHERE name = 'TECH_LEAD' AND organization_id = @digital_org_id), uo.id -FROM user_organizations uo - JOIN users u ON u.id = uo.user_id +FROM user_organization uo + JOIN user u ON u.id = uo.user_id WHERE u.email = 'sooyeon.jung@digitalsolution.com'; --- 최현우에게 PRODUCT_OWNER 역할 -INSERT INTO `user_roles` (`role_id`, `user_organization_id`) +INSERT INTO `user_role` (`role_id`, `user_organization_id`) SELECT - (SELECT id FROM roles WHERE name = 'PRODUCT_OWNER' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'digitalsolution.com')), + (SELECT id FROM role WHERE name = 'PRODUCT_OWNER' AND organization_id = @digital_org_id), uo.id -FROM user_organizations uo - JOIN users u ON u.id = uo.user_id +FROM user_organization uo + JOIN user u ON u.id = uo.user_id WHERE u.email = 'hyunwoo.choi@digitalsolution.com'; -- 크리에이티브웍스 --- 홍지아에게 CREATIVE_DIRECTOR 역할 -INSERT INTO `user_roles` (`role_id`, `user_organization_id`) +INSERT INTO `user_role` (`role_id`, `user_organization_id`) SELECT - (SELECT id FROM roles WHERE name = 'CREATIVE_DIRECTOR' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'creativeworks.net')), + (SELECT id FROM role WHERE name = 'CREATIVE_DIRECTOR' AND organization_id = @creative_org_id), uo.id -FROM user_organizations uo - JOIN users u ON u.id = uo.user_id +FROM user_organization uo + JOIN user u ON u.id = uo.user_id WHERE u.email = 'jia.hong@creativeworks.net'; -- 12. 외부 회사 역할별 기본 권한 할당 (샘플) -- DEPT_MANAGER 권한 -INSERT INTO `role_permissions` (`role_id`, `permission_id`) +INSERT INTO `role_permission` (`role_id`, `permission_id`) SELECT - (SELECT id FROM roles WHERE name = 'DEPT_MANAGER' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'techinnovation.co.kr')), + (SELECT id FROM role WHERE name = 'DEPT_MANAGER' AND organization_id = @tech_org_id), id -FROM permissions +FROM permission WHERE resource IN ( 'users.read.department', 'users.update', 'users.invite', 'departments.read', 'departments.manage', @@ -216,11 +183,11 @@ WHERE resource IN ( ); -- TECH_LEAD 권한 -INSERT INTO `role_permissions` (`role_id`, `permission_id`) +INSERT INTO `role_permission` (`role_id`, `permission_id`) SELECT - (SELECT id FROM roles WHERE name = 'TECH_LEAD' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'digitalsolution.com')), + (SELECT id FROM role WHERE name = 'TECH_LEAD' AND organization_id = @digital_org_id), id -FROM permissions +FROM permission WHERE resource LIKE 'ai.%' OR resource LIKE 'workflows.%' OR resource IN ( @@ -230,11 +197,11 @@ WHERE resource LIKE 'ai.%' ); -- CREATIVE_DIRECTOR 권한 -INSERT INTO `role_permissions` (`role_id`, `permission_id`) +INSERT INTO `role_permission` (`role_id`, `permission_id`) SELECT - (SELECT id FROM roles WHERE name = 'CREATIVE_DIRECTOR' AND organization_id = (SELECT id FROM organizations WHERE domain_name = 'creativeworks.net')), + (SELECT id FROM role WHERE name = 'CREATIVE_DIRECTOR' AND organization_id = @creative_org_id), id -FROM permissions +FROM permission WHERE resource LIKE 'content.%' OR resource LIKE 'campaigns.%' OR resource IN ( diff --git a/apps/user-service/src/main/resources/sql/schema.sql b/apps/user-service/src/main/resources/sql/schema.sql deleted file mode 100644 index e2a9a917..00000000 --- a/apps/user-service/src/main/resources/sql/schema.sql +++ /dev/null @@ -1,256 +0,0 @@ --- MariaDB 최적화된 스키마 (소문자, VARCHAR 크기 지정) -CREATE TABLE IF NOT EXISTS `permissions` ( - `id` int unsigned NOT NULL AUTO_INCREMENT, - `resource` varchar(100) NULL, - `description` varchar(255) NULL, - `created_at` timestamp DEFAULT CURRENT_TIMESTAMP, - `updated_at` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - `is_active` boolean DEFAULT TRUE, - `updated_by` bigint unsigned NULL, - `created_by` bigint unsigned NULL, - PRIMARY KEY (`id`) -); - -CREATE TABLE IF NOT EXISTS `organizations` ( - `id` bigint unsigned NOT NULL AUTO_INCREMENT, - `name` varchar(150) NULL, - `domain_name` varchar(100) NULL, - `created_at` timestamp DEFAULT CURRENT_TIMESTAMP, - `updated_at` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - PRIMARY KEY (`id`) -); - -CREATE TABLE IF NOT EXISTS `roles` ( - `id` bigint unsigned NOT NULL AUTO_INCREMENT, - `organization_id` bigint unsigned NULL, - `name` varchar(100) NULL, - `description` varchar(500) NULL, - PRIMARY KEY (`id`), - CONSTRAINT `fk_organizations_to_roles` FOREIGN KEY (`organization_id`) - REFERENCES `organizations` (`id`) ON DELETE SET NULL -); - -CREATE TABLE IF NOT EXISTS `users` ( - `id` bigint unsigned NOT NULL AUTO_INCREMENT, - `name` varchar(50) NULL, - `email` varchar(100) NULL, - `password` varchar(255) NULL, - `status` varchar(20) NULL, - `created_at` timestamp DEFAULT CURRENT_TIMESTAMP, - `updated_at` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - PRIMARY KEY (`id`) -); - -CREATE TABLE IF NOT EXISTS `departments` ( - `id` bigint unsigned NOT NULL AUTO_INCREMENT, - `organization_id` bigint unsigned NOT NULL, - `name` varchar(100) NULL, - PRIMARY KEY (`id`), - CONSTRAINT `fk_organizations_to_departments` FOREIGN KEY (`organization_id`) REFERENCES `organizations` (`id`) -); - -CREATE TABLE IF NOT EXISTS `positions` ( - `id` bigint unsigned NOT NULL AUTO_INCREMENT, - `organization_id` bigint unsigned NOT NULL, - `title` varchar(100) NULL, - PRIMARY KEY (`id`), - CONSTRAINT `fk_organizations_to_positions` FOREIGN KEY (`organization_id`) REFERENCES `organizations` (`id`) -); - -CREATE TABLE IF NOT EXISTS `user_organizations` ( - `id` bigint unsigned NOT NULL AUTO_INCREMENT, - `user_id` bigint unsigned NOT NULL, - `organization_id` bigint unsigned NOT NULL, - `position_id` bigint unsigned NOT NULL, - `department_id` bigint unsigned NOT NULL, - `employee_number` varchar(50) NULL, - `status` varchar(20) NULL, - `created_at` timestamp DEFAULT CURRENT_TIMESTAMP, - `updated_at` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - PRIMARY KEY (`id`), - CONSTRAINT `fk_users_to_user_organizations` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`), - CONSTRAINT `fk_organizations_to_user_organizations` FOREIGN KEY (`organization_id`) REFERENCES `organizations` (`id`), - CONSTRAINT `fk_positions_to_user_organizations` FOREIGN KEY (`position_id`) REFERENCES `positions` (`id`), - CONSTRAINT `fk_departments_to_user_organizations` FOREIGN KEY (`department_id`) REFERENCES `departments` (`id`) -); - -CREATE TABLE IF NOT EXISTS `role_permissions` ( - `id` bigint unsigned NOT NULL AUTO_INCREMENT, - `role_id` bigint unsigned NOT NULL, - `permission_id` int unsigned NOT NULL, - PRIMARY KEY (`id`), - CONSTRAINT `fk_roles_to_role_permissions` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`), - CONSTRAINT `fk_permissions_to_role_permissions` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`id`), - UNIQUE KEY `uk_role_permission` (`role_id`, `permission_id`) -); - -CREATE TABLE IF NOT EXISTS `user_roles` ( - `id` bigint unsigned NOT NULL AUTO_INCREMENT, - `role_id` bigint unsigned NOT NULL, - `user_organization_id` bigint unsigned NOT NULL, - PRIMARY KEY (`id`), - CONSTRAINT `fk_roles_to_user_roles` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`), - CONSTRAINT `fk_user_organizations_to_user_roles` FOREIGN KEY (`user_organization_id`) REFERENCES `user_organizations` (`id`), - UNIQUE KEY `uk_user_role` (`role_id`, `user_organization_id`) -); - --- 성능 최적화를 위한 인덱스 -CREATE INDEX IF NOT EXISTS - `idx_users_email` ON `users` (`email`); -CREATE INDEX IF NOT EXISTS - `idx_users_status` ON `users` (`status`); -CREATE INDEX IF NOT EXISTS - `idx_user_organizations_user` ON `user_organizations` (`user_id`); -CREATE INDEX IF NOT EXISTS - `idx_user_organizations_org` ON `user_organizations` (`organization_id`); -CREATE INDEX IF NOT EXISTS - `idx_user_organizations_status` ON `user_organizations` (`status`); -CREATE INDEX IF NOT EXISTS - `idx_roles_org` ON `roles` (`organization_id`); -CREATE INDEX IF NOT EXISTS - `idx_permissions_resource` ON `permissions` (`resource`); -CREATE INDEX IF NOT EXISTS - `idx_permissions_active` ON `permissions` (`is_active`); - - - -CREATE TABLE IF NOT EXISTS `workflows` ( - `id` bigint unsigned NOT NULL AUTO_INCREMENT, - `name` varchar(100) NOT NULL UNIQUE, - `description` text NULL, - `is_enabled` boolean DEFAULT TRUE, - `created_at` timestamp DEFAULT CURRENT_TIMESTAMP, - `created_by` bigint unsigned NULL, - `updated_at` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - `updated_by` bigint unsigned NULL, - PRIMARY KEY (`id`) - ); - -CREATE TABLE IF NOT EXISTS `schedules` ( - `id` bigint unsigned NOT NULL AUTO_INCREMENT, - `workflow_id` bigint unsigned NOT NULL, - `cron_expression` varchar(50) NULL, - `parameters` json NULL, - `is_active` boolean DEFAULT TRUE, - `last_run_status` varchar(20) NULL, - `last_run_at` timestamp NULL, - `created_at` timestamp DEFAULT CURRENT_TIMESTAMP, - `created_by` bigint unsigned NULL, - `updated_at` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - `updated_by` bigint unsigned NULL, - PRIMARY KEY (`id`), - CONSTRAINT `fk_schedules_to_workflows` FOREIGN KEY (`workflow_id`) REFERENCES `workflows` (`id`) - ); - -CREATE TABLE IF NOT EXISTS `jobs` ( - `id` bigint unsigned NOT NULL AUTO_INCREMENT, - `name` varchar(100) NOT NULL UNIQUE, - `description` text NULL, - `is_enabled` boolean DEFAULT TRUE, - `created_at` timestamp DEFAULT CURRENT_TIMESTAMP, - `created_by` bigint unsigned NULL, - `updated_at` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - `updated_by` bigint unsigned NULL, - PRIMARY KEY (`id`) - ); - -CREATE TABLE IF NOT EXISTS `tasks` ( - `id` bigint unsigned NOT NULL AUTO_INCREMENT, - `name` varchar(100) NOT NULL UNIQUE, - `type` varchar(50) NULL, - `parameters` json NULL, - `created_at` timestamp DEFAULT CURRENT_TIMESTAMP, - `updated_at` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - PRIMARY KEY (`id`) - ); - -CREATE TABLE IF NOT EXISTS `workflow_jobs` ( - `id` bigint unsigned NOT NULL AUTO_INCREMENT, - `workflow_id` bigint unsigned NOT NULL, - `job_id` bigint unsigned NOT NULL, - PRIMARY KEY (`id`), - CONSTRAINT `fk_workflow_jobs_to_workflows` FOREIGN KEY (`workflow_id`) REFERENCES `workflows` (`id`), - CONSTRAINT `fk_workflow_jobs_to_jobs` FOREIGN KEY (`job_id`) REFERENCES `jobs` (`id`), - UNIQUE KEY `uk_workflow_job` (`workflow_id`, `job_id`) - ); - -CREATE TABLE IF NOT EXISTS `job_tasks` ( - `id` bigint unsigned NOT NULL AUTO_INCREMENT, - `job_id` bigint unsigned NOT NULL, - `task_id` bigint unsigned NOT NULL, - `execution_order` int NULL, - PRIMARY KEY (`id`), - CONSTRAINT `fk_job_tasks_to_jobs` FOREIGN KEY (`job_id`) REFERENCES `jobs` (`id`), - CONSTRAINT `fk_job_tasks_to_tasks` FOREIGN KEY (`task_id`) REFERENCES `tasks` (`id`), - UNIQUE KEY `uk_job_task` (`job_id`, `task_id`) - ); - -CREATE TABLE IF NOT EXISTS `execution_logs` ( - `id` bigint unsigned NOT NULL AUTO_INCREMENT, - `execution_type` varchar(20) NULL COMMENT 'task, schedule, job, workflow', - `source_id` bigint unsigned NULL COMMENT '모든 데이터에 대한 ID ex: job_id, schedule_id, task_id, ...', - `log_level` varchar(20) NULL, - `executed_at` timestamp DEFAULT CURRENT_TIMESTAMP, - `log_message` text NULL, - `trace_id` char(36) NULL, - `config_snapshot` json NULL, - PRIMARY KEY (`id`), - INDEX `idx_source_id_type` (`source_id`, `execution_type`) - ); - -CREATE TABLE IF NOT EXISTS `task_io_data` ( - `id` bigint unsigned NOT NULL AUTO_INCREMENT, - `trace_id` char(36) NULL, - `io_type` varchar(10) NULL COMMENT 'INPUT, OUTPUT', - `name` varchar(100) NULL, - `data_type` varchar(50) NULL, - `data_value` json NULL, - `created_at` timestamp DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY (`id`), - INDEX `idx_trace_id` (`trace_id`) - ); - -CREATE TABLE IF NOT EXISTS `configs` ( - `id` bigint unsigned NOT NULL AUTO_INCREMENT, - `target_type` varchar(50) NULL COMMENT 'user, job, workflow', - `target_id` bigint unsigned NULL, - `version` int NULL, - `json` json NULL, - `is_active` boolean DEFAULT TRUE, - `created_at` timestamp DEFAULT CURRENT_TIMESTAMP, - `created_by` bigint unsigned NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `uk_config_target` (`target_type`, `target_id`) - ); - -CREATE TABLE IF NOT EXISTS `categories` ( - `id` bigint unsigned NOT NULL AUTO_INCREMENT, - `name` varchar(100) NULL, - `description` text NULL, - `created_at` timestamp DEFAULT CURRENT_TIMESTAMP, - `updated_at` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - PRIMARY KEY (`id`) - ); - -CREATE TABLE IF NOT EXISTS `user_configs` ( - `id` bigint unsigned NOT NULL AUTO_INCREMENT, - `user_id` bigint unsigned NOT NULL, - `type` varchar(50) NULL, - `name` varchar(100) NULL, - `json` json NULL, - `is_active` boolean DEFAULT TRUE, - `created_at` timestamp DEFAULT CURRENT_TIMESTAMP, - `updated_at` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - PRIMARY KEY (`id`) - ); - --- 인덱스 추가 (성능 최적화) -CREATE INDEX IF NOT EXISTS `idx_schedules_workflow` ON `schedules` (`workflow_id`); -CREATE INDEX IF NOT EXISTS `idx_jobs_enabled` ON `jobs` (`is_enabled`); -CREATE INDEX IF NOT EXISTS `idx_tasks_type` ON `tasks` (`type`); -CREATE INDEX IF NOT EXISTS `idx_workflows_enabled` ON `workflows` (`is_enabled`); -CREATE UNIQUE INDEX IF NOT EXISTS `uk_schedules_workflow` ON `schedules` (`workflow_id`); -CREATE UNIQUE INDEX IF NOT EXISTS `uk_job_name` ON `jobs` (`name`); -CREATE UNIQUE INDEX IF NOT EXISTS `uk_task_name` ON `tasks` (`name`); -CREATE UNIQUE INDEX IF NOT EXISTS `uk_workflows_name` ON `workflows` (`name`); -CREATE INDEX IF NOT EXISTS `idx_user_configs_user` ON `user_configs` (`user_id`); \ No newline at end of file diff --git a/apps/user-service/src/test/java/com/gltkorea/icebang/DatabaseConnectionTest.java b/apps/user-service/src/test/java/com/gltkorea/icebang/DatabaseConnectionTest.java index e744873b..c15170cc 100644 --- a/apps/user-service/src/test/java/com/gltkorea/icebang/DatabaseConnectionTest.java +++ b/apps/user-service/src/test/java/com/gltkorea/icebang/DatabaseConnectionTest.java @@ -28,7 +28,7 @@ // @ActiveProfiles("test") // application-test-unit.yml 설정을 활성화 // @Transactional // 테스트 후 데이터 롤백 // @Sql( -// scripts = {"classpath:sql/create-schema.sql", "classpath:sql/insert-user-data.sql"}, +// scripts = {"classpath:sql/create-01-schema.sql", "classpath:sql/insert-user-data.sql"}, // executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) // class DatabaseConnectionTest { //