diff options
| author | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-08-21 06:57:36 +0000 |
|---|---|---|
| committer | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-08-21 06:57:36 +0000 |
| commit | 02b1cf005cf3e1df64183d20ba42930eb2767a9f (patch) | |
| tree | e932c54d5260b0e6fda2b46be2a6ba1c3ee30434 /db/schema/compliance.ts | |
| parent | d78378ecd7ceede1429359f8058c7a99ac34b1b7 (diff) | |
(대표님, 최겸) 설계메뉴추가, 작업사항 업데이트
설계메뉴 - 문서관리
설계메뉴 - 벤더 데이터
gtc 메뉴 업데이트
정보시스템 - 메뉴리스트 및 정보 업데이트
파일 라우트 업데이트
엑셀임포트 개선
기본계약 개선
벤더 가입과정 변경 및 개선
벤더 기본정보 - pq
돌체 오류 수정 및 개선
벤더 로그인 과정 이메일 오류 수정
Diffstat (limited to 'db/schema/compliance.ts')
| -rw-r--r-- | db/schema/compliance.ts | 173 |
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 |
