feat: WTM 멀티프로젝트 플랫폼 구축 (BE + FE 전체 구현)
Phase 0: wbx-spring-core 라이브러리 전환 - java-library 플러그인, WbxAutoConfiguration, Admin 조건부 활성화 - 루트 settings.gradle + build.gradle (멀티모듈) Phase 1: wtm-api 모듈 생성 - 23개 JPA Entity, 14개 Controller, 79개 API 엔드포인트 - Flyway V100~V107 MySQL 마이그레이션 - TimesheetRuleEngine, TimesheetApprovalHandler, P6WbsParser Phase 2: wtm-frontend (Vue 3 + PrimeVue 4) - 10개 도메인 모듈, 17개 View, 5개 서브컴포넌트 - 반응형 레이아웃 (AppLayout, AppSidebar, AppTopbar) - BaseCrudTable, BaseFormDialog, BasePageHeader 표준 컴포넌트 - JWT 인터셉터, 역할 기반 메뉴 필터링 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
이 Commit은 다음에 포함되어 있습니다:
65
.gitignore
벤더링됨
65
.gitignore
벤더링됨
@@ -1,50 +1,31 @@
|
|||||||
HELP.md
|
# Build
|
||||||
.gradle
|
|
||||||
build/
|
build/
|
||||||
!gradle/wrapper/gradle-wrapper.jar
|
dist/
|
||||||
!**/src/main/**/build/
|
.gradle/
|
||||||
!**/src/test/**/build/
|
|
||||||
|
|
||||||
### STS ###
|
|
||||||
.apt_generated
|
|
||||||
.classpath
|
|
||||||
.factorypath
|
|
||||||
.project
|
|
||||||
.settings
|
|
||||||
.springBeans
|
|
||||||
.sts4-cache
|
|
||||||
bin/
|
|
||||||
!**/src/main/**/bin/
|
|
||||||
!**/src/test/**/bin/
|
|
||||||
|
|
||||||
### IntelliJ IDEA ###
|
|
||||||
.idea
|
|
||||||
*.iws
|
|
||||||
*.iml
|
|
||||||
*.ipr
|
|
||||||
out/
|
out/
|
||||||
!**/src/main/**/out/
|
|
||||||
!**/src/test/**/out/
|
|
||||||
|
|
||||||
### NetBeans ###
|
# IDE
|
||||||
/nbproject/private/
|
.idea/
|
||||||
/nbbuild/
|
*.iml
|
||||||
/dist/
|
|
||||||
/nbdist/
|
|
||||||
/.nb-gradle/
|
|
||||||
|
|
||||||
### VS Code ###
|
|
||||||
.vscode/
|
.vscode/
|
||||||
|
*.swp
|
||||||
|
|
||||||
### Runtime ###
|
# Node
|
||||||
*.log
|
node_modules/
|
||||||
server.log
|
wtm-frontend/node_modules/
|
||||||
uploads/
|
|
||||||
temp/
|
|
||||||
|
|
||||||
### Environment ###
|
# OS
|
||||||
.env
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Env (local overrides)
|
||||||
.env.local
|
.env.local
|
||||||
*.pem
|
.env.*.local
|
||||||
*.key
|
|
||||||
|
# Claude/OMC
|
||||||
.claude/
|
.claude/
|
||||||
|
.omc/
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
*.log
|
||||||
|
logs/
|
||||||
|
|||||||
99
build.gradle
99
build.gradle
@@ -1,70 +1,39 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id 'java'
|
id 'java'
|
||||||
id 'org.springframework.boot' version '3.5.0'
|
id 'io.spring.dependency-management' version '1.1.7'
|
||||||
id 'io.spring.dependency-management' version '1.1.7'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
group = 'kr.co.accura.wbx.spring'
|
subprojects {
|
||||||
version = '0.0.1-SNAPSHOT'
|
group = 'kr.co.accura'
|
||||||
|
version = '1.0.0-SNAPSHOT'
|
||||||
|
|
||||||
java {
|
apply plugin: 'java'
|
||||||
toolchain {
|
apply plugin: 'io.spring.dependency-management'
|
||||||
languageVersion = JavaLanguageVersion.of(21)
|
|
||||||
}
|
java {
|
||||||
}
|
toolchain {
|
||||||
|
languageVersion = JavaLanguageVersion.of(21)
|
||||||
configurations {
|
}
|
||||||
compileOnly {
|
}
|
||||||
extendsFrom annotationProcessor
|
|
||||||
}
|
repositories {
|
||||||
}
|
mavenCentral()
|
||||||
|
}
|
||||||
repositories {
|
|
||||||
mavenCentral()
|
dependencyManagement {
|
||||||
}
|
imports {
|
||||||
|
mavenBom "org.springframework.boot:spring-boot-dependencies:3.5.0"
|
||||||
dependencies {
|
}
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-actuator'
|
}
|
||||||
runtimeOnly 'io.micrometer:micrometer-registry-prometheus'
|
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-cache'
|
dependencies {
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
compileOnly 'org.projectlombok:lombok'
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
|
annotationProcessor 'org.projectlombok:lombok'
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
|
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'
|
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-security'
|
}
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-validation'
|
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-web'
|
tasks.named('test') {
|
||||||
implementation 'org.flywaydb:flyway-core'
|
useJUnitPlatform()
|
||||||
implementation 'org.flywaydb:flyway-mysql'
|
}
|
||||||
|
|
||||||
// JWT
|
|
||||||
implementation 'io.jsonwebtoken:jjwt-api:0.12.6'
|
|
||||||
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.6'
|
|
||||||
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.6'
|
|
||||||
|
|
||||||
// DB Drivers (4개 DBMS)
|
|
||||||
runtimeOnly 'com.mysql:mysql-connector-j'
|
|
||||||
runtimeOnly 'org.postgresql:postgresql'
|
|
||||||
runtimeOnly 'com.oracle.database.jdbc:ojdbc11:23.6.0.24.10'
|
|
||||||
runtimeOnly 'com.microsoft.sqlserver:mssql-jdbc:12.8.1.jre11'
|
|
||||||
runtimeOnly 'org.flywaydb:flyway-sqlserver'
|
|
||||||
|
|
||||||
// OpenAPI
|
|
||||||
// SpringDoc — Boot 3.5 호환
|
|
||||||
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.6'
|
|
||||||
|
|
||||||
// Admin Console (Thymeleaf)
|
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
|
|
||||||
|
|
||||||
compileOnly 'org.projectlombok:lombok'
|
|
||||||
developmentOnly 'org.springframework.boot:spring-boot-devtools'
|
|
||||||
annotationProcessor 'org.projectlombok:lombok'
|
|
||||||
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
|
||||||
testImplementation 'org.springframework.security:spring-security-test'
|
|
||||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
|
||||||
testRuntimeOnly 'com.h2database:h2'
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.named('test') {
|
|
||||||
useJUnitPlatform()
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1,9 @@
|
|||||||
rootProject.name = 'wbx-spring-core'
|
rootProject.name = 'wbx-spring'
|
||||||
|
|
||||||
|
// 공유 프레임워크
|
||||||
|
include 'wbx-spring-core'
|
||||||
|
|
||||||
|
// === 고객 프로젝트 (추가 시 여기에 include) ===
|
||||||
|
include 'wtm-api' // 한화오션 WTM (시수관리)
|
||||||
|
// include 'xxx-api' // 향후 프로젝트 B
|
||||||
|
// include 'yyy-api' // 향후 프로젝트 C
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
package kr.co.accura.wbx.spring;
|
|
||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|
||||||
import org.springframework.cache.annotation.EnableCaching;
|
|
||||||
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
|
|
||||||
import org.springframework.scheduling.annotation.EnableAsync;
|
|
||||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
|
||||||
|
|
||||||
@SpringBootApplication
|
|
||||||
@EnableJpaAuditing
|
|
||||||
@EnableAsync
|
|
||||||
@EnableScheduling
|
|
||||||
@EnableCaching
|
|
||||||
public class WbxSpringCoreApplication {
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
SpringApplication.run(WbxSpringCoreApplication.class, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
50
wbx-spring-core/.gitignore
벤더링됨
일반 파일
50
wbx-spring-core/.gitignore
벤더링됨
일반 파일
@@ -0,0 +1,50 @@
|
|||||||
|
HELP.md
|
||||||
|
.gradle
|
||||||
|
build/
|
||||||
|
!gradle/wrapper/gradle-wrapper.jar
|
||||||
|
!**/src/main/**/build/
|
||||||
|
!**/src/test/**/build/
|
||||||
|
|
||||||
|
### STS ###
|
||||||
|
.apt_generated
|
||||||
|
.classpath
|
||||||
|
.factorypath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.springBeans
|
||||||
|
.sts4-cache
|
||||||
|
bin/
|
||||||
|
!**/src/main/**/bin/
|
||||||
|
!**/src/test/**/bin/
|
||||||
|
|
||||||
|
### IntelliJ IDEA ###
|
||||||
|
.idea
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
out/
|
||||||
|
!**/src/main/**/out/
|
||||||
|
!**/src/test/**/out/
|
||||||
|
|
||||||
|
### NetBeans ###
|
||||||
|
/nbproject/private/
|
||||||
|
/nbbuild/
|
||||||
|
/dist/
|
||||||
|
/nbdist/
|
||||||
|
/.nb-gradle/
|
||||||
|
|
||||||
|
### VS Code ###
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
### Runtime ###
|
||||||
|
*.log
|
||||||
|
server.log
|
||||||
|
uploads/
|
||||||
|
temp/
|
||||||
|
|
||||||
|
### Environment ###
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
*.pem
|
||||||
|
*.key
|
||||||
|
.claude/
|
||||||
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
@@ -0,0 +1,2 @@
|
|||||||
|
#Wed Mar 25 16:49:13 KST 2026
|
||||||
|
gradle.version=8.14.4
|
||||||
바이너리 파일은 표시되지 않습니다.
@@ -0,0 +1,12 @@
|
|||||||
|
{"t":0,"agent":"a18f090","agent_type":"Explore","event":"agent_start","parent_mode":"none"}
|
||||||
|
{"t":0,"agent":"a18f090","agent_type":"Explore","event":"agent_stop","success":true,"duration_ms":44564}
|
||||||
|
{"t":0,"agent":"ad9b656","agent_type":"architect","event":"agent_start","parent_mode":"none"}
|
||||||
|
{"t":0,"agent":"ad9b656","agent_type":"architect","event":"agent_stop","success":true,"duration_ms":169049}
|
||||||
|
{"t":0,"agent":"ad7c101","agent_type":"architect","event":"agent_start","parent_mode":"none"}
|
||||||
|
{"t":0,"agent":"ad7c101","agent_type":"architect","event":"agent_stop","success":true,"duration_ms":202690}
|
||||||
|
{"t":0,"agent":"aeff378","agent_type":"critic","event":"agent_start","parent_mode":"none"}
|
||||||
|
{"t":0,"agent":"aeff378","agent_type":"critic","event":"agent_stop","success":true,"duration_ms":175651}
|
||||||
|
{"t":0,"agent":"a35d81f","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"}
|
||||||
|
{"t":0,"agent":"a66b53d","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"}
|
||||||
|
{"t":0,"agent":"a35d81f","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":105638}
|
||||||
|
{"t":0,"agent":"a66b53d","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":411042}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
{
|
||||||
|
"agents": [
|
||||||
|
{
|
||||||
|
"agent_id": "a18f0906df8444921",
|
||||||
|
"agent_type": "Explore",
|
||||||
|
"started_at": "2026-03-25T09:57:59.104Z",
|
||||||
|
"parent_mode": "none",
|
||||||
|
"status": "completed",
|
||||||
|
"completed_at": "2026-03-25T09:58:43.668Z",
|
||||||
|
"duration_ms": 44564
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"agent_id": "ad9b65686f679467a",
|
||||||
|
"agent_type": "oh-my-claudecode:architect",
|
||||||
|
"started_at": "2026-03-25T10:12:41.765Z",
|
||||||
|
"parent_mode": "none",
|
||||||
|
"status": "completed",
|
||||||
|
"completed_at": "2026-03-25T10:15:30.814Z",
|
||||||
|
"duration_ms": 169049
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"agent_id": "ad7c101944473c52f",
|
||||||
|
"agent_type": "oh-my-claudecode:architect",
|
||||||
|
"started_at": "2026-03-25T10:20:25.037Z",
|
||||||
|
"parent_mode": "none",
|
||||||
|
"status": "completed",
|
||||||
|
"completed_at": "2026-03-25T10:23:47.727Z",
|
||||||
|
"duration_ms": 202690
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"agent_id": "aeff378642946b837",
|
||||||
|
"agent_type": "oh-my-claudecode:critic",
|
||||||
|
"started_at": "2026-03-25T10:32:26.548Z",
|
||||||
|
"parent_mode": "none",
|
||||||
|
"status": "completed",
|
||||||
|
"completed_at": "2026-03-25T10:35:22.199Z",
|
||||||
|
"duration_ms": 175651
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"agent_id": "a35d81fe5c1491345",
|
||||||
|
"agent_type": "general-purpose",
|
||||||
|
"started_at": "2026-03-25T10:54:19.348Z",
|
||||||
|
"parent_mode": "none",
|
||||||
|
"status": "completed",
|
||||||
|
"completed_at": "2026-03-25T10:56:04.986Z",
|
||||||
|
"duration_ms": 105638
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"agent_id": "a66b53d0c9bd248ef",
|
||||||
|
"agent_type": "general-purpose",
|
||||||
|
"started_at": "2026-03-25T10:54:45.602Z",
|
||||||
|
"parent_mode": "none",
|
||||||
|
"status": "completed",
|
||||||
|
"completed_at": "2026-03-25T11:01:36.644Z",
|
||||||
|
"duration_ms": 411042
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"total_spawned": 6,
|
||||||
|
"total_completed": 6,
|
||||||
|
"total_failed": 0,
|
||||||
|
"last_updated": "2026-03-25T11:01:36.764Z"
|
||||||
|
}
|
||||||
42
wbx-spring-core/build.gradle
일반 파일
42
wbx-spring-core/build.gradle
일반 파일
@@ -0,0 +1,42 @@
|
|||||||
|
plugins {
|
||||||
|
id 'java-library'
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
// Spring Boot Starters (api로 노출 — 소비 모듈이 사용)
|
||||||
|
api 'org.springframework.boot:spring-boot-starter-web'
|
||||||
|
api 'org.springframework.boot:spring-boot-starter-data-jpa'
|
||||||
|
api 'org.springframework.boot:spring-boot-starter-security'
|
||||||
|
api 'org.springframework.boot:spring-boot-starter-validation'
|
||||||
|
api 'org.springframework.boot:spring-boot-starter-data-redis'
|
||||||
|
api 'org.springframework.boot:spring-boot-starter-cache'
|
||||||
|
api 'org.springframework.boot:spring-boot-starter-actuator'
|
||||||
|
api 'org.springframework.boot:spring-boot-starter-oauth2-client'
|
||||||
|
api 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'
|
||||||
|
|
||||||
|
// JWT
|
||||||
|
api 'io.jsonwebtoken:jjwt-api:0.12.6'
|
||||||
|
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.6'
|
||||||
|
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.6'
|
||||||
|
|
||||||
|
// OpenAPI
|
||||||
|
api 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.6'
|
||||||
|
|
||||||
|
// Admin Console (조건부)
|
||||||
|
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
|
||||||
|
|
||||||
|
// Flyway (소비 모듈이 DBMS별 추가)
|
||||||
|
api 'org.flywaydb:flyway-core'
|
||||||
|
|
||||||
|
// DB 드라이버 — compileOnly (소비 모듈이 runtimeOnly로 선택)
|
||||||
|
compileOnly 'com.mysql:mysql-connector-j'
|
||||||
|
compileOnly 'org.postgresql:postgresql'
|
||||||
|
compileOnly 'com.oracle.database.jdbc:ojdbc11:23.6.0.24.10'
|
||||||
|
compileOnly 'com.microsoft.sqlserver:mssql-jdbc:12.8.1.jre11'
|
||||||
|
|
||||||
|
// Micrometer
|
||||||
|
runtimeOnly 'io.micrometer:micrometer-registry-prometheus'
|
||||||
|
|
||||||
|
// Test
|
||||||
|
testRuntimeOnly 'com.h2database:h2'
|
||||||
|
}
|
||||||
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
바이너리 파일은 표시되지 않습니다.
이 Diff에서 너무 많은 파일이 변경되어 일부 파일이 표시되지 않습니다 더 보기
새 Issue에서 참조
사용자 차단