diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 68e5096..3b51ec7 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -10,9 +10,39 @@ "WebFetch(domain:developers.cloudflare.com)", "Bash(git add:*)", "Bash(mkdir:*)", - "Bash(cp:*)" + "Bash(cp:*)", + "Bash(npm run init-db:*)", + "Bash(npm start)", + "Bash(set PORT=3001)", + "Bash(node:*)", + "Bash(curl:*)", + "Bash(mv:*)", + "Bash(true)", + "Bash(PORT=3001 npm start)", + "Bash(sqlite3:*)", + "Bash(PORT=3002 npm start)", + "Bash(taskkill:*)", + "Bash(rm:*)", + "mcp__playwright__browser_navigate", + "mcp__playwright__browser_type", + "mcp__playwright__browser_click", + "mcp__playwright__browser_snapshot", + "mcp__playwright__browser_handle_dialog", + "mcp__playwright__browser_close", + "mcp__playwright__browser_console_messages", + "mcp__playwright__browser_press_key", + "mcp__playwright__browser_file_upload", + "mcp__playwright__browser_select_option", + "Bash(tasklist)", + "Bash(start http://localhost:8000)", + "Bash(npm --version)", + "mcp__sequential-thinking__sequentialthinking" ], "deny": [], - "ask": [] - } + "ask": [], + "additionalDirectories": [ + "C:\\c\\Users\\COMTREE\\claude_code" + ] + }, + "default-mode": "plan" } \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c2c1347 --- /dev/null +++ b/.gitignore @@ -0,0 +1,151 @@ +# Dependencies +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Coverage directory used by tools like istanbul +coverage/ + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage +.grunt + +# Bower dependency directory +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons +build/Release + +# Dependency directories +jspm_packages/ + +# Optional npm cache directory +.npm + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.local +.env.development.local +.env.test.local +.env.production.local + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# Grunt intermediate storage +.grunt + +# Bower dependency directory +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Optional npm cache directory +.npm + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env + +# next.js build output +.next + +# Nuxt.js build output +.nuxt + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Database files +*.db +*.sqlite +*.sqlite3 + +# Upload files (production) +uploads/* +!uploads/.gitkeep + +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# IDE files +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# Temporary files +*.tmp +*.temp diff --git a/.playwright-mcp/-.hwp b/.playwright-mcp/-.hwp new file mode 100644 index 0000000..c3e18e2 Binary files /dev/null and b/.playwright-mcp/-.hwp differ diff --git a/.playwright-mcp/-.zip b/.playwright-mcp/-.zip new file mode 100644 index 0000000..4895e1e Binary files /dev/null and b/.playwright-mcp/-.zip differ diff --git a/.playwright-mcp/-2025-7-xls-filename-UTF-8-EC-84-B8-EB-B6-80-20-EC-A7-80-EA-B8-89-EB-82-B4-EC-97-AD-282025-7-EC-9B-94-20-EC-8B-AC-EC-95-BC-20-EB-B9-84-EC-83-81-EA-B7-BC-EB-AC-B4-29-EC-8B-A0-EB-8F-99-ED-9D-AC.xls b/.playwright-mcp/-2025-7-xls-filename-UTF-8-EC-84-B8-EB-B6-80-20-EC-A7-80-EA-B8-89-EB-82-B4-EC-97-AD-282025-7-EC-9B-94-20-EC-8B-AC-EC-95-BC-20-EB-B9-84-EC-83-81-EA-B7-BC-EB-AC-B4-29-EC-8B-A0-EB-8F-99-ED-9D-AC.xls new file mode 100644 index 0000000..1a20d92 Binary files /dev/null and b/.playwright-mcp/-2025-7-xls-filename-UTF-8-EC-84-B8-EB-B6-80-20-EC-A7-80-EA-B8-89-EB-82-B4-EC-97-AD-282025-7-EC-9B-94-20-EC-8B-AC-EC-95-BC-20-EB-B9-84-EC-83-81-EA-B7-BC-EB-AC-B4-29-EC-8B-A0-EB-8F-99-ED-9D-AC.xls differ diff --git a/.playwright-mcp/-6-.png b/.playwright-mcp/-6-.png new file mode 100644 index 0000000..f229d64 Binary files /dev/null and b/.playwright-mcp/-6-.png differ diff --git a/.playwright-mcp/-hwp-filename-UTF-8-EB-AC-B8-ED-99-94-EC-B2-B4-ED-97-98-EA-B4-80-20-EA-B8-B0-EA-B0-84-EC-A0-9C-EA-B7-BC-EB-A1-9C-EC-9E-90-20-EC-B1-84-EC-9A-A9-20-EA-B3-B5-EA-B3-A0-EB-AC-B8.hwp b/.playwright-mcp/-hwp-filename-UTF-8-EB-AC-B8-ED-99-94-EC-B2-B4-ED-97-98-EA-B4-80-20-EA-B8-B0-EA-B0-84-EC-A0-9C-EA-B7-BC-EB-A1-9C-EC-9E-90-20-EC-B1-84-EC-9A-A9-20-EA-B3-B5-EA-B3-A0-EB-AC-B8.hwp new file mode 100644 index 0000000..c3e18e2 Binary files /dev/null and b/.playwright-mcp/-hwp-filename-UTF-8-EB-AC-B8-ED-99-94-EC-B2-B4-ED-97-98-EA-B4-80-20-EA-B8-B0-EA-B0-84-EC-A0-9C-EA-B7-BC-EB-A1-9C-EC-9E-90-20-EC-B1-84-EC-9A-A9-20-EA-B3-B5-EA-B3-A0-EB-AC-B8.hwp differ diff --git a/.playwright-mcp/20250807-084242.jpg b/.playwright-mcp/20250807-084242.jpg new file mode 100644 index 0000000..92add3f Binary files /dev/null and b/.playwright-mcp/20250807-084242.jpg differ diff --git a/.playwright-mcp/문화체험관-다도체험-운영.zip b/.playwright-mcp/문화체험관-다도체험-운영.zip new file mode 100644 index 0000000..afb6cbb Binary files /dev/null and b/.playwright-mcp/문화체험관-다도체험-운영.zip differ diff --git a/admin/api-client.js b/admin/api-client.js new file mode 100644 index 0000000..f0a7dcb --- /dev/null +++ b/admin/api-client.js @@ -0,0 +1,260 @@ +// 관리자용 API 클라이언트 +// SQLite 백엔드와 통신하는 함수들 + +const API_BASE_URL = ''; + +// API 요청 헬퍼 함수 +async function apiRequest(url, options = {}) { + const fullUrl = `${API_BASE_URL}${url}`; + console.log('🌐 API 요청:', options.method || 'GET', fullUrl); + console.log('요청 옵션:', options); + + const response = await fetch(fullUrl, { + credentials: 'include', // 세션 쿠키 포함 + headers: { + 'Content-Type': 'application/json', + ...options.headers + }, + ...options + }); + + console.log('📨 응답 받음:', response.status, response.statusText); + console.log('응답 URL:', response.url); + + if (!response.ok) { + const error = await response.text(); + console.error('❌ API 오류 응답:', error); + throw new Error(`API Error: ${response.status} - ${error}`); + } + + return response; +} + +// 인증 관련 API +const AuthAPI = { + // 현재 세션 확인 + async getSession() { + try { + const response = await apiRequest('/api/auth/session'); + return await response.json(); + } catch (error) { + console.error('세션 확인 오류:', error); + return { user: null }; + } + }, + + // 로그인 + async login(email, password) { + try { + const response = await apiRequest('/api/auth/login', { + method: 'POST', + body: JSON.stringify({ email, password }) + }); + return await response.json(); + } catch (error) { + console.error('로그인 오류:', error); + throw error; + } + }, + + // 로그아웃 + async logout() { + try { + await apiRequest('/api/auth/logout', { + method: 'POST' + }); + } catch (error) { + console.error('로그아웃 오류:', error); + throw error; + } + } +}; + +// 파일 관리 API +const FilesAPI = { + // 모든 파일 조회 (관리자용) + async getAll() { + try { + const response = await apiRequest('/api/files'); + return await response.json(); + } catch (error) { + console.error('파일 목록 조회 오류:', error); + throw error; + } + }, + + // 공개 파일 조회 (일반 사용자용) + async getPublic() { + try { + const response = await apiRequest('/api/files/public'); + return await response.json(); + } catch (error) { + console.error('공개 파일 목록 조회 오류:', error); + throw error; + } + }, + + // 파일 추가 + async create(formData) { + try { + const response = await fetch('/api/files', { + method: 'POST', + credentials: 'include', + body: formData // FormData는 Content-Type 헤더를 자동 설정 + }); + + if (!response.ok) { + const error = await response.text(); + throw new Error(`API Error: ${response.status} - ${error}`); + } + + return await response.json(); + } catch (error) { + console.error('파일 추가 오류:', error); + throw error; + } + }, + + // 파일 수정 (FormData 지원) + async update(id, data) { + try { + let requestOptions; + + if (data instanceof FormData) { + // FormData인 경우 (파일 업로드 포함) + requestOptions = { + method: 'PUT', + credentials: 'include', + body: data // FormData는 Content-Type 헤더를 자동 설정 + }; + + console.log('📁 FormData를 사용한 파일 수정 요청'); + const response = await fetch(`/api/files/${id}`, requestOptions); + + if (!response.ok) { + const error = await response.text(); + throw new Error(`API Error: ${response.status} - ${error}`); + } + + return await response.json(); + } else { + // 일반 JSON 데이터인 경우 + const response = await apiRequest(`/api/files/${id}`, { + method: 'PUT', + body: JSON.stringify(data) + }); + return await response.json(); + } + } catch (error) { + console.error('파일 수정 오류:', error); + throw error; + } + }, + + // 파일 삭제 + async delete(id) { + try { + await apiRequest(`/api/files/${id}`, { + method: 'DELETE' + }); + } catch (error) { + console.error('파일 삭제 오류:', error); + throw error; + } + }, + + // 파일 다운로드 + async download(fileId, attachmentId) { + try { + const response = await apiRequest(`/api/download/${fileId}/${attachmentId}`); + return response; + } catch (error) { + console.error('파일 다운로드 오류:', error); + throw error; + } + } +}; + +// 카테고리 관리 API +const CategoriesAPI = { + // 모든 카테고리 조회 + async getAll() { + try { + const response = await apiRequest('/api/categories'); + return await response.json(); + } catch (error) { + console.error('카테고리 목록 조회 오류:', error); + throw error; + } + }, + + // 카테고리 추가 + async create(name) { + try { + const response = await apiRequest('/api/categories', { + method: 'POST', + body: JSON.stringify({ name }) + }); + return await response.json(); + } catch (error) { + console.error('카테고리 추가 오류:', error); + throw error; + } + }, + + // 카테고리 수정 + async update(id, name) { + try { + const url = `/api/categories/${id}`; + console.log('🔄 카테고리 수정 API 호출:', url); + console.log('전송 데이터:', { id, name }); + + const response = await apiRequest(url, { + method: 'PUT', + body: JSON.stringify({ name }) + }); + + console.log('API 응답 상태:', response.status); + const result = await response.json(); + console.log('API 응답 데이터:', result); + return result; + } catch (error) { + console.error('카테고리 수정 오류:', error); + throw error; + } + }, + + // 카테고리 삭제 + async delete(id) { + try { + await apiRequest(`/api/categories/${id}`, { + method: 'DELETE' + }); + } catch (error) { + console.error('카테고리 삭제 오류:', error); + throw error; + } + } +}; + +// 연결 테스트 API +const SystemAPI = { + // 서버 연결 테스트 + async testConnection() { + try { + const response = await fetch('/api/health'); + return response.ok; + } catch (error) { + console.error('연결 테스트 오류:', error); + return false; + } + } +}; + +// 전역으로 내보내기 +window.AdminAPI = { + Auth: AuthAPI, + Files: FilesAPI, + Categories: CategoriesAPI, + System: SystemAPI +}; diff --git a/admin/index.html b/admin/index.html index 6f173a4..7ec02c7 100644 --- a/admin/index.html +++ b/admin/index.html @@ -3,45 +3,72 @@
-파일과 문서를 효율적으로 관리하세요
-