summaryrefslogtreecommitdiff
path: root/lib/users/middleware/page-tracking.ts
blob: bd93fb8218b96f93d9b2f80622d71771ab72654b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
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
}