refactor: 프론트엔드 SSO 인증 통합 및 API 경로 정리

- Gateway 로그인/포탈 페이지 SSO 연동
- System1 web/fastapi-bridge API base URL 동적 설정
- SSO 토큰 기반 인증 흐름 통일
- deprecated JS 파일 삭제

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Hyungi Ahn
2026-03-06 23:18:09 +09:00
parent ec755ed52f
commit 61c810bd47
63 changed files with 255 additions and 1357 deletions

View File

@@ -28,7 +28,6 @@ class WorkAnalysisAPIClient {
config.body = JSON.stringify(data);
}
console.log(`📡 API 호출: ${this.baseURL}${endpoint} (${method})`);
const response = await fetch(`${this.baseURL}${endpoint}`, config);
const result = await response.json();
@@ -37,11 +36,10 @@ class WorkAnalysisAPIClient {
throw new Error(result.message || `HTTP ${response.status}`);
}
console.log(`✅ API 성공: ${this.baseURL}${endpoint}`);
return result;
} catch (error) {
console.error(` API 실패: ${this.baseURL}${endpoint}`, error);
console.error(` API 실패: ${this.baseURL}${endpoint}`, error);
throw error;
}
}
@@ -68,11 +66,9 @@ class WorkAnalysisAPIClient {
* 기본 통계 조회
*/
async getBasicStats(startDate, endDate, projectId = null) {
console.log('🔍 getBasicStats 호출:', startDate, '~', endDate, projectId ? `(프로젝트: ${projectId})` : '');
const params = this.createDateParams(startDate, endDate,
projectId ? { project_id: projectId } : {}
);
console.log('🌐 API 요청 URL:', `/work-analysis/stats?${params}`);
return await this.apiCall(`/work-analysis/stats?${params}`);
}
@@ -138,20 +134,18 @@ class WorkAnalysisAPIClient {
* @returns {Promise<Array>} 결과 배열
*/
async batchCall(apiCalls) {
console.log('🔄 배치 API 호출 시작:', apiCalls.length, '개');
const promises = apiCalls.map(async ({ name, method, ...args }) => {
try {
const result = await this[method](...args);
return { name, success: true, data: result };
} catch (error) {
console.warn(`⚠️ ${name} API 오류:`, error);
console.warn(` ${name} API 오류:`, error);
return { name, success: false, error: error.message, data: null };
}
});
const results = await Promise.all(promises);
console.log('✅ 배치 API 호출 완료');
return results.reduce((acc, result) => {
acc[result.name] = result;

View File

@@ -23,7 +23,6 @@ class WorkAnalysisChartRenderer {
if (this.charts.has(chartId)) {
this.charts.get(chartId).destroy();
this.charts.delete(chartId);
console.log('🗑️ 차트 제거:', chartId);
}
}
@@ -33,7 +32,6 @@ class WorkAnalysisChartRenderer {
destroyAllCharts() {
this.charts.forEach((chart, id) => {
chart.destroy();
console.log('🗑️ 차트 제거:', id);
});
this.charts.clear();
}
@@ -52,7 +50,6 @@ class WorkAnalysisChartRenderer {
const chart = new Chart(canvas, config);
this.charts.set(chartId, chart);
console.log('📊 차트 생성:', chartId);
return chart;
}
@@ -65,7 +62,6 @@ class WorkAnalysisChartRenderer {
* @param {string} projectId - 프로젝트 ID (선택사항)
*/
async renderTimeSeriesChart(startDate, endDate, projectId = '') {
console.log('📈 시계열 차트 렌더링 시작');
try {
const api = window.WorkAnalysisAPI;
@@ -77,7 +73,7 @@ class WorkAnalysisChartRenderer {
const canvas = document.getElementById('workStatusChart');
if (!canvas) {
console.error(' workStatusChart 캔버스를 찾을 수 없습니다');
console.error(' workStatusChart 캔버스를 찾을 수 없습니다');
return;
}
@@ -125,10 +121,9 @@ class WorkAnalysisChartRenderer {
};
this.createChart('workStatus', canvas, config);
console.log('✅ 시계열 차트 렌더링 완료');
} catch (error) {
console.error(' 시계열 차트 렌더링 실패:', error);
console.error(' 시계열 차트 렌더링 실패:', error);
this._showChartError('workStatusChart', '시계열 차트를 불러올 수 없습니다');
}
}
@@ -140,11 +135,10 @@ class WorkAnalysisChartRenderer {
* @param {Array} projectData - 프로젝트 데이터
*/
renderStackedBarChart(projectData) {
console.log('📊 스택 바 차트 렌더링 시작');
const canvas = document.getElementById('projectDistributionChart');
if (!canvas) {
console.error(' projectDistributionChart 캔버스를 찾을 수 없습니다');
console.error(' projectDistributionChart 캔버스를 찾을 수 없습니다');
return;
}
@@ -212,7 +206,6 @@ class WorkAnalysisChartRenderer {
};
this.createChart('projectDistribution', canvas, config);
console.log('✅ 스택 바 차트 렌더링 완료');
}
/**
@@ -256,11 +249,10 @@ class WorkAnalysisChartRenderer {
* @param {Array} workerData - 작업자 데이터
*/
renderWorkerPerformanceChart(workerData) {
console.log('👤 작업자별 성과 차트 렌더링 시작');
const canvas = document.getElementById('workerPerformanceChart');
if (!canvas) {
console.error(' workerPerformanceChart 캔버스를 찾을 수 없습니다');
console.error(' workerPerformanceChart 캔버스를 찾을 수 없습니다');
return;
}
@@ -308,7 +300,6 @@ class WorkAnalysisChartRenderer {
};
this.createChart('workerPerformance', canvas, config);
console.log('✅ 작업자별 성과 차트 렌더링 완료');
}
// ========== 오류 분석 차트 ==========
@@ -318,11 +309,10 @@ class WorkAnalysisChartRenderer {
* @param {Array} errorData - 오류 데이터
*/
renderErrorAnalysisChart(errorData) {
console.log('⚠️ 오류 분석 차트 렌더링 시작');
const canvas = document.getElementById('errorAnalysisChart');
if (!canvas) {
console.error(' errorAnalysisChart 캔버스를 찾을 수 없습니다');
console.error(' errorAnalysisChart 캔버스를 찾을 수 없습니다');
return;
}
@@ -380,7 +370,6 @@ class WorkAnalysisChartRenderer {
};
this.createChart('errorAnalysis', canvas, config);
console.log('✅ 오류 분석 차트 렌더링 완료');
}
// ========== 유틸리티 ==========
@@ -421,9 +410,8 @@ class WorkAnalysisChartRenderer {
this.charts.forEach((chart, id) => {
try {
chart.resize();
console.log('📏 차트 리사이즈:', id);
} catch (error) {
console.warn('⚠️ 차트 리사이즈 실패:', id, error);
console.warn(' 차트 리사이즈 실패:', id, error);
}
});
}

View File

@@ -47,7 +47,6 @@ class WorkAnalysisDataProcessor {
* @returns {Object} 집계된 프로젝트 데이터
*/
aggregateProjectData(recentWorkData) {
console.log('📊 프로젝트 데이터 집계 시작');
if (!recentWorkData || recentWorkData.length === 0) {
return { projects: [], totalHours: 0 };
@@ -62,7 +61,6 @@ class WorkAnalysisDataProcessor {
// 주말 연차는 제외
if (isWeekend && isVacation) {
console.log('🏖️ 주말 연차/휴무 제외:', work.report_date, work.project_name);
return;
}
@@ -118,7 +116,6 @@ class WorkAnalysisDataProcessor {
const totalHours = projects.reduce((sum, p) => sum + p.totalHours, 0);
console.log('✅ 프로젝트 데이터 집계 완료:', projects.length, '개 프로젝트');
return { projects, totalHours };
}
@@ -151,7 +148,6 @@ class WorkAnalysisDataProcessor {
* @returns {Array} 집계된 오류 데이터
*/
aggregateErrorData(recentWorkData) {
console.log('📊 오류 분석 데이터 집계 시작');
if (!recentWorkData || recentWorkData.length === 0) {
return [];
@@ -166,7 +162,6 @@ class WorkAnalysisDataProcessor {
// 주말 연차는 완전히 제외
if (isWeekend && isVacation) {
console.log('🏖️ 주말 연차/휴무 제외:', work.report_date, work.project_name);
return;
}
@@ -243,7 +238,6 @@ class WorkAnalysisDataProcessor {
return (a.project_name || '').localeCompare(b.project_name || '');
});
console.log('✅ 오류 분석 데이터 집계 완료:', processedResult.length, '개 항목');
return processedResult;
}

View File

@@ -18,13 +18,11 @@ class WorkAnalysisMainController {
* 초기화
*/
init() {
console.log('🚀 작업 분석 메인 컨트롤러 초기화');
this.setupEventListeners();
this.setupStateListeners();
this.initializeUI();
console.log('✅ 작업 분석 메인 컨트롤러 초기화 완료');
}
/**
@@ -157,16 +155,14 @@ class WorkAnalysisMainController {
const startDate = document.getElementById('startDate').value;
const endDate = document.getElementById('endDate').value;
console.log('🔄 기간 확정 처리 시작:', startDate, '~', endDate);
this.state.confirmPeriod(startDate, endDate);
this.showToast('기간이 확정되었습니다', 'success');
console.log('✅ 기간 확정 완료 - 각 분석 버튼을 눌러서 데이터를 확인하세요');
} catch (error) {
console.error(' 기간 확정 처리 오류:', error);
console.error(' 기간 확정 처리 오류:', error);
this.state.setError(error);
this.showToast(error.message, 'error');
}
@@ -222,13 +218,10 @@ class WorkAnalysisMainController {
const { start, end } = currentState.confirmedPeriod;
try {
console.log('📊 기본 통계 로딩 시작 - 기간:', start, '~', end);
this.state.startLoading('기본 통계를 로딩 중입니다...');
console.log('🌐 API 호출 전 - getBasicStats 호출...');
const statsResponse = await this.api.getBasicStats(start, end);
console.log('📊 기본 통계 API 응답:', statsResponse);
if (statsResponse.success && statsResponse.data) {
const stats = statsResponse.data;
@@ -250,7 +243,6 @@ class WorkAnalysisMainController {
this.state.setCache('basicStats', cardData);
this.updateResultCards(cardData);
console.log('✅ 기본 통계 로딩 완료:', cardData);
} else {
// 기본값으로 카드 업데이트
const defaultData = {
@@ -261,11 +253,11 @@ class WorkAnalysisMainController {
errorRate: 0
};
this.updateResultCards(defaultData);
console.warn('⚠️ 기본 통계 데이터가 없어서 기본값으로 설정');
console.warn(' 기본 통계 데이터가 없어서 기본값으로 설정');
}
} catch (error) {
console.error(' 기본 통계 로드 실패:', error);
console.error(' 기본 통계 로드 실패:', error);
// 에러 시에도 기본값으로 카드 업데이트
const defaultData = {
totalHours: 0,
@@ -318,7 +310,6 @@ class WorkAnalysisMainController {
}
]);
console.log('🔍 기간별 작업 현황 API 응답:', batchData);
// 데이터 처리
const recentWorkData = batchData.recentWork?.success ? batchData.recentWork.data.data : [];
@@ -332,7 +323,7 @@ class WorkAnalysisMainController {
this.showToast('기간별 작업 현황 분석이 완료되었습니다', 'success');
} catch (error) {
console.error(' 기간별 작업 현황 분석 오류:', error);
console.error(' 기간별 작업 현황 분석 오류:', error);
this.state.setError(error);
this.showToast('기간별 작업 현황 분석에 실패했습니다', 'error');
} finally {
@@ -358,7 +349,6 @@ class WorkAnalysisMainController {
// 실제 API 호출
const distributionData = await this.api.getProjectDistributionData(start, end);
console.log('🔍 프로젝트별 분포 API 응답:', distributionData);
// 데이터 처리
const recentWorkData = distributionData.recentWork?.success ? distributionData.recentWork.data.data : [];
@@ -366,7 +356,6 @@ class WorkAnalysisMainController {
const projectData = this.dataProcessor.aggregateProjectData(recentWorkData);
console.log('📊 취합된 프로젝트 데이터:', projectData);
// 테이블 렌더링
this.tableRenderer.renderProjectDistributionTable(projectData, workerData);
@@ -374,7 +363,7 @@ class WorkAnalysisMainController {
this.showToast('프로젝트별 분포 분석이 완료되었습니다', 'success');
} catch (error) {
console.error(' 프로젝트별 분포 분석 오류:', error);
console.error(' 프로젝트별 분포 분석 오류:', error);
this.state.setError(error);
this.showToast('프로젝트별 분포 분석에 실패했습니다', 'error');
} finally {
@@ -399,7 +388,6 @@ class WorkAnalysisMainController {
const workerStatsResponse = await this.api.getWorkerStats(start, end);
console.log('👤 작업자 통계 API 응답:', workerStatsResponse);
if (workerStatsResponse.success && workerStatsResponse.data) {
this.chartRenderer.renderWorkerPerformanceChart(workerStatsResponse.data);
@@ -409,7 +397,7 @@ class WorkAnalysisMainController {
}
} catch (error) {
console.error(' 작업자별 성과 분석 오류:', error);
console.error(' 작업자별 성과 분석 오류:', error);
this.state.setError(error);
this.showToast('작업자별 성과 분석에 실패했습니다', 'error');
} finally {
@@ -438,7 +426,6 @@ class WorkAnalysisMainController {
this.api.getErrorAnalysis(start, end)
]);
console.log('🔍 오류 분석 API 응답:', recentWorkResponse);
if (recentWorkResponse.success && recentWorkResponse.data) {
this.tableRenderer.renderErrorAnalysisTable(recentWorkResponse.data);
@@ -448,7 +435,7 @@ class WorkAnalysisMainController {
}
} catch (error) {
console.error(' 오류 분석 실패:', error);
console.error(' 오류 분석 실패:', error);
this.state.setError(error);
this.showToast('오류 분석에 실패했습니다', 'error');
} finally {
@@ -571,13 +558,11 @@ class WorkAnalysisMainController {
* 토스트 메시지 표시
*/
showToast(message, type = 'info') {
console.log(`📢 ${type.toUpperCase()}: ${message}`);
// 간단한 토스트 구현 (실제로는 더 정교한 토스트 라이브러리 사용 권장)
if (type === 'error') {
alert(`${message}`);
} else if (type === 'success') {
console.log(`${message}`);
} else if (type === 'warning') {
alert(`⚠️ ${message}`);
}
@@ -587,7 +572,7 @@ class WorkAnalysisMainController {
* 에러 처리
*/
handleError(errorInfo) {
console.error(' 에러 발생:', errorInfo);
console.error(' 에러 발생:', errorInfo);
this.showToast(errorInfo.message, 'error');
}
@@ -597,7 +582,6 @@ class WorkAnalysisMainController {
* 컨트롤러 상태 디버그
*/
debug() {
console.log('🔍 메인 컨트롤러 상태:');
console.log('- API 클라이언트:', this.api);
console.log('- 상태 관리자:', this.state.getState());
console.log('- 차트 상태:', this.chartRenderer.getChartStatus());

View File

@@ -34,7 +34,6 @@ class WorkAnalysisModuleLoader {
* 모듈들을 순차적으로 로드
*/
async _loadModules() {
console.log('🚀 작업 분석 모듈 로딩 시작');
try {
// 의존성 순서대로 로드
@@ -42,11 +41,10 @@ class WorkAnalysisModuleLoader {
await this._loadModule(module);
}
console.log('✅ 모든 작업 분석 모듈 로딩 완료');
this._onAllModulesLoaded();
} catch (error) {
console.error(' 모듈 로딩 실패:', error);
console.error(' 모듈 로딩 실패:', error);
this._onLoadingError(error);
throw error;
}
@@ -58,7 +56,6 @@ class WorkAnalysisModuleLoader {
*/
async _loadModule(module) {
return new Promise((resolve, reject) => {
console.log(`📦 로딩 중: ${module.name}`);
const script = document.createElement('script');
script.src = module.path;
@@ -66,12 +63,11 @@ class WorkAnalysisModuleLoader {
script.onload = () => {
module.loaded = true;
console.log(`✅ 로딩 완료: ${module.name}`);
resolve();
};
script.onerror = (error) => {
console.error(` 로딩 실패: ${module.name}`, error);
console.error(` 로딩 실패: ${module.name}`, error);
reject(new Error(`Failed to load ${module.name}: ${module.path}`));
};
@@ -95,7 +91,7 @@ class WorkAnalysisModuleLoader {
const missingGlobals = requiredGlobals.filter(name => !window[name]);
if (missingGlobals.length > 0) {
console.warn('⚠️ 일부 전역 객체가 누락됨:', missingGlobals);
console.warn(' 일부 전역 객체가 누락됨:', missingGlobals);
}
// 하위 호환성을 위한 전역 함수들 설정
@@ -106,7 +102,6 @@ class WorkAnalysisModuleLoader {
detail: { modules: this.modules }
}));
console.log('🎉 작업 분석 시스템 준비 완료');
}
/**
@@ -165,7 +160,6 @@ class WorkAnalysisModuleLoader {
// 전역 함수로 등록
Object.assign(window, legacyFunctions);
console.log('🔗 하위 호환성 함수 설정 완료');
}
/**

View File

@@ -39,7 +39,6 @@ class WorkAnalysisStateManager {
* 초기화
*/
init() {
console.log('🔧 상태 관리자 초기화');
// 기본 날짜 설정 (현재 월)
const now = new Date();
@@ -63,7 +62,6 @@ class WorkAnalysisStateManager {
const prevState = { ...this.state };
this.state = { ...this.state, ...updates };
console.log('🔄 상태 업데이트:', updates);
// 리스너들에게 상태 변경 알림
this.notifyListeners(prevState, this.state);
@@ -94,7 +92,7 @@ class WorkAnalysisStateManager {
try {
callback(newState, prevState);
} catch (error) {
console.error(` 리스너 ${key} 오류:`, error);
console.error(` 리스너 ${key} 오류:`, error);
}
});
}
@@ -157,7 +155,6 @@ class WorkAnalysisStateManager {
}
});
console.log('✅ 기간 확정:', startDate, '~', endDate);
}
/**
@@ -177,7 +174,6 @@ class WorkAnalysisStateManager {
// DOM 업데이트 직접 수행
this.updateTabDOM(tabId);
console.log('🔄 탭 전환:', tabId);
}
/**
@@ -259,11 +255,9 @@ class WorkAnalysisStateManager {
const age = Date.now() - cached.timestamp;
if (age > maxAge) {
console.log('🗑️ 캐시 만료:', key);
return null;
}
console.log('📦 캐시 히트:', key);
return cached.data;
}
@@ -309,7 +303,7 @@ class WorkAnalysisStateManager {
isLoading: false
});
console.error(' 에러 발생:', errorInfo);
console.error(' 에러 발생:', errorInfo);
}
/**
@@ -353,8 +347,6 @@ class WorkAnalysisStateManager {
* 상태 디버그 정보 출력
*/
debug() {
console.log('🔍 현재 상태:', this.state);
console.log('👂 등록된 리스너:', Array.from(this.listeners.keys()));
}
}

View File

@@ -16,19 +16,17 @@ class WorkAnalysisTableRenderer {
* @param {Array} workerData - 작업자 데이터
*/
renderProjectDistributionTable(projectData, workerData) {
console.log('📋 프로젝트별 분포 테이블 렌더링 시작');
const tbody = document.getElementById('projectDistributionTableBody');
const tfoot = document.getElementById('projectDistributionTableFooter');
if (!tbody) {
console.error(' projectDistributionTableBody 요소를 찾을 수 없습니다');
console.error(' projectDistributionTableBody 요소를 찾을 수 없습니다');
return;
}
// 프로젝트 데이터가 없으면 작업자 데이터로 대체
if (!projectData || !projectData.projects || projectData.projects.length === 0) {
console.log('⚠️ 프로젝트 데이터가 없어서 작업자 데이터로 대체합니다.');
this._renderFallbackTable(workerData, tbody, tfoot);
return;
}
@@ -130,7 +128,6 @@ class WorkAnalysisTableRenderer {
tfoot.style.display = 'table-footer-group';
}
console.log('✅ 프로젝트별 분포 테이블 렌더링 완료');
}
/**
@@ -189,17 +186,14 @@ class WorkAnalysisTableRenderer {
* @param {Array} recentWorkData - 최근 작업 데이터
*/
renderErrorAnalysisTable(recentWorkData) {
console.log('📊 오류 분석 테이블 렌더링 시작');
console.log('📊 받은 데이터:', recentWorkData);
const tableBody = document.getElementById('errorAnalysisTableBody');
const tableFooter = document.getElementById('errorAnalysisTableFooter');
console.log('📊 DOM 요소 확인:', { tableBody, tableFooter });
// DOM 요소 존재 확인
if (!tableBody) {
console.error(' errorAnalysisTableBody 요소를 찾을 수 없습니다');
console.error(' errorAnalysisTableBody 요소를 찾을 수 없습니다');
return;
}
@@ -335,7 +329,6 @@ class WorkAnalysisTableRenderer {
}
}
console.log('✅ 오류 분석 테이블 렌더링 완료');
}
// ========== 기간별 작업 현황 테이블 ==========
@@ -347,11 +340,10 @@ class WorkAnalysisTableRenderer {
* @param {Array} recentWorkData - 최근 작업 데이터
*/
renderWorkStatusTable(projectData, workerData, recentWorkData) {
console.log('📈 기간별 작업 현황 테이블 렌더링 시작');
const tableContainer = document.querySelector('#work-status-tab .table-container');
if (!tableContainer) {
console.error(' 작업 현황 테이블 컨테이너를 찾을 수 없습니다');
console.error(' 작업 현황 테이블 컨테이너를 찾을 수 없습니다');
return;
}
@@ -431,7 +423,6 @@ class WorkAnalysisTableRenderer {
`;
tableContainer.innerHTML = tableHTML;
console.log('✅ 기간별 작업 현황 테이블 렌더링 완료');
}
/**