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은 다음에 포함되어 있습니다:
2026-03-25 21:01:43 +09:00
부모 783865266b
커밋 df723f1d59
533개의 변경된 파일15528개의 추가작업 그리고 154개의 파일을 삭제

파일 보기

@@ -0,0 +1,8 @@
-- WBX Spring Framework — 초기 역할 데이터
INSERT IGNORE INTO wbx_roles (code, name, description, is_system) VALUES
('SA', 'System Administrator', '전체 시스템 관리', true),
('PM', 'Project Manager', '프로젝트 관리, 최종 결재', true),
('PCM', 'Project Control Mgr', 'WBS/TEAL 관리', true),
('PTK', 'Project Timekeeper', '시수 관리', true),
('DL', 'Discipline Lead', '1차 결재, Discipline 관리', true),
('USER', 'General User', '일반 사용자', true);

파일 보기

@@ -0,0 +1,10 @@
-- WBX Spring Framework — 초기 시스템 설정
INSERT IGNORE INTO wbx_system_config (config_key, config_value, value_type, description) VALUES
('auth.max_failed_attempts', '5', 'INT', '최대 로그인 실패 횟수'),
('auth.lockout_minutes', '15', 'INT', '계정 잠금 시간(분)'),
('auth.password_expiry_days', '90', 'INT', '비밀번호 만료 기간(일)'),
('auth.session_timeout_minutes', '480', 'INT', '세션 타임아웃(분)'),
('notification.sse_heartbeat_seconds', '30', 'INT', 'SSE 하트비트 주기(초)'),
('file.max_upload_size_mb', '50', 'INT', '최대 업로드 크기(MB)'),
('app.timezone', 'Asia/Seoul', 'STRING', '시스템 타임존'),
('app.date_format', 'yyyy-MM-dd', 'STRING', '날짜 표시 형식');

파일 보기

@@ -0,0 +1,134 @@
-- WBX Spring Framework — MSSQL 스키마
CREATE TABLE wbx_users (
id BIGINT IDENTITY(1,1) PRIMARY KEY,
email NVARCHAR(255) NOT NULL UNIQUE,
username NVARCHAR(100) NOT NULL UNIQUE,
hashed_password NVARCHAR(500),
full_name NVARCHAR(255),
phone NVARCHAR(50),
department_id BIGINT,
position_title NVARCHAR(100),
employee_number NVARCHAR(50) UNIQUE,
is_active BIT DEFAULT 1,
is_admin BIT DEFAULT 0,
mfa_enabled BIT DEFAULT 0,
azure_oid NVARCHAR(255),
sso_provider NVARCHAR(50),
failed_login_attempts INT DEFAULT 0,
last_failed_login DATETIME2,
locked_until DATETIME2,
password_changed_at DATETIME2,
must_change_password BIT DEFAULT 0,
last_login_at DATETIME2,
created_at DATETIME2 DEFAULT GETDATE(),
updated_at DATETIME2 DEFAULT GETDATE(),
created_by BIGINT,
updated_by BIGINT
);
CREATE TABLE wbx_roles (
id BIGINT IDENTITY(1,1) PRIMARY KEY,
code NVARCHAR(50) NOT NULL UNIQUE,
name NVARCHAR(100) NOT NULL,
description NVARCHAR(500),
is_system BIT DEFAULT 0,
created_at DATETIME2 DEFAULT GETDATE(),
updated_at DATETIME2 DEFAULT GETDATE()
);
CREATE TABLE wbx_user_roles (
id BIGINT IDENTITY(1,1) PRIMARY KEY,
user_id BIGINT NOT NULL FOREIGN KEY REFERENCES wbx_users(id),
role_id BIGINT NOT NULL FOREIGN KEY REFERENCES wbx_roles(id),
CONSTRAINT uk_wbx_user_role UNIQUE (user_id, role_id)
);
CREATE TABLE wbx_role_permissions (
id BIGINT IDENTITY(1,1) PRIMARY KEY,
role_id BIGINT NOT NULL FOREIGN KEY REFERENCES wbx_roles(id),
module NVARCHAR(100) NOT NULL,
action NVARCHAR(50) NOT NULL,
dept_scope NVARCHAR(20) DEFAULT 'OWN',
CONSTRAINT uk_wbx_role_perm UNIQUE (role_id, module, action)
);
CREATE TABLE wbx_refresh_tokens (
id BIGINT IDENTITY(1,1) PRIMARY KEY,
user_id BIGINT NOT NULL FOREIGN KEY REFERENCES wbx_users(id),
token_hash NVARCHAR(500) NOT NULL,
device_info NVARCHAR(500),
ip_address NVARCHAR(50),
expires_at DATETIME2 NOT NULL,
created_at DATETIME2 DEFAULT GETDATE()
);
CREATE TABLE wbx_totp_secrets (
id BIGINT IDENTITY(1,1) PRIMARY KEY,
user_id BIGINT NOT NULL UNIQUE FOREIGN KEY REFERENCES wbx_users(id),
encrypted_secret NVARCHAR(500) NOT NULL,
verified BIT DEFAULT 0,
backup_codes NVARCHAR(2000),
created_at DATETIME2 DEFAULT GETDATE(),
updated_at DATETIME2 DEFAULT GETDATE(),
created_by BIGINT,
updated_by BIGINT
);
CREATE TABLE wbx_login_history (
id BIGINT IDENTITY(1,1) PRIMARY KEY,
user_id BIGINT,
email NVARCHAR(255),
action NVARCHAR(50),
auth_method NVARCHAR(50),
ip_address NVARCHAR(50),
user_agent NVARCHAR(500),
failure_reason NVARCHAR(500),
created_at DATETIME2 DEFAULT GETDATE()
);
CREATE TABLE wbx_notifications (
id BIGINT IDENTITY(1,1) PRIMARY KEY,
user_id BIGINT NOT NULL FOREIGN KEY REFERENCES wbx_users(id),
title NVARCHAR(500),
message NVARCHAR(MAX),
type NVARCHAR(50),
is_read BIT DEFAULT 0,
link NVARCHAR(1000),
created_at DATETIME2 DEFAULT GETDATE()
);
CREATE TABLE wbx_audit_logs (
id BIGINT IDENTITY(1,1) PRIMARY KEY,
user_id BIGINT,
username NVARCHAR(255),
action NVARCHAR(50) NOT NULL,
resource NVARCHAR(100) NOT NULL,
resource_id BIGINT,
detail NVARCHAR(4000),
ip_address NVARCHAR(50),
created_at DATETIME2 DEFAULT GETDATE()
);
CREATE TABLE wbx_file_uploads (
id BIGINT IDENTITY(1,1) PRIMARY KEY,
user_id BIGINT,
original_name NVARCHAR(500),
stored_name NVARCHAR(500),
file_key NVARCHAR(500),
content_type NVARCHAR(200),
file_size BIGINT,
category NVARCHAR(100),
created_at DATETIME2 DEFAULT GETDATE()
);
CREATE TABLE wbx_system_config (
id BIGINT IDENTITY(1,1) PRIMARY KEY,
config_key NVARCHAR(100) NOT NULL UNIQUE,
config_value NVARCHAR(4000),
value_type NVARCHAR(20) DEFAULT 'STRING',
description NVARCHAR(500),
is_editable BIT DEFAULT 1,
updated_at DATETIME2 DEFAULT GETDATE(),
updated_by BIGINT
);

파일 보기

@@ -0,0 +1,141 @@
-- WBX Spring Framework — MySQL 스키마 (utf8mb4)
-- Hibernate ddl-auto와 병행 사용 가능 (Flyway 활성화 시 이 파일 사용)
CREATE TABLE IF NOT EXISTS wbx_users (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
email VARCHAR(255) NOT NULL UNIQUE,
username VARCHAR(100) NOT NULL UNIQUE,
hashed_password VARCHAR(500),
full_name VARCHAR(255),
phone VARCHAR(50),
department_id BIGINT,
position_title VARCHAR(100),
employee_number VARCHAR(50) UNIQUE,
is_active TINYINT(1) DEFAULT 1,
is_admin TINYINT(1) DEFAULT 0,
mfa_enabled TINYINT(1) DEFAULT 0,
azure_oid VARCHAR(255),
sso_provider VARCHAR(50),
failed_login_attempts INT DEFAULT 0,
last_failed_login DATETIME,
locked_until DATETIME,
password_changed_at DATETIME,
must_change_password TINYINT(1) DEFAULT 0,
last_login_at DATETIME,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
created_by BIGINT,
updated_by BIGINT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS wbx_roles (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
code VARCHAR(50) NOT NULL UNIQUE,
name VARCHAR(100) NOT NULL,
description VARCHAR(500),
is_system TINYINT(1) DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS wbx_user_roles (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT NOT NULL,
role_id BIGINT NOT NULL,
UNIQUE KEY uk_user_role (user_id, role_id),
FOREIGN KEY (user_id) REFERENCES wbx_users(id),
FOREIGN KEY (role_id) REFERENCES wbx_roles(id)
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS wbx_role_permissions (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
role_id BIGINT NOT NULL,
module VARCHAR(100) NOT NULL,
action VARCHAR(50) NOT NULL,
dept_scope VARCHAR(20) DEFAULT 'OWN',
UNIQUE KEY uk_role_perm (role_id, module, action),
FOREIGN KEY (role_id) REFERENCES wbx_roles(id)
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS wbx_refresh_tokens (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT NOT NULL,
token_hash VARCHAR(500) NOT NULL,
device_info VARCHAR(500),
ip_address VARCHAR(50),
expires_at DATETIME NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES wbx_users(id)
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS wbx_totp_secrets (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT NOT NULL UNIQUE,
encrypted_secret VARCHAR(500) NOT NULL,
verified TINYINT(1) DEFAULT 0,
backup_codes VARCHAR(2000),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
created_by BIGINT,
updated_by BIGINT,
FOREIGN KEY (user_id) REFERENCES wbx_users(id)
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS wbx_login_history (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT,
email VARCHAR(255),
action VARCHAR(50),
auth_method VARCHAR(50),
ip_address VARCHAR(50),
user_agent VARCHAR(500),
failure_reason VARCHAR(500),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS wbx_notifications (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT NOT NULL,
title VARCHAR(500),
message TEXT,
type VARCHAR(50),
is_read TINYINT(1) DEFAULT 0,
link VARCHAR(1000),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES wbx_users(id)
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS wbx_audit_logs (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT,
username VARCHAR(255),
action VARCHAR(50) NOT NULL,
resource VARCHAR(100) NOT NULL,
resource_id BIGINT,
detail VARCHAR(4000),
ip_address VARCHAR(50),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS wbx_file_uploads (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT,
original_name VARCHAR(500),
stored_name VARCHAR(500),
file_key VARCHAR(500),
content_type VARCHAR(200),
file_size BIGINT,
category VARCHAR(100),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS wbx_system_config (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
config_key VARCHAR(100) NOT NULL UNIQUE,
config_value VARCHAR(4000),
value_type VARCHAR(20) DEFAULT 'STRING',
description VARCHAR(500),
is_editable TINYINT(1) DEFAULT 1,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
updated_by BIGINT
) ENGINE=InnoDB;

파일 보기

@@ -0,0 +1,134 @@
-- WBX Spring Framework — Oracle 스키마
CREATE TABLE wbx_users (
id NUMBER(19) GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
email VARCHAR2(255) NOT NULL UNIQUE,
username VARCHAR2(100) NOT NULL UNIQUE,
hashed_password VARCHAR2(500),
full_name VARCHAR2(255),
phone VARCHAR2(50),
department_id NUMBER(19),
position_title VARCHAR2(100),
employee_number VARCHAR2(50) UNIQUE,
is_active NUMBER(1) DEFAULT 1,
is_admin NUMBER(1) DEFAULT 0,
mfa_enabled NUMBER(1) DEFAULT 0,
azure_oid VARCHAR2(255),
sso_provider VARCHAR2(50),
failed_login_attempts NUMBER(10) DEFAULT 0,
last_failed_login TIMESTAMP,
locked_until TIMESTAMP,
password_changed_at TIMESTAMP,
must_change_password NUMBER(1) DEFAULT 0,
last_login_at TIMESTAMP,
created_at TIMESTAMP DEFAULT SYSTIMESTAMP,
updated_at TIMESTAMP DEFAULT SYSTIMESTAMP,
created_by NUMBER(19),
updated_by NUMBER(19)
);
CREATE TABLE wbx_roles (
id NUMBER(19) GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
code VARCHAR2(50) NOT NULL UNIQUE,
name VARCHAR2(100) NOT NULL,
description VARCHAR2(500),
is_system NUMBER(1) DEFAULT 0,
created_at TIMESTAMP DEFAULT SYSTIMESTAMP,
updated_at TIMESTAMP DEFAULT SYSTIMESTAMP
);
CREATE TABLE wbx_user_roles (
id NUMBER(19) GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
user_id NUMBER(19) NOT NULL REFERENCES wbx_users(id),
role_id NUMBER(19) NOT NULL REFERENCES wbx_roles(id),
CONSTRAINT uk_wbx_user_role UNIQUE (user_id, role_id)
);
CREATE TABLE wbx_role_permissions (
id NUMBER(19) GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
role_id NUMBER(19) NOT NULL REFERENCES wbx_roles(id),
module VARCHAR2(100) NOT NULL,
action VARCHAR2(50) NOT NULL,
dept_scope VARCHAR2(20) DEFAULT 'OWN',
CONSTRAINT uk_wbx_role_perm UNIQUE (role_id, module, action)
);
CREATE TABLE wbx_refresh_tokens (
id NUMBER(19) GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
user_id NUMBER(19) NOT NULL REFERENCES wbx_users(id),
token_hash VARCHAR2(500) NOT NULL,
device_info VARCHAR2(500),
ip_address VARCHAR2(50),
expires_at TIMESTAMP NOT NULL,
created_at TIMESTAMP DEFAULT SYSTIMESTAMP
);
CREATE TABLE wbx_totp_secrets (
id NUMBER(19) GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
user_id NUMBER(19) NOT NULL UNIQUE REFERENCES wbx_users(id),
encrypted_secret VARCHAR2(500) NOT NULL,
verified NUMBER(1) DEFAULT 0,
backup_codes VARCHAR2(2000),
created_at TIMESTAMP DEFAULT SYSTIMESTAMP,
updated_at TIMESTAMP DEFAULT SYSTIMESTAMP,
created_by NUMBER(19),
updated_by NUMBER(19)
);
CREATE TABLE wbx_login_history (
id NUMBER(19) GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
user_id NUMBER(19),
email VARCHAR2(255),
action VARCHAR2(50),
auth_method VARCHAR2(50),
ip_address VARCHAR2(50),
user_agent VARCHAR2(500),
failure_reason VARCHAR2(500),
created_at TIMESTAMP DEFAULT SYSTIMESTAMP
);
CREATE TABLE wbx_notifications (
id NUMBER(19) GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
user_id NUMBER(19) NOT NULL REFERENCES wbx_users(id),
title VARCHAR2(500),
message CLOB,
type VARCHAR2(50),
is_read NUMBER(1) DEFAULT 0,
link VARCHAR2(1000),
created_at TIMESTAMP DEFAULT SYSTIMESTAMP
);
CREATE TABLE wbx_audit_logs (
id NUMBER(19) GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
user_id NUMBER(19),
username VARCHAR2(255),
action VARCHAR2(50) NOT NULL,
resource VARCHAR2(100) NOT NULL,
resource_id NUMBER(19),
detail VARCHAR2(4000),
ip_address VARCHAR2(50),
created_at TIMESTAMP DEFAULT SYSTIMESTAMP
);
CREATE TABLE wbx_file_uploads (
id NUMBER(19) GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
user_id NUMBER(19),
original_name VARCHAR2(500),
stored_name VARCHAR2(500),
file_key VARCHAR2(500),
content_type VARCHAR2(200),
file_size NUMBER(19),
category VARCHAR2(100),
created_at TIMESTAMP DEFAULT SYSTIMESTAMP
);
CREATE TABLE wbx_system_config (
id NUMBER(19) GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
config_key VARCHAR2(100) NOT NULL UNIQUE,
config_value VARCHAR2(4000),
value_type VARCHAR2(20) DEFAULT 'STRING',
description VARCHAR2(500),
is_editable NUMBER(1) DEFAULT 1,
updated_at TIMESTAMP DEFAULT SYSTIMESTAMP,
updated_by NUMBER(19)
);

파일 보기

@@ -0,0 +1,134 @@
-- WBX Spring Framework — PostgreSQL 스키마
CREATE TABLE IF NOT EXISTS wbx_users (
id BIGSERIAL PRIMARY KEY,
email VARCHAR(255) NOT NULL UNIQUE,
username VARCHAR(100) NOT NULL UNIQUE,
hashed_password VARCHAR(500),
full_name VARCHAR(255),
phone VARCHAR(50),
department_id BIGINT,
position_title VARCHAR(100),
employee_number VARCHAR(50) UNIQUE,
is_active BOOLEAN DEFAULT TRUE,
is_admin BOOLEAN DEFAULT FALSE,
mfa_enabled BOOLEAN DEFAULT FALSE,
azure_oid VARCHAR(255),
sso_provider VARCHAR(50),
failed_login_attempts INT DEFAULT 0,
last_failed_login TIMESTAMP,
locked_until TIMESTAMP,
password_changed_at TIMESTAMP,
must_change_password BOOLEAN DEFAULT FALSE,
last_login_at TIMESTAMP,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW(),
created_by BIGINT,
updated_by BIGINT
);
CREATE TABLE IF NOT EXISTS wbx_roles (
id BIGSERIAL PRIMARY KEY,
code VARCHAR(50) NOT NULL UNIQUE,
name VARCHAR(100) NOT NULL,
description VARCHAR(500),
is_system BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS wbx_user_roles (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL REFERENCES wbx_users(id),
role_id BIGINT NOT NULL REFERENCES wbx_roles(id),
UNIQUE (user_id, role_id)
);
CREATE TABLE IF NOT EXISTS wbx_role_permissions (
id BIGSERIAL PRIMARY KEY,
role_id BIGINT NOT NULL REFERENCES wbx_roles(id),
module VARCHAR(100) NOT NULL,
action VARCHAR(50) NOT NULL,
dept_scope VARCHAR(20) DEFAULT 'OWN',
UNIQUE (role_id, module, action)
);
CREATE TABLE IF NOT EXISTS wbx_refresh_tokens (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL REFERENCES wbx_users(id),
token_hash VARCHAR(500) NOT NULL,
device_info VARCHAR(500),
ip_address VARCHAR(50),
expires_at TIMESTAMP NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS wbx_totp_secrets (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL UNIQUE REFERENCES wbx_users(id),
encrypted_secret VARCHAR(500) NOT NULL,
verified BOOLEAN DEFAULT FALSE,
backup_codes VARCHAR(2000),
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW(),
created_by BIGINT,
updated_by BIGINT
);
CREATE TABLE IF NOT EXISTS wbx_login_history (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT,
email VARCHAR(255),
action VARCHAR(50),
auth_method VARCHAR(50),
ip_address VARCHAR(50),
user_agent VARCHAR(500),
failure_reason VARCHAR(500),
created_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS wbx_notifications (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL REFERENCES wbx_users(id),
title VARCHAR(500),
message TEXT,
type VARCHAR(50),
is_read BOOLEAN DEFAULT FALSE,
link VARCHAR(1000),
created_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS wbx_audit_logs (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT,
username VARCHAR(255),
action VARCHAR(50) NOT NULL,
resource VARCHAR(100) NOT NULL,
resource_id BIGINT,
detail VARCHAR(4000),
ip_address VARCHAR(50),
created_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS wbx_file_uploads (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT,
original_name VARCHAR(500),
stored_name VARCHAR(500),
file_key VARCHAR(500),
content_type VARCHAR(200),
file_size BIGINT,
category VARCHAR(100),
created_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS wbx_system_config (
id BIGSERIAL PRIMARY KEY,
config_key VARCHAR(100) NOT NULL UNIQUE,
config_value VARCHAR(4000),
value_type VARCHAR(20) DEFAULT 'STRING',
description VARCHAR(500),
is_editable BOOLEAN DEFAULT TRUE,
updated_at TIMESTAMP DEFAULT NOW(),
updated_by BIGINT
);