Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions apps/api/src/answer-evaluation/answer-evaluation.constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const AccuracyEval = {
PERFECT: 'PERFECT',
MINOR_ERROR: 'MINOR_ERROR',
WRONG: 'WRONG',
} as const;
type AccuracyEval = (typeof AccuracyEval)[keyof typeof AccuracyEval];

const LogicEval = {
CLEAR: 'CLEAR',
WEAK: 'WEAK',
NONE: 'NONE',
} as const;
type LogicEval = (typeof LogicEval)[keyof typeof LogicEval];

const DepthEval = {
DEEP: 'DEEP',
BASIC: 'BASIC',
NONE: 'NONE',
} as const;
type DepthEval = (typeof DepthEval)[keyof typeof DepthEval];

export { AccuracyEval, LogicEval, DepthEval };
56 changes: 56 additions & 0 deletions apps/api/src/answer-evaluation/answer-evaluation.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import {
Entity,
PrimaryGeneratedColumn,
Column,
CreateDateColumn,
OneToOne,
JoinColumn,
} from 'typeorm';
import {
AccuracyEval,
LogicEval,
DepthEval,
} from './answer-evaluation.constants';
import { AnswerSubmission } from 'src/answer-submission/answer-submission.entity';

@Entity('answer_evaluations')
class AnswerEvaluation {
@PrimaryGeneratedColumn()
id: number;

@Column({ name: 'submission_id', type: 'int' })
submissionId: number;

@Column({ name: 'feedback_message', type: 'text' })
feedbackMessage: string;

@Column({ name: 'detail_analysis', type: 'jsonb' })
detailAnalysis: any;

@Column({ name: 'score_details', type: 'jsonb' })
scoreDetails: any;

@Column({ name: 'accuracy_eval', type: 'enum', enum: AccuracyEval })
accuracyEval: AccuracyEval;

@Column({ name: 'logic_eval', type: 'enum', enum: LogicEval })
logicEval: LogicEval;

@Column({ name: 'depth_eval', type: 'enum', enum: DepthEval })
depthEval: DepthEval;

@Column({ name: 'has_application', type: 'boolean', default: false })
hasApplication: boolean;

@Column({ name: 'is_complete_sentence', type: 'boolean', default: false })
isCompleteSentence: boolean;

@CreateDateColumn({ name: 'created_at', type: 'timestamp' })
createdAt: Date;

@OneToOne(() => AnswerSubmission)
@JoinColumn({ name: 'submission_id' })
submission: AnswerSubmission;
}

export { AnswerEvaluation };
20 changes: 20 additions & 0 deletions apps/api/src/answer-submission/answer-submission.constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const QuizMode = {
DAILY: 'DAILY',
INTERVIEW: 'INTERVIEW',
} as const;
type QuizMode = (typeof QuizMode)[keyof typeof QuizMode];

const InputType = {
VOICE: 'VOICE',
TEXT: 'TEXT',
} as const;
type InputType = (typeof InputType)[keyof typeof InputType];

const ProcessStatus = {
PENDING: 'PENDING',
DONE: 'DONE',
FAILED: 'FAILED',
} as const;
type ProcessStatus = (typeof ProcessStatus)[keyof typeof ProcessStatus];

export { QuizMode, InputType, ProcessStatus };
75 changes: 75 additions & 0 deletions apps/api/src/answer-submission/answer-submission.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import {
Entity,
PrimaryGeneratedColumn,
Column,
CreateDateColumn,
ManyToOne,
JoinColumn,
OneToOne,
} from 'typeorm';
import {
QuizMode,
InputType,
ProcessStatus,
} from './answer-submission.constants';
import { Question } from 'src/question/question.entity';
import { AudioAsset } from 'src/audio-asset/audio-asset.entity';

@Entity('answer_submissions')
class AnswerSubmission {
@PrimaryGeneratedColumn()
id: number;

@Column({ name: 'quiz_mode', type: 'enum', enum: QuizMode })
quizMode: QuizMode;

@Column({ name: 'input_type', type: 'enum', enum: InputType })
inputType: InputType;

@Column({ name: 'raw_answer', type: 'text' })
rawAnswer: string;

@Column({ name: 'taken_time', type: 'int' })
takenTime: number;

@Column({ type: 'int', default: 0 })
score: number;

@CreateDateColumn({ name: 'submitted_at', type: 'timestamp' })
submittedAt: Date;

@Column({
name: 'stt_status',
type: 'enum',
enum: ProcessStatus,
default: ProcessStatus.PENDING,
})
sttStatus: ProcessStatus;

@Column({
name: 'evaluation_status',
type: 'enum',
enum: ProcessStatus,
default: ProcessStatus.PENDING,
})
evaluationStatus: ProcessStatus;

@Column({ name: 'user_id', type: 'int' })
userId: number;

@Column({ name: 'question_id', type: 'int' })
questionId: number;

@Column({ name: 'audio_asset_id', type: 'int' })
audioAssetId: number;

@ManyToOne(() => Question)
@JoinColumn({ name: 'question_id' })
question: Question;

@OneToOne(() => AudioAsset)
@JoinColumn({ name: 'audio_asset_id' })
audioAsset: AudioAsset;
}

export { AnswerSubmission };
27 changes: 27 additions & 0 deletions apps/api/src/audio-asset/audio-asset.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import {
Entity,
PrimaryGeneratedColumn,
Column,
CreateDateColumn,
} from 'typeorm';

@Entity('audio_assets')
class AudioAsset {
@PrimaryGeneratedColumn()
id: number;

@Column({ name: 'storage_url', type: 'text' })
storageUrl: string;

// BIGINT는 JS에서 범위 문제로 string으로 반환
@Column({ name: 'byte_size', type: 'bigint' })
byteSize: string;

@Column({ name: 'duration_ms', type: 'int' })
durationMs: number;

@CreateDateColumn({ name: 'created_at', type: 'timestamp' })
createdAt: Date;
}

export { AudioAsset };
18 changes: 18 additions & 0 deletions apps/api/src/category/category.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';

@Entity('categories')
class Category {
@PrimaryGeneratedColumn()
id: number;

@Column({ type: 'varchar', length: 255 })
name: string;

@Column({ name: 'parent_id', type: 'int', nullable: true })
parentId: number | null;

@Column({ type: 'int', default: 1 })
depth: number;
}

export { Category };
45 changes: 45 additions & 0 deletions apps/api/src/question-solution/question-solution.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Question } from 'src/question/question.entity';
import {
Entity,
PrimaryGeneratedColumn,
Column,
CreateDateColumn,
OneToOne,
JoinColumn,
} from 'typeorm';

@Entity('question_solutions')
class QuestionSolution {
@PrimaryGeneratedColumn()
id: number;

@Column({ name: 'question_id', type: 'int' })
questionId: number;

@Column({ name: 'reference_source', type: 'varchar', length: 255 })
referenceSource: string;

@Column({ name: 'standard_definition', type: 'text' })
standardDefinition: string;

@Column({ name: 'technical_mechanism', type: 'jsonb' })
technicalMechanism: any;

@Column({ name: 'key_terminology', type: 'jsonb' })
keyTerminology: any;

@Column({ name: 'practical_application', type: 'text' })
practicalApplication: string;

@Column({ name: 'common_misconceptions', type: 'text' })
commonMisconceptions: string;

@CreateDateColumn({ name: 'created_at', type: 'timestamp' })
createdAt: Date;

@OneToOne(() => Question)
@JoinColumn({ name: 'question_id' })
question: Question;
}

export { QuestionSolution };
38 changes: 38 additions & 0 deletions apps/api/src/question/question.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Category } from 'src/category/category.entity';
import {
Entity,
PrimaryGeneratedColumn,
Column,
JoinColumn,
OneToOne,
} from 'typeorm';

@Entity('questions')
class Question {
@PrimaryGeneratedColumn()
id: number;

@Column({ type: 'varchar', length: 255 })
title: string;

@Column({ type: 'text' })
content: string;

@Column({ name: 'tts_url', type: 'varchar', length: 255, nullable: true })
ttsUrl: string;

@Column({ name: 'avg_score', type: 'float', default: 0 })
avgScore: number;

@Column({ name: 'avg_importance', type: 'float', default: 0 })
avgImportance: number;

@Column({ name: 'category_id', type: 'int', nullable: true })
categoryId: number;

@OneToOne(() => Category)
@JoinColumn({ name: 'category_id' })
category: Category;
}

export { Question };
Loading