summaryrefslogtreecommitdiff
path: root/lib/users/middleware
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-07-07 01:44:45 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-07-07 01:44:45 +0000
commit90f79a7a691943a496f67f01c1e493256070e4de (patch)
tree37275fde3ae08c2bca384fbbc8eb378de7e39230 /lib/users/middleware
parentfbb3b7f05737f9571b04b0a8f4f15c0928de8545 (diff)
(대표님) 변경사항 20250707 10시 43분 - unstaged 변경사항 추가
Diffstat (limited to 'lib/users/middleware')
-rw-r--r--lib/users/middleware/page-tracking.ts98
1 files changed, 98 insertions, 0 deletions
diff --git a/lib/users/middleware/page-tracking.ts b/lib/users/middleware/page-tracking.ts
new file mode 100644
index 00000000..bd93fb82
--- /dev/null
+++ b/lib/users/middleware/page-tracking.ts
@@ -0,0 +1,98 @@
+
+// lib/middleware/page-tracking.ts - 페이지 방문 추적 미들웨어
+import { NextRequest, NextResponse } from 'next/server'
+import { getToken } from 'next-auth/jwt'
+import { UAParser } from 'ua-parser-js';
+import { SessionRepository } from '../session/repository'
+
+export async function trackPageVisit(request: NextRequest) {
+ try {
+ const token = await getToken({ req: request })
+ const url = new URL(request.url)
+
+ // API 경로나 정적 파일은 추적하지 않음
+ if (url.pathname.startsWith('/api') ||
+ url.pathname.startsWith('/_next') ||
+ url.pathname.includes('.')) {
+ return
+ }
+
+ const userAgent = request.headers.get('user-agent') || ''
+ const parser = new UAParser(userAgent)
+ const result = parser.getResult()
+
+ // 활성 세션 조회
+ let sessionId = null
+ if (token?.id) {
+ const activeSession = await SessionRepository.getActiveSessionByUserId(token.id)
+ if (activeSession) {
+ sessionId = activeSession.id
+ // 세션 활동 시간 업데이트
+ await SessionRepository.updateLoginSession(activeSession.id, {
+ lastActivityAt: new Date()
+ })
+ }
+ }
+
+ // 페이지 방문 기록
+ await SessionRepository.recordPageVisit({
+ userId: token?.id || undefined,
+ sessionId,
+ route: url.pathname,
+ pageTitle: extractPageTitle(url.pathname), // 구현 필요
+ referrer: request.headers.get('referer') || undefined,
+ ipAddress: getClientIP(request),
+ userAgent,
+ queryParams: url.search ? url.search.substring(1) : undefined,
+ deviceType: getDeviceType(result.device.type),
+ browserName: result.browser.name,
+ osName: result.os.name,
+ })
+
+ } catch (error) {
+ console.error('Failed to track page visit:', error)
+ }
+}
+
+function getClientIP(request: NextRequest): string {
+ const forwarded = request.headers.get('x-forwarded-for');
+ const realIP = request.headers.get('x-real-ip');
+ const cfConnectingIP = request.headers.get('cf-connecting-ip'); // Cloudflare
+
+ if (cfConnectingIP) {
+ return cfConnectingIP;
+ }
+
+ if (forwarded) {
+ return forwarded.split(',')[0].trim();
+ }
+
+ if (realIP) {
+ return realIP;
+ }
+
+ // NextRequest에는 ip 프로퍼티가 없으므로 기본값 반환
+ return '127.0.0.1';
+}
+
+
+function getDeviceType(deviceType?: string): string {
+ if (!deviceType) return 'desktop'
+ if (deviceType === 'mobile') return 'mobile'
+ if (deviceType === 'tablet') return 'tablet'
+ return 'desktop'
+}
+
+function extractPageTitle(pathname: string): string {
+ // 라우트 기반 페이지 제목 매핑
+ const titleMap: Record<string, string> = {
+ '/': 'Home',
+ '/dashboard': 'Dashboard',
+ '/profile': 'Profile',
+ '/settings': 'Settings',
+ // 추가 필요
+ }
+
+ return titleMap[pathname] || pathname
+}
+