From b9137c93b0fc658180d191a780a7fe10371ef087 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=B3=B4=EA=B3=A4?= Date: Sat, 7 Feb 2026 12:52:28 +0900 Subject: [PATCH] =?UTF-8?q?feat:AI=20=EC=9D=8C=EC=84=B1=EB=85=B9=EC=9D=8C?= =?UTF-8?q?=20=ED=85=8C=EC=9D=B4=EB=B8=94=20=EB=A7=88=EC=9D=B4=EA=B7=B8?= =?UTF-8?q?=EB=A0=88=EC=9D=B4=EC=85=98=20=EB=B0=8F=20=EB=AA=A8=EB=8D=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ai_voice_recordings 테이블 마이그레이션 생성 - AiVoiceRecording 모델 추가 (Tenants 네임스페이스) Co-Authored-By: Claude Opus 4.6 --- LOGICAL_RELATIONSHIPS.md | 27 +++-------- app/Models/Tenants/AiVoiceRecording.php | 46 +++++++++++++++++++ ...00000_create_ai_voice_recordings_table.php | 37 +++++++++++++++ 3 files changed, 89 insertions(+), 21 deletions(-) create mode 100644 app/Models/Tenants/AiVoiceRecording.php create mode 100644 database/migrations/2026_02_07_200000_create_ai_voice_recordings_table.php diff --git a/LOGICAL_RELATIONSHIPS.md b/LOGICAL_RELATIONSHIPS.md index 31a48df..a81b37c 100644 --- a/LOGICAL_RELATIONSHIPS.md +++ b/LOGICAL_RELATIONSHIPS.md @@ -1,6 +1,6 @@ # 논리적 데이터베이스 관계 문서 -> **자동 생성**: 2026-02-07 01:10:55 +> **자동 생성**: 2026-02-07 09:56:46 > **소스**: Eloquent 모델 관계 분석 ## 📊 모델별 관계 현황 @@ -499,8 +499,6 @@ ### orders - **item()**: belongsTo → `items` - **sale()**: belongsTo → `sales` - **items()**: hasMany → `order_items` -- **nodes()**: hasMany → `order_nodes` -- **rootNodes()**: hasMany → `order_nodes` - **histories()**: hasMany → `order_histories` - **versions()**: hasMany → `order_versions` - **workOrders()**: hasMany → `work_orders` @@ -516,7 +514,6 @@ ### order_items **모델**: `App\Models\Orders\OrderItem` - **order()**: belongsTo → `orders` -- **node()**: belongsTo → `order_nodes` - **item()**: belongsTo → `items` - **quote()**: belongsTo → `quotes` - **quoteItem()**: belongsTo → `quote_items` @@ -527,14 +524,6 @@ ### order_item_components - **orderItem()**: belongsTo → `order_items` -### order_nodes -**모델**: `App\Models\Orders\OrderNode` - -- **parent()**: belongsTo → `order_nodes` -- **order()**: belongsTo → `orders` -- **children()**: hasMany → `order_nodes` -- **items()**: hasMany → `order_items` - ### order_versions **모델**: `App\Models\Orders\OrderVersion` @@ -608,7 +597,6 @@ ### work_orders - **primaryAssignee()**: hasMany → `work_order_assignees` - **items()**: hasMany → `work_order_items` - **issues()**: hasMany → `work_order_issues` -- **stepProgress()**: hasMany → `work_order_step_progress` - **shipments()**: hasMany → `shipments` - **bendingDetail()**: hasOne → `work_order_bending_details` @@ -636,14 +624,6 @@ ### work_order_items - **workOrder()**: belongsTo → `work_orders` - **item()**: belongsTo → `items` -### work_order_step_progress -**모델**: `App\Models\Production\WorkOrderStepProgress` - -- **workOrder()**: belongsTo → `work_orders` -- **processStep()**: belongsTo → `process_steps` -- **workOrderItem()**: belongsTo → `work_order_items` -- **completedByUser()**: belongsTo → `users` - ### work_results **모델**: `App\Models\Production\WorkResult` @@ -777,6 +757,11 @@ ### ai_reports - **creator()**: belongsTo → `users` +### ai_token_usages +**모델**: `App\Models\Tenants\AiTokenUsage` + +- **creator()**: belongsTo → `users` + ### approvals **모델**: `App\Models\Tenants\Approval` diff --git a/app/Models/Tenants/AiVoiceRecording.php b/app/Models/Tenants/AiVoiceRecording.php new file mode 100644 index 0000000..f2e385c --- /dev/null +++ b/app/Models/Tenants/AiVoiceRecording.php @@ -0,0 +1,46 @@ + 'integer', + 'file_expiry_date' => 'datetime', + ]; + + public const STATUS_PENDING = 'PENDING'; + + public const STATUS_PROCESSING = 'PROCESSING'; + + public const STATUS_COMPLETED = 'COMPLETED'; + + public const STATUS_FAILED = 'FAILED'; + + public function user(): BelongsTo + { + return $this->belongsTo(\App\Models\Members\User::class); + } +} diff --git a/database/migrations/2026_02_07_200000_create_ai_voice_recordings_table.php b/database/migrations/2026_02_07_200000_create_ai_voice_recordings_table.php new file mode 100644 index 0000000..9e9075c --- /dev/null +++ b/database/migrations/2026_02_07_200000_create_ai_voice_recordings_table.php @@ -0,0 +1,37 @@ +id(); + $table->unsignedBigInteger('tenant_id')->comment('테넌트 ID'); + $table->unsignedBigInteger('user_id')->comment('작성자 ID'); + $table->string('title', 200)->comment('녹음 제목'); + $table->unsignedBigInteger('interview_template_id')->nullable()->comment('연결된 인터뷰 템플릿 ID'); + $table->string('audio_file_path', 500)->nullable()->comment('GCS 오브젝트 경로'); + $table->string('audio_gcs_uri', 500)->nullable()->comment('GCS URI (gs://...)'); + $table->longText('transcript_text')->nullable()->comment('STT 변환 텍스트'); + $table->longText('analysis_text')->nullable()->comment('Gemini AI 분석 결과'); + $table->string('status', 20)->default('PENDING')->comment('상태: PENDING, PROCESSING, COMPLETED, FAILED'); + $table->unsignedInteger('duration_seconds')->nullable()->comment('녹음 시간(초)'); + $table->timestamp('file_expiry_date')->nullable()->comment('파일 삭제 예정일'); + $table->timestamps(); + $table->softDeletes(); + + $table->index('tenant_id'); + $table->index('user_id'); + $table->index('status'); + }); + } + + public function down(): void + { + Schema::dropIfExists('ai_voice_recordings'); + } +};