From 6c186c91ab135b8d8a753cdff3a0df87ee60e319 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=B3=B4=EA=B3=A4?= Date: Tue, 10 Feb 2026 09:50:14 +0900 Subject: [PATCH] =?UTF-8?q?feat:=ED=9A=8C=EC=9D=98=EB=A1=9D=20=ED=85=8C?= =?UTF-8?q?=EC=9D=B4=EB=B8=94=20=EB=A7=88=EC=9D=B4=EA=B7=B8=EB=A0=88?= =?UTF-8?q?=EC=9D=B4=EC=85=98=20=EC=B6=94=EA=B0=80=20(meeting=5Fminutes,?= =?UTF-8?q?=20meeting=5Fminute=5Fsegments)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.6 --- ...10_100000_create_meeting_minutes_table.php | 51 +++++++++++++++++++ ...1_create_meeting_minute_segments_table.php | 39 ++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 database/migrations/2026_02_10_100000_create_meeting_minutes_table.php create mode 100644 database/migrations/2026_02_10_100001_create_meeting_minute_segments_table.php diff --git a/database/migrations/2026_02_10_100000_create_meeting_minutes_table.php b/database/migrations/2026_02_10_100000_create_meeting_minutes_table.php new file mode 100644 index 0000000..91c74aa --- /dev/null +++ b/database/migrations/2026_02_10_100000_create_meeting_minutes_table.php @@ -0,0 +1,51 @@ +id()->comment('ID'); + $table->unsignedBigInteger('tenant_id')->comment('테넌트 ID'); + $table->unsignedBigInteger('user_id')->comment('작성자 ID'); + + $table->string('title', 300)->default('무제 회의록')->comment('회의 제목'); + $table->string('folder', 100)->nullable()->comment('폴더 분류'); + $table->json('participants')->nullable()->comment('참여자 목록'); + + $table->date('meeting_date')->comment('회의 날짜'); + $table->time('meeting_time')->nullable()->comment('회의 시작 시간'); + $table->unsignedInteger('duration_seconds')->default(0)->comment('녹음 총 시간(초)'); + + $table->string('audio_file_path', 500)->nullable()->comment('오디오 GCS 경로'); + $table->string('audio_gcs_uri', 500)->nullable()->comment('오디오 GCS URI'); + $table->unsignedBigInteger('audio_file_size')->nullable()->comment('오디오 파일 크기(bytes)'); + + $table->longText('full_transcript')->nullable()->comment('전체 트랜스크립트'); + + $table->longText('summary')->nullable()->comment('AI 요약'); + $table->json('decisions')->nullable()->comment('결정사항 목록'); + $table->json('action_items')->nullable()->comment('액션아이템 목록'); + + $table->string('status', 20)->default('DRAFT')->comment('상태 (DRAFT/RECORDING/PROCESSING/COMPLETED/FAILED)'); + $table->string('stt_language', 10)->default('ko-KR')->comment('STT 언어'); + + $table->timestamps(); + $table->softDeletes(); + + $table->index('tenant_id', 'idx_mm_tenant'); + $table->index('user_id', 'idx_mm_user'); + $table->index(['tenant_id', 'meeting_date'], 'idx_mm_tenant_date'); + $table->index('status', 'idx_mm_status'); + }); + } + + public function down(): void + { + Schema::dropIfExists('meeting_minutes'); + } +}; diff --git a/database/migrations/2026_02_10_100001_create_meeting_minute_segments_table.php b/database/migrations/2026_02_10_100001_create_meeting_minute_segments_table.php new file mode 100644 index 0000000..328f6e3 --- /dev/null +++ b/database/migrations/2026_02_10_100001_create_meeting_minute_segments_table.php @@ -0,0 +1,39 @@ +id()->comment('ID'); + $table->unsignedBigInteger('meeting_minute_id')->comment('회의록 ID'); + $table->unsignedInteger('segment_order')->comment('세그먼트 순서'); + + $table->string('speaker_name', 100)->default('화자 1')->comment('화자 이름'); + $table->string('speaker_label', 20)->nullable()->comment('화자 라벨'); + $table->text('text')->comment('발화 텍스트'); + + $table->unsignedInteger('start_time_ms')->default(0)->comment('시작 시간(ms)'); + $table->unsignedInteger('end_time_ms')->nullable()->comment('종료 시간(ms)'); + $table->boolean('is_manual_speaker')->default(true)->comment('수동 화자 전환 여부'); + + $table->timestamps(); + + $table->index('meeting_minute_id', 'idx_mms_meeting'); + $table->index(['meeting_minute_id', 'segment_order'], 'idx_mms_meeting_order'); + + $table->foreign('meeting_minute_id', 'fk_mms_meeting') + ->references('id')->on('meeting_minutes') + ->onDelete('cascade'); + }); + } + + public function down(): void + { + Schema::dropIfExists('meeting_minute_segments'); + } +};