summaryrefslogtreecommitdiff
path: root/lib/polices/service.ts
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-08-06 04:23:40 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-08-06 04:23:40 +0000
commitde2ac5a2860bc25180971e7a11f852d9d44675b7 (patch)
treeb931c363f2cb19e177a0a7b17190d5de2a82d709 /lib/polices/service.ts
parent6c549b0f264e9be4d60af38f9efc05b189d6849f (diff)
(대표님) 정기평가, 법적검토, 정책, 가입관련 처리 및 관련 컴포넌트 추가, 메뉴 변경
Diffstat (limited to 'lib/polices/service.ts')
-rw-r--r--lib/polices/service.ts341
1 files changed, 341 insertions, 0 deletions
diff --git a/lib/polices/service.ts b/lib/polices/service.ts
new file mode 100644
index 00000000..33cd592c
--- /dev/null
+++ b/lib/polices/service.ts
@@ -0,0 +1,341 @@
+'use server'
+
+import db from '@/db/db'
+import { policyVersions, userConsents, consentLogs } from '@/db/schema'
+import { eq, desc, and } from 'drizzle-orm'
+import { revalidatePath } from 'next/cache'
+
+// 정책 버전 생성
+export async function createPolicyVersion(data: {
+ policyType: 'privacy_policy' | 'terms_of_service'
+ version: string
+ content: string
+ effectiveDate: Date
+}) {
+ try {
+ // 트랜잭션으로 처리
+ const result = await db.transaction(async (tx) => {
+ // 기존의 현재 정책들을 비활성화
+ await tx
+ .update(policyVersions)
+ .set({ isCurrent: false })
+ .where(eq(policyVersions.policyType, data.policyType))
+
+ // 새 정책 버전 생성
+ const [newPolicy] = await tx
+ .insert(policyVersions)
+ .values({
+ policyType: data.policyType,
+ version: data.version,
+ content: data.content,
+ effectiveDate: data.effectiveDate,
+ isCurrent: true,
+ })
+ .returning()
+
+ return newPolicy
+ })
+
+ revalidatePath('/evcp/policies')
+ return { success: true, policy: result }
+ } catch (error) {
+ console.error('Error creating policy version:', error)
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : '정책 생성에 실패했습니다.'
+ }
+ }
+}
+
+// 정책 버전 활성화
+export async function activatePolicyVersion(policyId: number) {
+ try {
+ // 먼저 해당 정책의 타입을 조회
+ const targetPolicy = await db
+ .select()
+ .from(policyVersions)
+ .where(eq(policyVersions.id, policyId))
+ .limit(1)
+
+ if (targetPolicy.length === 0) {
+ return { success: false, error: '정책을 찾을 수 없습니다.' }
+ }
+
+ // 트랜잭션으로 처리
+ await db.transaction(async (tx) => {
+ // 해당 정책 타입의 모든 버전을 비활성화
+ await tx
+ .update(policyVersions)
+ .set({ isCurrent: false })
+ .where(eq(policyVersions.policyType, targetPolicy[0].policyType))
+
+ // 선택한 버전만 활성화
+ await tx
+ .update(policyVersions)
+ .set({ isCurrent: true })
+ .where(eq(policyVersions.id, policyId))
+ })
+
+ revalidatePath('/admin/policies')
+ return { success: true }
+ } catch (error) {
+ console.error('Error activating policy version:', error)
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : '정책 활성화에 실패했습니다.'
+ }
+ }
+}
+
+// 정책 히스토리 조회
+export async function getPolicyHistory(policyType: 'privacy_policy' | 'terms_of_service') {
+ try {
+ const history = await db
+ .select()
+ .from(policyVersions)
+ .where(eq(policyVersions.policyType, policyType))
+ .orderBy(desc(policyVersions.createdAt))
+
+ return { success: true, data: history }
+ } catch (error) {
+ console.error('Error fetching policy history:', error)
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : '히스토리 조회에 실패했습니다.'
+ }
+ }
+}
+
+// 현재 활성 정책들 조회
+export async function getCurrentPolicies() {
+ try {
+ const currentPolicies = await db
+ .select()
+ .from(policyVersions)
+ .where(eq(policyVersions.isCurrent, true))
+
+ // 정책 타입별로 그룹화
+ const grouped = currentPolicies.reduce((acc, policy) => {
+ acc[policy.policyType] = policy
+ return acc
+ }, {} as Record<string, any>)
+
+ return { success: true, data: grouped }
+ } catch (error) {
+ console.error('Error fetching current policies:', error)
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : '정책 조회에 실패했습니다.'
+ }
+ }
+}
+
+// 모든 정책 조회 (관리자용)
+export async function getAllPolicies() {
+ try {
+ const allPolicies = await db
+ .select()
+ .from(policyVersions)
+ .orderBy(desc(policyVersions.createdAt))
+
+ // 정책 타입별로 그룹화
+ const grouped = allPolicies.reduce((acc, policy) => {
+ if (!acc[policy.policyType]) {
+ acc[policy.policyType] = []
+ }
+ acc[policy.policyType].push(policy)
+ return acc
+ }, {} as Record<string, any[]>)
+
+ return { success: true, data: grouped }
+ } catch (error) {
+ console.error('Error fetching all policies:', error)
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : '정책 조회에 실패했습니다.'
+ }
+ }
+}
+
+// 정책 통계 조회
+export async function getPolicyStats() {
+ try {
+ // 각 정책별 버전 수와 최신 업데이트 날짜
+ const stats = await db
+ .select({
+ policyType: policyVersions.policyType,
+ totalVersions: 'COUNT(*)',
+ latestUpdate: 'MAX(created_at)',
+ currentVersion: policyVersions.version,
+ })
+ .from(policyVersions)
+ .where(eq(policyVersions.isCurrent, true))
+ .groupBy(policyVersions.policyType, policyVersions.version)
+
+ return { success: true, data: stats }
+ } catch (error) {
+ console.error('Error fetching policy stats:', error)
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : '통계 조회에 실패했습니다.'
+ }
+ }
+}
+
+// 사용자 동의 기록
+export async function recordUserConsent(data: {
+ userId: number
+ consents: Array<{
+ consentType: 'privacy_policy' | 'terms_of_service' | 'marketing' | 'optional'
+ consentStatus: boolean
+ policyVersion: string
+ }>
+ ipAddress?: string
+ userAgent?: string
+}) {
+ try {
+ const result = await db.transaction(async (tx) => {
+ const consentRecords = []
+ const logRecords = []
+
+ for (const consent of data.consents) {
+ // 사용자 동의 기록
+ const [consentRecord] = await tx
+ .insert(userConsents)
+ .values({
+ userId: data.userId,
+ consentType: consent.consentType,
+ consentStatus: consent.consentStatus,
+ policyVersion: consent.policyVersion,
+ ipAddress: data.ipAddress,
+ userAgent: data.userAgent,
+ })
+ .returning()
+
+ consentRecords.push(consentRecord)
+
+ // 동의 로그 기록
+ const [logRecord] = await tx
+ .insert(consentLogs)
+ .values({
+ userId: data.userId,
+ consentType: consent.consentType,
+ action: 'consent',
+ oldStatus: null,
+ newStatus: consent.consentStatus,
+ policyVersion: consent.policyVersion,
+ ipAddress: data.ipAddress,
+ userAgent: data.userAgent,
+ })
+ .returning()
+
+ logRecords.push(logRecord)
+ }
+
+ return { consents: consentRecords, logs: logRecords }
+ })
+
+ return { success: true, data: result }
+ } catch (error) {
+ console.error('Error recording user consent:', error)
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : '동의 기록에 실패했습니다.'
+ }
+ }
+}
+
+// 사용자 동의 상태 조회
+export async function getUserConsentStatus(userId: number) {
+ try {
+ const consents = await db
+ .select()
+ .from(userConsents)
+ .where(eq(userConsents.userId, userId))
+ .orderBy(desc(userConsents.consentedAt))
+
+ // 각 동의 타입별 최신 상태만 반환
+ const latestConsents = consents.reduce((acc, consent) => {
+ if (!acc[consent.consentType] ||
+ new Date(consent.consentedAt) > new Date(acc[consent.consentType].consentedAt)) {
+ acc[consent.consentType] = consent
+ }
+ return acc
+ }, {} as Record<string, any>)
+
+ return { success: true, data: latestConsents }
+ } catch (error) {
+ console.error('Error fetching user consent status:', error)
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : '동의 상태 조회에 실패했습니다.'
+ }
+ }
+}
+
+// 사용자 동의 철회
+export async function revokeUserConsent(data: {
+ userId: number
+ consentType: 'privacy_policy' | 'terms_of_service' | 'marketing' | 'optional'
+ revokeReason?: string
+ ipAddress?: string
+ userAgent?: string
+}) {
+ try {
+ // 현재 동의 상태 조회
+ const currentConsent = await db
+ .select()
+ .from(userConsents)
+ .where(
+ and(
+ eq(userConsents.userId, data.userId),
+ eq(userConsents.consentType, data.consentType)
+ )
+ )
+ .orderBy(desc(userConsents.consentedAt))
+ .limit(1)
+
+ if (currentConsent.length === 0) {
+ return { success: false, error: '동의 기록을 찾을 수 없습니다.' }
+ }
+
+ const result = await db.transaction(async (tx) => {
+ // 동의 철회 기록
+ const [updatedConsent] = await tx
+ .update(userConsents)
+ .set({
+ consentStatus: false,
+ revokedAt: new Date(),
+ revokeReason: data.revokeReason,
+ })
+ .where(eq(userConsents.id, currentConsent[0].id))
+ .returning()
+
+ // 철회 로그 기록
+ const [logRecord] = await tx
+ .insert(consentLogs)
+ .values({
+ userId: data.userId,
+ consentType: data.consentType,
+ action: 'revoke',
+ oldStatus: currentConsent[0].consentStatus,
+ newStatus: false,
+ policyVersion: currentConsent[0].policyVersion,
+ ipAddress: data.ipAddress,
+ userAgent: data.userAgent,
+ additionalData: data.revokeReason ? { revokeReason: data.revokeReason } : null,
+ })
+ .returning()
+
+ return { consent: updatedConsent, log: logRecord }
+ })
+
+ return { success: true, data: result }
+ } catch (error) {
+ console.error('Error revoking user consent:', error)
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : '동의 철회에 실패했습니다.'
+ }
+ }
+} \ No newline at end of file