summaryrefslogtreecommitdiff
path: root/db/schema/consent.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 /db/schema/consent.ts
parent6c549b0f264e9be4d60af38f9efc05b189d6849f (diff)
(대표님) 정기평가, 법적검토, 정책, 가입관련 처리 및 관련 컴포넌트 추가, 메뉴 변경
Diffstat (limited to 'db/schema/consent.ts')
-rw-r--r--db/schema/consent.ts138
1 files changed, 138 insertions, 0 deletions
diff --git a/db/schema/consent.ts b/db/schema/consent.ts
new file mode 100644
index 00000000..a02d5575
--- /dev/null
+++ b/db/schema/consent.ts
@@ -0,0 +1,138 @@
+// schema/consent.ts
+import {
+ pgTable,
+ integer,
+ varchar,
+ boolean,
+ timestamp,
+ text,
+ json,
+ pgEnum,
+ uniqueIndex,
+ index,
+ } from "drizzle-orm/pg-core";
+import { users } from "./users";
+
+ // 동의 타입 enum
+ export const consentTypeEnum = pgEnum("consent_type", [
+ "privacy_policy",
+ "terms_of_service",
+ "marketing",
+ "optional"
+ ]);
+
+ // 동의 액션 enum
+ export const consentActionEnum = pgEnum("consent_action", [
+ "consent",
+ "revoke",
+ "update"
+ ]);
+
+ // 정책 타입 enum
+ export const policyTypeEnum = pgEnum("policy_type", [
+ "privacy_policy",
+ "terms_of_service"
+ ]);
+
+ // 1. 정책 버전 관리 테이블
+ export const policyVersions = pgTable("policy_versions", {
+ id: integer("id").primaryKey().generatedAlwaysAsIdentity(),
+ policyType: policyTypeEnum("policy_type").notNull(),
+ version: varchar("version", { length: 20 }).notNull(),
+ content: text("content").notNull(),
+ effectiveDate: timestamp("effective_date", { withTimezone: true }).notNull(),
+ isCurrent: boolean("is_current").default(false).notNull(),
+ createdAt: timestamp("created_at", { withTimezone: true })
+ .defaultNow()
+ .notNull(),
+ }, (table) => {
+ return {
+ // 정책 타입과 버전의 유니크 조합
+ policyVersionUniqueIdx: uniqueIndex("policy_versions_type_version_idx")
+ .on(table.policyType, table.version),
+ // 현재 버전 조회용 인덱스
+ currentPolicyIdx: index("policy_versions_current_idx")
+ .on(table.isCurrent),
+ // 효력 발생일 인덱스
+ effectiveDateIdx: index("policy_versions_effective_date_idx")
+ .on(table.effectiveDate),
+ };
+ });
+
+ // 2. 사용자 동의 내역 테이블
+ export const userConsents = pgTable("user_consents", {
+ id: integer("id").primaryKey().generatedAlwaysAsIdentity(),
+ userId: integer("user_id")
+ .references(() => users.id, { onDelete: "cascade" })
+ .notNull(),
+ consentType: consentTypeEnum("consent_type").notNull(),
+ consentStatus: boolean("consent_status").default(false).notNull(),
+ policyVersion: varchar("policy_version", { length: 20 }).notNull(),
+ consentedAt: timestamp("consented_at", { withTimezone: true })
+ .defaultNow()
+ .notNull(),
+ ipAddress: varchar("ip_address", { length: 45 }), // IPv6 지원
+ userAgent: text("user_agent"),
+ revokedAt: timestamp("revoked_at", { withTimezone: true }),
+ revokeReason: text("revoke_reason"),
+ createdAt: timestamp("created_at", { withTimezone: true })
+ .defaultNow()
+ .notNull(),
+ updatedAt: timestamp("updated_at", { withTimezone: true })
+ .defaultNow()
+ .notNull(),
+ }, (table) => {
+ return {
+ // 사용자별 동의 타입 조회용 인덱스
+ userConsentTypeIdx: index("user_consents_user_type_idx")
+ .on(table.userId, table.consentType),
+ // 동의 시점 인덱스
+ consentedAtIdx: index("user_consents_consented_at_idx")
+ .on(table.consentedAt),
+ // 정책 버전별 인덱스
+ policyVersionIdx: index("user_consents_policy_version_idx")
+ .on(table.policyVersion),
+ };
+ });
+
+ // 3. 동의 로그 테이블 (모든 동의/철회 이력 보관)
+ export const consentLogs = pgTable("consent_logs", {
+ id: integer("id").primaryKey().generatedAlwaysAsIdentity(),
+ userId: integer("user_id")
+ .references(() => users.id, { onDelete: "cascade" })
+ .notNull(),
+ consentType: consentTypeEnum("consent_type").notNull(),
+ action: consentActionEnum("action").notNull(),
+ oldStatus: boolean("old_status"),
+ newStatus: boolean("new_status").notNull(),
+ policyVersion: varchar("policy_version", { length: 20 }).notNull(),
+ ipAddress: varchar("ip_address", { length: 45 }),
+ userAgent: text("user_agent"),
+ actionTimestamp: timestamp("action_timestamp", { withTimezone: true })
+ .defaultNow()
+ .notNull(),
+ additionalData: json("additional_data"), // 추가 메타데이터
+ }, (table) => {
+ return {
+ // 사용자별 액션 시간 순 조회용 인덱스
+ userActionTimestampIdx: index("consent_logs_user_action_timestamp_idx")
+ .on(table.userId, table.actionTimestamp),
+ // 동의 타입별 인덱스
+ consentTypeIdx: index("consent_logs_consent_type_idx")
+ .on(table.consentType),
+ // 액션 타입별 인덱스
+ actionIdx: index("consent_logs_action_idx")
+ .on(table.action),
+ };
+ });
+
+
+ export type PolicyVersion = typeof policyVersions.$inferSelect;
+ export type NewPolicyVersion = typeof policyVersions.$inferInsert;
+
+ export type UserConsent = typeof userConsents.$inferSelect;
+ export type NewUserConsent = typeof userConsents.$inferInsert;
+
+ export type ConsentLog = typeof consentLogs.$inferSelect;
+ export type NewConsentLog = typeof consentLogs.$inferInsert;
+ \ No newline at end of file