feat: 토큰 만료 시 자동 로그아웃 기능 추가 및 테이블명 수정

🔐 토큰 만료 시 자동 로그아웃 기능:
1. JWT 토큰 만료 시간 대폭 연장:
   - 액세스 토큰: 24시간 → 7일
   - 리프레시 토큰: 7일 → 30일
   - 사용자 편의성 크게 향상

2. 토큰 만료 감지 및 처리:
   - isTokenExpired() 함수 추가
   - JWT 페이로드 파싱하여 exp 확인
   - 현재 시간과 비교하여 만료 여부 판단

3. 자동 로그아웃 처리:
   - API 호출 시 401 오류 감지
   - 주기적 토큰 만료 확인 (5분마다)
   - 만료 시 자동 인증 데이터 정리
   - 사용자 알림 후 로그인 페이지 리다이렉트

4. 개선된 인증 데이터 관리:
   - clearAuthData() 함수로 통합 관리
   - token, user, userInfo, currentUser 모두 정리
   - 메모리 누수 방지

🐛 데이터베이스 테이블명 수정:
1. projectModel.js:
   - Projects → projects (대문자 → 소문자)
   - 실제 DB 테이블명과 일치

2. taskModel.js:
   - Tasks → tasks (대문자 → 소문자)
   - 실제 DB 테이블명과 일치

3. API 오류 해결:
   - '테이블이 존재하지 않습니다' 오류 수정
   - projects, tasks API 정상 작동

 사용자 경험 개선:
- 토큰 만료로 인한 예상치 못한 오류 방지
- 명확한 만료 알림 메시지
- 자동 로그아웃으로 보안 강화
- 더 긴 세션 유지로 편의성 향상

🔧 기술적 개선:
- JWT 페이로드 안전한 파싱
- 에러 핸들링 강화
- 주기적 백그라운드 확인
- 전역 함수로 재사용성 향상

🎯 결과:
- 안정적인 인증 시스템
- 사용자 친화적인 세션 관리
- 보안성과 편의성의 균형
- API 호출 오류 해결

테스트:
- 토큰 만료 후 자동 로그아웃 확인
- projects, tasks API 정상 작동 확인
This commit is contained in:
Hyungi Ahn
2025-11-03 12:49:25 +09:00
parent 2445b3b29e
commit 790d12fe13
6 changed files with 82 additions and 37 deletions

View File

@@ -1,9 +1,9 @@
// daily-work-report.js - 통합 API 설정 적용 버전
// daily-work-report.js - 브라우저 호환 버전
// =================================================================
// 🌐 통합 API 설정 import
// 🌐 API 설정 (window 객체에서 가져오기)
// =================================================================
import { API, getAuthHeaders, apiCall } from '/js/api-config.js';
// API 설정은 api-config.js에서 window 객체에 설정됨
// 전역 변수
let workTypes = [];
@@ -117,7 +117,7 @@ async function loadData() {
async function loadWorkers() {
try {
console.log('Workers API 호출 중... (통합 API 사용)');
const data = await apiCall(`${API}/workers`);
const data = await window.apiCall(`${window.API}/workers`);
workers = Array.isArray(data) ? data : (data.data || data.workers || []);
console.log('✅ Workers 로드 성공:', workers.length);
} catch (error) {
@@ -129,7 +129,7 @@ async function loadWorkers() {
async function loadProjects() {
try {
console.log('Projects API 호출 중... (통합 API 사용)');
const data = await apiCall(`${API}/projects`);
const data = await window.apiCall(`${window.API}/projects`);
projects = Array.isArray(data) ? data : (data.data || data.projects || []);
console.log('✅ Projects 로드 성공:', projects.length);
} catch (error) {
@@ -140,7 +140,7 @@ async function loadProjects() {
async function loadWorkTypes() {
try {
const data = await apiCall(`${API}/daily-work-reports/work-types`);
const data = await window.apiCall(`${window.API}/daily-work-reports/work-types`);
if (Array.isArray(data) && data.length > 0) {
workTypes = data;
console.log('✅ 작업 유형 API 사용 (통합 설정)');
@@ -159,7 +159,7 @@ async function loadWorkTypes() {
async function loadWorkStatusTypes() {
try {
const data = await apiCall(`${API}/daily-work-reports/work-status-types`);
const data = await window.apiCall(`${window.API}/daily-work-reports/work-status-types`);
if (Array.isArray(data) && data.length > 0) {
workStatusTypes = data;
console.log('✅ 업무 상태 유형 API 사용 (통합 설정)');
@@ -177,7 +177,7 @@ async function loadWorkStatusTypes() {
async function loadErrorTypes() {
try {
const data = await apiCall(`${API}/daily-work-reports/error-types`);
const data = await window.apiCall(`${window.API}/daily-work-reports/error-types`);
if (Array.isArray(data) && data.length > 0) {
errorTypes = data;
console.log('✅ 에러 유형 API 사용 (통합 설정)');
@@ -424,7 +424,7 @@ async function saveWorkReport() {
console.log('전송 데이터 (통합 API 사용):', requestData);
try {
const result = await apiCall(`${API}/daily-work-reports`, {
const result = await window.apiCall(`${window.API}/daily-work-reports`, {
method: 'POST',
body: JSON.stringify(requestData)
});
@@ -510,7 +510,7 @@ async function loadTodayWorkers() {
console.log(`🔒 본인 입력분만 조회 (통합 API): ${API}/daily-work-reports?${queryParams}`);
const rawData = await apiCall(`${API}/daily-work-reports?${queryParams}`);
const rawData = await window.apiCall(`${window.API}/daily-work-reports?${queryParams}`);
console.log('📊 당일 작업 데이터 (통합 API):', rawData);
let data = [];
@@ -645,7 +645,7 @@ async function editWorkItem(workId) {
// 1. 기존 데이터 조회 (통합 API 사용)
showMessage('작업 정보를 불러오는 중... (통합 API)', 'loading');
const workData = await apiCall(`${API}/daily-work-reports/${workId}`);
const workData = await window.apiCall(`${window.API}/daily-work-reports/${workId}`);
console.log('수정할 작업 데이터 (통합 API):', workData);
// 2. 수정 모달 표시
@@ -784,7 +784,7 @@ async function saveEditedWork() {
showMessage('작업을 수정하는 중... (통합 API)', 'loading');
const result = await apiCall(`${API}/daily-work-reports/${editingWorkId}`, {
const result = await window.apiCall(`${window.API}/daily-work-reports/${editingWorkId}`, {
method: 'PUT',
body: JSON.stringify(updateData)
});
@@ -813,7 +813,7 @@ async function deleteWorkItem(workId) {
showMessage('작업을 삭제하는 중... (통합 API)', 'loading');
// 개별 항목 삭제 API 호출 (본인 작성분만 삭제 가능) - 통합 API 사용
const result = await apiCall(`${API}/daily-work-reports/my-entry/${workId}`, {
const result = await window.apiCall(`${window.API}/daily-work-reports/my-entry/${workId}`, {
method: 'DELETE'
});