summaryrefslogtreecommitdiff
path: root/db/schema/compliance.ts
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-08-21 06:57:36 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-08-21 06:57:36 +0000
commit02b1cf005cf3e1df64183d20ba42930eb2767a9f (patch)
treee932c54d5260b0e6fda2b46be2a6ba1c3ee30434 /db/schema/compliance.ts
parentd78378ecd7ceede1429359f8058c7a99ac34b1b7 (diff)
(대표님, 최겸) 설계메뉴추가, 작업사항 업데이트
설계메뉴 - 문서관리 설계메뉴 - 벤더 데이터 gtc 메뉴 업데이트 정보시스템 - 메뉴리스트 및 정보 업데이트 파일 라우트 업데이트 엑셀임포트 개선 기본계약 개선 벤더 가입과정 변경 및 개선 벤더 기본정보 - pq 돌체 오류 수정 및 개선 벤더 로그인 과정 이메일 오류 수정
Diffstat (limited to 'db/schema/compliance.ts')
-rw-r--r--db/schema/compliance.ts173
1 files changed, 173 insertions, 0 deletions
diff --git a/db/schema/compliance.ts b/db/schema/compliance.ts
new file mode 100644
index 00000000..b49650b1
--- /dev/null
+++ b/db/schema/compliance.ts
@@ -0,0 +1,173 @@
+import { pgTable, integer, varchar, text, timestamp, boolean, decimal, serial } from 'drizzle-orm/pg-core';
+import { relations } from 'drizzle-orm';
+import { basicContract } from './basicContractDocumnet';
+import { users } from './users';
+
+// 1. 설문조사 템플릿 (어떤 계약 타입에 어떤 설문을 적용할지)
+export const complianceSurveyTemplates = pgTable('compliance_survey_templates', {
+ id: serial('id').primaryKey(),
+ name: varchar('name', { length: 255 }).notNull(), // '기본 준법 설문', '금융업 준법 설문' 등
+ description: text('description'),
+ version: varchar('version', { length: 50 }).notNull().default('1.0'),
+ isActive: boolean('is_active').notNull().default(true),
+ createdAt: timestamp('created_at').defaultNow(),
+ updatedAt: timestamp('updated_at').defaultNow(),
+});
+
+// 2. 설문 질문들
+export const complianceQuestions = pgTable('compliance_questions', {
+ id: serial('id').primaryKey(),
+ templateId: integer('template_id').references(() => complianceSurveyTemplates.id).notNull(),
+ questionNumber: varchar('question_number', { length: 10 }).notNull(), // '4', '10-1' 등
+ questionText: text('question_text').notNull(),
+ questionType: varchar('question_type', { length: 20 }).notNull(),
+ // 'RADIO', 'CHECKBOX', 'TEXT', 'TEXTAREA', 'DROPDOWN', 'FILE', 'PERCENTAGE', 'CONDITIONAL'
+ isRequired: boolean('is_required').notNull().default(true),
+ hasDetailText: boolean('has_detail_text').notNull().default(false), // 상세 기술 필요 여부
+ hasFileUpload: boolean('has_file_upload').notNull().default(false), // 첨부파일 필요 여부
+ parentQuestionId: integer('parent_question_id'), // 조건부 질문의 부모
+ conditionalValue: varchar('conditional_value', { length: 100 }), // 부모 질문의 어떤 답변에서 나타날지
+ displayOrder: integer('display_order').notNull(),
+ createdAt: timestamp('created_at').defaultNow(),
+});
+
+// 3. 선택형 질문의 옵션들
+export const complianceQuestionOptions = pgTable('compliance_question_options', {
+ id: serial('id').primaryKey(),
+ questionId: integer('question_id').references(() => complianceQuestions.id).notNull(),
+ optionValue: varchar('option_value', { length: 100 }).notNull(), // 'YES', 'NO', 'COMPANY_CORP' 등
+ optionText: varchar('option_text', { length: 255 }).notNull(), // '네', '아니오', '주식회사/유한회사' 등
+ allowsOtherInput: boolean('allows_other_input').notNull().default(false), // '기타' 선택 시 수기입력 가능
+ displayOrder: integer('display_order').notNull(),
+});
+
+// 4. 설문 응답 (기본계약과 연결)
+export const complianceResponses = pgTable('compliance_responses', {
+ id: serial('id').primaryKey(),
+ basicContractId: integer('basic_contract_id').references(() => basicContract.id).notNull(),
+ templateId: integer('template_id').references(() => complianceSurveyTemplates.id).notNull(),
+ status: varchar('status', { length: 20 }).notNull().default('IN_PROGRESS'), // 'IN_PROGRESS', 'COMPLETED', 'REVIEWED'
+ completedAt: timestamp('completed_at'),
+ reviewedBy: integer('reviewed_by').references(() => users.id), // 검토자
+ reviewedAt: timestamp('reviewed_at'),
+ reviewNotes: text('review_notes'), // 검토 의견
+ createdAt: timestamp('created_at').defaultNow(),
+ updatedAt: timestamp('updated_at').defaultNow(),
+});
+
+// 5. 각 질문에 대한 답변
+export const complianceResponseAnswers = pgTable('compliance_response_answers', {
+ id: serial('id').primaryKey(),
+ responseId: integer('response_id').references(() => complianceResponses.id).notNull(),
+ questionId: integer('question_id').references(() => complianceQuestions.id).notNull(),
+ answerValue: text('answer_value'), // 선택값 또는 입력값
+ detailText: text('detail_text'), // 상세 기술 내용
+ otherText: varchar('other_text', { length: 500 }), // '기타' 선택 시 수기입력 내용
+ percentageValue: decimal('percentage_value', { precision: 5, scale: 2 }), // 지분율 등
+ createdAt: timestamp('created_at').defaultNow(),
+ updatedAt: timestamp('updated_at').defaultNow(),
+});
+
+// 6. 응답에 첨부된 파일들
+export const complianceResponseFiles = pgTable('compliance_response_files', {
+ id: serial('id').primaryKey(),
+ answerId: integer('answer_id').references(() => complianceResponseAnswers.id).notNull(),
+ fileName: varchar('file_name', { length: 255 }).notNull(),
+ filePath: varchar('file_path', { length: 1024 }).notNull(),
+ fileSize: integer('file_size'),
+ mimeType: varchar('mime_type', { length: 100 }),
+ uploadedAt: timestamp('uploaded_at').defaultNow(),
+});
+
+// Relations 정의
+export const complianceSurveyTemplatesRelations = relations(complianceSurveyTemplates, ({ many }) => ({
+ questions: many(complianceQuestions),
+ responses: many(complianceResponses),
+}));
+
+export const complianceQuestionsRelations = relations(complianceQuestions, ({ one, many }) => ({
+ template: one(complianceSurveyTemplates, {
+ fields: [complianceQuestions.templateId],
+ references: [complianceSurveyTemplates.id],
+ }),
+ parentQuestion: one(complianceQuestions, {
+ fields: [complianceQuestions.parentQuestionId],
+ references: [complianceQuestions.id],
+ }),
+ childQuestions: many(complianceQuestions),
+ options: many(complianceQuestionOptions),
+ answers: many(complianceResponseAnswers),
+}));
+
+export const complianceQuestionOptionsRelations = relations(complianceQuestionOptions, ({ one }) => ({
+ question: one(complianceQuestions, {
+ fields: [complianceQuestionOptions.questionId],
+ references: [complianceQuestions.id],
+ }),
+}));
+
+export const complianceResponsesRelations = relations(complianceResponses, ({ one, many }) => ({
+ basicContract: one(basicContract, {
+ fields: [complianceResponses.basicContractId],
+ references: [basicContract.id],
+ }),
+ template: one(complianceSurveyTemplates, {
+ fields: [complianceResponses.templateId],
+ references: [complianceSurveyTemplates.id],
+ }),
+ answers: many(complianceResponseAnswers),
+}));
+
+export const complianceResponseAnswersRelations = relations(complianceResponseAnswers, ({ one, many }) => ({
+ response: one(complianceResponses, {
+ fields: [complianceResponseAnswers.responseId],
+ references: [complianceResponses.id],
+ }),
+ question: one(complianceQuestions, {
+ fields: [complianceResponseAnswers.questionId],
+ references: [complianceQuestions.id],
+ }),
+ files: many(complianceResponseFiles),
+}));
+
+export const complianceResponseFilesRelations = relations(complianceResponseFiles, ({ one }) => ({
+ answer: one(complianceResponseAnswers, {
+ fields: [complianceResponseFiles.answerId],
+ references: [complianceResponseAnswers.id],
+ }),
+}));
+
+// 타입 정의
+export type ComplianceSurveyTemplate = typeof complianceSurveyTemplates.$inferSelect;
+export type ComplianceQuestion = typeof complianceQuestions.$inferSelect;
+export type ComplianceQuestionOption = typeof complianceQuestionOptions.$inferSelect;
+export type ComplianceResponse = typeof complianceResponses.$inferSelect;
+export type ComplianceResponseAnswer = typeof complianceResponseAnswers.$inferSelect;
+export type ComplianceResponseFile = typeof complianceResponseFiles.$inferSelect;
+
+// Insert 타입
+export type NewComplianceSurveyTemplate = typeof complianceSurveyTemplates.$inferInsert;
+export type NewComplianceQuestion = typeof complianceQuestions.$inferInsert;
+export type NewComplianceQuestionOption = typeof complianceQuestionOptions.$inferInsert;
+export type NewComplianceResponse = typeof complianceResponses.$inferInsert;
+export type NewComplianceResponseAnswer = typeof complianceResponseAnswers.$inferInsert;
+export type NewComplianceResponseFile = typeof complianceResponseFiles.$inferInsert;
+
+// 질문 타입 상수
+export const QUESTION_TYPES = {
+ RADIO: 'RADIO', // 라디오 버튼 (단일 선택)
+ CHECKBOX: 'CHECKBOX', // 체크박스 (다중 선택)
+ TEXT: 'TEXT', // 단일 라인 텍스트
+ TEXTAREA: 'TEXTAREA', // 다중 라인 텍스트
+ DROPDOWN: 'DROPDOWN', // 드롭다운 선택
+ FILE: 'FILE', // 파일 업로드
+ PERCENTAGE: 'PERCENTAGE', // 지분율 등 퍼센트 입력
+ CONDITIONAL: 'CONDITIONAL', // 조건부 질문
+} as const;
+
+// 응답 상태 상수
+export const RESPONSE_STATUS = {
+ IN_PROGRESS: 'IN_PROGRESS',
+ COMPLETED: 'COMPLETED',
+ REVIEWED: 'REVIEWED',
+} as const; \ No newline at end of file