diff --git a/docker-compose.yml b/docker-compose.yml index 0c475cc..5f880fd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -416,6 +416,21 @@ services: # AI Service — 맥미니로 이전됨 (~/docker/tk-ai-service/) # ================================================================= + # ================================================================= + # Dashboard (tkds) + # ================================================================= + + tkds-web: + build: + context: ./tkds/web + dockerfile: Dockerfile + container_name: tk-tkds-web + restart: unless-stopped + ports: + - "30780:80" + networks: + - tk-network + # ================================================================= # Gateway # ================================================================= @@ -470,6 +485,7 @@ services: - TUNNEL_TOKEN=${CLOUDFLARE_TUNNEL_TOKEN} depends_on: - gateway + - tkds-web - system2-web - system3-web - tkpurchase-web diff --git a/gateway/html/shared/nav-header.js b/gateway/html/shared/nav-header.js index b1abc05..4126af2 100644 --- a/gateway/html/shared/nav-header.js +++ b/gateway/html/shared/nav-header.js @@ -62,10 +62,10 @@ var loginUrl; if (hostname.includes('technicalkorea.net')) { - loginUrl = window.location.protocol + '//tkfb.technicalkorea.net/dashboard'; + loginUrl = window.location.protocol + '//tkds.technicalkorea.net/dashboard'; } else { - // 개발 환경: Gateway 포트 (30000) - loginUrl = window.location.protocol + '//' + hostname + ':30000/dashboard'; + // 개발 환경: tkds 포트 (30780) + loginUrl = window.location.protocol + '//' + hostname + ':30780/dashboard'; } if (redirect) { diff --git a/gateway/nginx.conf b/gateway/nginx.conf index 7434f18..ca51262 100644 --- a/gateway/nginx.conf +++ b/gateway/nginx.conf @@ -7,21 +7,16 @@ server { # ===== Gateway 자체 페이지 (포털, 로그인) ===== root /usr/share/nginx/html; - # 대시보드 (로그인 + 네비게이션 허브 통합) - location = /dashboard { + # 로그인 페이지 + location = /login { add_header Cache-Control "no-store, no-cache, must-revalidate"; add_header Pragma "no-cache"; - try_files /dashboard.html =404; + try_files /login.html =404; } - # 루트 → 대시보드 리다이렉트 - location = / { - return 302 /dashboard$is_args$args; - } - - # 로그인 → 대시보드 리다이렉트 - location = /login { - return 302 /dashboard$is_args$args; + # 대시보드 → tkds로 리다이렉트 (북마크 깨짐 방지) + location = /dashboard { + return 301 $scheme://tkds.technicalkorea.net/dashboard; } # 공유 JS/CSS (nav-header 등) diff --git a/system1-factory/web/js/api-base.js b/system1-factory/web/js/api-base.js index 432054e..b7aeefe 100644 --- a/system1-factory/web/js/api-base.js +++ b/system1-factory/web/js/api-base.js @@ -52,10 +52,10 @@ if ('caches' in window) { window.getLoginUrl = function() { var hostname = window.location.hostname; if (hostname.includes('technicalkorea.net')) { - return window.location.protocol + '//tkfb.technicalkorea.net/login?redirect=' + encodeURIComponent(window.location.href); + return window.location.protocol + '//tkds.technicalkorea.net/dashboard?redirect=' + encodeURIComponent(window.location.href); } - // 개발 환경: 게이트웨이 SSO 로그인 페이지 - return '/login?redirect=' + encodeURIComponent(window.location.href); + // 개발 환경: tkds 포트 (30780) + return window.location.protocol + '//' + hostname + ':30780/dashboard?redirect=' + encodeURIComponent(window.location.href); }; /** diff --git a/system1-factory/web/static/js/tkfb-core.js b/system1-factory/web/static/js/tkfb-core.js index 16b6110..078e854 100644 --- a/system1-factory/web/static/js/tkfb-core.js +++ b/system1-factory/web/static/js/tkfb-core.js @@ -16,8 +16,8 @@ function getToken() { return _cookieGet('sso_token') || localStorage.getItem('ss function getLoginUrl() { const h = location.hostname; const t = Date.now(); - if (h.includes('technicalkorea.net')) return location.protocol + '//tkfb.technicalkorea.net/login?redirect=' + encodeURIComponent(location.href) + '&_t=' + t; - return location.protocol + '//' + h + ':30000/login?redirect=' + encodeURIComponent(location.href) + '&_t=' + t; + if (h.includes('technicalkorea.net')) return location.protocol + '//tkds.technicalkorea.net/dashboard?redirect=' + encodeURIComponent(location.href) + '&_t=' + t; + return location.protocol + '//' + h + ':30780/dashboard?redirect=' + encodeURIComponent(location.href) + '&_t=' + t; } function decodeToken(t) { try { const b = atob(t.split('.')[1].replace(/-/g,'+').replace(/_/g,'/')); return JSON.parse(new TextDecoder().decode(Uint8Array.from(b, c => c.charCodeAt(0)))); } catch { return null; } } diff --git a/system2-report/web/js/api-base.js b/system2-report/web/js/api-base.js index 008e115..4e9e1d7 100644 --- a/system2-report/web/js/api-base.js +++ b/system2-report/web/js/api-base.js @@ -53,9 +53,9 @@ if ('serviceWorker' in navigator) { var hostname = window.location.hostname; var t = Date.now(); if (hostname.includes('technicalkorea.net')) { - return window.location.protocol + '//tkfb.technicalkorea.net/login?redirect=' + encodeURIComponent(window.location.href) + '&_t=' + t; + return window.location.protocol + '//tkds.technicalkorea.net/dashboard?redirect=' + encodeURIComponent(window.location.href) + '&_t=' + t; } - return window.location.protocol + '//' + hostname + ':30000/login?redirect=' + encodeURIComponent(window.location.href) + '&_t=' + t; + return window.location.protocol + '//' + hostname + ':30780/dashboard?redirect=' + encodeURIComponent(window.location.href) + '&_t=' + t; }; window.clearSSOAuth = function() { diff --git a/system3-nonconformance/web/static/js/core/auth-manager.js b/system3-nonconformance/web/static/js/core/auth-manager.js index 6616ec9..a1db25a 100644 --- a/system3-nonconformance/web/static/js/core/auth-manager.js +++ b/system3-nonconformance/web/static/js/core/auth-manager.js @@ -92,9 +92,9 @@ class AuthManager { _getLoginUrl() { const hostname = window.location.hostname; if (hostname.includes('technicalkorea.net')) { - return window.location.protocol + '//tkfb.technicalkorea.net/login?redirect=' + encodeURIComponent(window.location.href); + return window.location.protocol + '//tkds.technicalkorea.net/dashboard?redirect=' + encodeURIComponent(window.location.href); } - return window.location.protocol + '//' + hostname + ':30000/login?redirect=' + encodeURIComponent(window.location.href); + return window.location.protocol + '//' + hostname + ':30780/dashboard?redirect=' + encodeURIComponent(window.location.href); } /** diff --git a/tkds/web/Dockerfile b/tkds/web/Dockerfile new file mode 100644 index 0000000..5ab7db1 --- /dev/null +++ b/tkds/web/Dockerfile @@ -0,0 +1,5 @@ +FROM nginx:alpine +COPY nginx.conf /etc/nginx/conf.d/default.conf +COPY dashboard.html /usr/share/nginx/html/dashboard.html +EXPOSE 80 +CMD ["nginx", "-g", "daemon off;"] diff --git a/gateway/html/dashboard.html b/tkds/web/dashboard.html similarity index 95% rename from gateway/html/dashboard.html rename to tkds/web/dashboard.html index f63802f..c6c0c44 100644 --- a/gateway/html/dashboard.html +++ b/tkds/web/dashboard.html @@ -326,22 +326,22 @@ if (hostname.includes('technicalkorea.net')) { return protocol + '//' + name + '.technicalkorea.net'; } - var ports = { tkreport: 30180, tkqc: 30280, tkuser: 30380, tkpurchase: 30480, tksafety: 30580, tksupport: 30680 }; + var ports = { tkfb: 30000, tkreport: 30180, tkqc: 30280, tkuser: 30380, tkpurchase: 30480, tksafety: 30580, tksupport: 30680 }; return protocol + '//' + hostname + ':' + (ports[name] || 30000); } // ===== Card Definitions ===== var DAILY_CARDS = [ - { id: 'tbm', name: 'TBM', icon: '\uD83D\uDCCB', href: '/pages/work/tbm.html', pageKey: 's1.work.tbm' }, - { id: 'report', name: '\uC791\uC5C5\uBCF4\uACE0\uC11C', icon: '\uD83D\uDCDD', href: '/pages/work/report-create.html', pageKey: 's1.work.report_create' }, + { id: 'tbm', name: 'TBM', icon: '\uD83D\uDCCB', subdomain: 'tkfb', path: '/pages/work/tbm.html', pageKey: 's1.work.tbm' }, + { id: 'report', name: '\uC791\uC5C5\uBCF4\uACE0\uC11C', icon: '\uD83D\uDCDD', subdomain: 'tkfb', path: '/pages/work/report-create.html', pageKey: 's1.work.report_create' }, { id: 'issue', name: '\uC548\uC804\uC2E0\uACE0', icon: '\u26A0\uFE0F', subdomain: 'tkreport', path: '/pages/safety/issue-report.html', accessKey: 'system2' }, - { id: 'checkin', name: '\uCD9C\uD1F4\uADFC \uCCB4\uD06C', icon: '\u23F0', href: '/pages/attendance/checkin.html', pageKey: 's1.inspection.checkin' }, - { id: 'vacation', name: '\uB0B4 \uC5F0\uCC28 \uC815\uBCF4', icon: '\uD83C\uDFD6\uFE0F', href: '/pages/attendance/my-vacation-info.html', pageKey: 's1.attendance.my_vacation_info' }, - { id: 'leave', name: '\uD734\uAC00 \uC2E0\uCCAD', icon: '\uD83D\uDCC5', href: '/pages/attendance/vacation-request.html', pageKey: 's1.attendance.vacation_request' } + { id: 'checkin', name: '\uCD9C\uD1F4\uADFC \uCCB4\uD06C', icon: '\u23F0', subdomain: 'tkfb', path: '/pages/attendance/checkin.html', pageKey: 's1.inspection.checkin' }, + { id: 'vacation', name: '\uB0B4 \uC5F0\uCC28 \uC815\uBCF4', icon: '\uD83C\uDFD6\uFE0F', subdomain: 'tkfb', path: '/pages/attendance/my-vacation-info.html', pageKey: 's1.attendance.my_vacation_info' }, + { id: 'leave', name: '\uD734\uAC00 \uC2E0\uCCAD', icon: '\uD83D\uDCC5', subdomain: 'tkfb', path: '/pages/attendance/vacation-request.html', pageKey: 's1.attendance.vacation_request' } ]; var SYSTEM_CARDS = [ - { id: 'factory', name: '\uACF5\uC7A5\uAD00\uB9AC', icon: '\uD83C\uDFED', href: '/pages/dashboard.html', pageKey: 's1.dashboard', color: '#1a56db' }, + { id: 'factory', name: '\uACF5\uC7A5\uAD00\uB9AC', icon: '\uD83C\uDFED', subdomain: 'tkfb', path: '/pages/dashboard.html', pageKey: 's1.dashboard', color: '#1a56db' }, { id: 'report_sys', name: '\uC2E0\uACE0', icon: '\uD83D\uDEA8', subdomain: 'tkreport', accessKey: 'system2', color: '#dc2626' }, { id: 'quality', name: '\uBD80\uC801\uD569\uAD00\uB9AC', icon: '\uD83D\uDCCA', subdomain: 'tkqc', pageKey: 'issues_dashboard', color: '#059669' } ]; @@ -578,7 +578,7 @@ if (user) { // Partner redirect if (user.partner_company_id) { - window.location.href = '/pages/partner/partner-portal.html'; + window.location.href = getSubdomainUrl('tkfb') + '/pages/partner/partner-portal.html'; return; } diff --git a/tkds/web/nginx.conf b/tkds/web/nginx.conf new file mode 100644 index 0000000..63e1147 --- /dev/null +++ b/tkds/web/nginx.conf @@ -0,0 +1,38 @@ +server { + listen 80; + server_name _; + + location = /dashboard { + add_header Cache-Control "no-store, no-cache, must-revalidate"; + add_header Pragma "no-cache"; + root /usr/share/nginx/html; + try_files /dashboard.html =404; + } + + location = / { + return 302 /dashboard$is_args$args; + } + + location /auth/ { + proxy_pass http://sso-auth:3000/api/auth/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + location /api/ { + proxy_pass http://system1-api:3005/api/; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + location /health { + access_log off; + return 200 '{"status":"ok","service":"tkds"}'; + add_header Content-Type application/json; + } +} diff --git a/tkpurchase/web/static/js/tkpurchase-core.js b/tkpurchase/web/static/js/tkpurchase-core.js index aea9a9d..d2110f0 100644 --- a/tkpurchase/web/static/js/tkpurchase-core.js +++ b/tkpurchase/web/static/js/tkpurchase-core.js @@ -21,8 +21,8 @@ function getToken() { return _cookieGet('sso_token') || localStorage.getItem('ss function getLoginUrl() { const h = location.hostname; const t = Date.now(); - if (h.includes('technicalkorea.net')) return location.protocol + '//tkfb.technicalkorea.net/login?redirect=' + encodeURIComponent(location.href) + '&_t=' + t; - return location.protocol + '//' + h + ':30000/login?redirect=' + encodeURIComponent(location.href) + '&_t=' + t; + if (h.includes('technicalkorea.net')) return location.protocol + '//tkds.technicalkorea.net/dashboard?redirect=' + encodeURIComponent(location.href) + '&_t=' + t; + return location.protocol + '//' + h + ':30780/dashboard?redirect=' + encodeURIComponent(location.href) + '&_t=' + t; } function decodeToken(t) { try { const b = atob(t.split('.')[1].replace(/-/g,'+').replace(/_/g,'/')); return JSON.parse(new TextDecoder().decode(Uint8Array.from(b, c => c.charCodeAt(0)))); } catch { return null; } } diff --git a/tksafety/web/static/js/tksafety-core.js b/tksafety/web/static/js/tksafety-core.js index 4a9ca41..0b201da 100644 --- a/tksafety/web/static/js/tksafety-core.js +++ b/tksafety/web/static/js/tksafety-core.js @@ -21,8 +21,8 @@ function getToken() { return _cookieGet('sso_token') || localStorage.getItem('ss function getLoginUrl() { const h = location.hostname; const t = Date.now(); - if (h.includes('technicalkorea.net')) return location.protocol + '//tkfb.technicalkorea.net/login?redirect=' + encodeURIComponent(location.href) + '&_t=' + t; - return location.protocol + '//' + h + ':30000/login?redirect=' + encodeURIComponent(location.href) + '&_t=' + t; + if (h.includes('technicalkorea.net')) return location.protocol + '//tkds.technicalkorea.net/dashboard?redirect=' + encodeURIComponent(location.href) + '&_t=' + t; + return location.protocol + '//' + h + ':30780/dashboard?redirect=' + encodeURIComponent(location.href) + '&_t=' + t; } function decodeToken(t) { try { const b = atob(t.split('.')[1].replace(/-/g,'+').replace(/_/g,'/')); return JSON.parse(new TextDecoder().decode(Uint8Array.from(b, c => c.charCodeAt(0)))); } catch { return null; } } diff --git a/tksupport/web/index.html b/tksupport/web/index.html index 3f7fce9..332b739 100644 --- a/tksupport/web/index.html +++ b/tksupport/web/index.html @@ -120,7 +120,7 @@ - + + + +