diff --git a/LOGICAL_RELATIONSHIPS.md b/LOGICAL_RELATIONSHIPS.md index 575494d..12cf164 100644 --- a/LOGICAL_RELATIONSHIPS.md +++ b/LOGICAL_RELATIONSHIPS.md @@ -1,6 +1,6 @@ # 논리적 데이터베이스 관계 문서 -> **자동 생성**: 2026-01-26 22:07:37 +> **자동 생성**: 2026-01-29 00:51:16 > **소스**: Eloquent 모델 관계 분석 ## 📊 모델별 관계 현황 @@ -194,6 +194,35 @@ ### model_versions - **model()**: belongsTo → `models` - **bomTemplates()**: hasMany → `bom_templates` +### documents +**모델**: `App\Models\Documents\Document` + +- **creator()**: belongsTo → `users` +- **updater()**: belongsTo → `users` +- **approvals()**: hasMany → `document_approvals` +- **data()**: hasMany → `document_data` +- **attachments()**: hasMany → `document_attachments` +- **linkable()**: morphTo → `(Polymorphic)` + +### document_approvals +**모델**: `App\Models\Documents\DocumentApproval` + +- **document()**: belongsTo → `documents` +- **user()**: belongsTo → `users` +- **creator()**: belongsTo → `users` + +### document_attachments +**모델**: `App\Models\Documents\DocumentAttachment` + +- **document()**: belongsTo → `documents` +- **file()**: belongsTo → `files` +- **creator()**: belongsTo → `users` + +### document_datas +**모델**: `App\Models\Documents\DocumentData` + +- **document()**: belongsTo → `documents` + ### estimates **모델**: `App\Models\Estimate\Estimate` diff --git a/database/migrations/2026_01_27_152523_create_global_categories_table.php b/database/migrations/2026_01_27_152523_create_global_categories_table.php new file mode 100644 index 0000000..28baa8f --- /dev/null +++ b/database/migrations/2026_01_27_152523_create_global_categories_table.php @@ -0,0 +1,118 @@ +id()->comment('글로벌 카테고리 PK'); + $table->unsignedBigInteger('parent_id')->nullable()->comment('상위 카테고리ID(NULL=최상위)'); + $table->string('code_group', 30)->comment('코드 그룹'); + $table->string('profile_code', 30)->nullable()->comment('역할 프로필 코드'); + $table->string('code', 30)->comment('카테고리 코드(영문, 고유)'); + $table->string('name', 100)->comment('카테고리명'); + $table->boolean('is_active')->default(true)->comment('활성여부'); + $table->integer('sort_order')->default(1)->comment('정렬순서'); + $table->string('description', 255)->nullable()->comment('비고'); + $table->unsignedBigInteger('created_by')->nullable()->comment('등록자'); + $table->unsignedBigInteger('updated_by')->nullable()->comment('수정자'); + $table->unsignedBigInteger('deleted_by')->nullable()->comment('삭제자'); + $table->timestamps(); + $table->softDeletes(); + + // 인덱스 + $table->unique(['code_group', 'code'], 'uq_global_codegroup_code'); + $table->index('parent_id', 'idx_global_parent_id'); + $table->index('code_group', 'idx_global_code_group'); + + // 자기 참조 FK + $table->foreign('parent_id', 'fk_global_category_parent') + ->references('id') + ->on('global_categories') + ->onDelete('set null'); + }); + + // tenant 1의 카테고리를 글로벌 카테고리로 복사 + $this->seedFromTenant1(); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('global_categories'); + } + + /** + * tenant 1의 카테고리를 글로벌로 복사 + */ + private function seedFromTenant1(): void + { + $categories = \DB::table('categories') + ->where('tenant_id', 1) + ->whereNull('deleted_at') + ->orderBy('parent_id') + ->orderBy('sort_order') + ->get(); + + if ($categories->isEmpty()) { + return; + } + + $idMap = []; // old_id => new_id + + // 1단계: parent_id가 NULL인 루트 카테고리 + foreach ($categories->where('parent_id', null) as $cat) { + $newId = \DB::table('global_categories')->insertGetId([ + 'parent_id' => null, + 'code_group' => $cat->code_group, + 'profile_code' => $cat->profile_code, + 'code' => $cat->code, + 'name' => $cat->name, + 'is_active' => $cat->is_active, + 'sort_order' => $cat->sort_order, + 'description' => $cat->description, + 'created_at' => now(), + 'updated_at' => now(), + ]); + $idMap[$cat->id] = $newId; + } + + // 2단계: 자식 카테고리 (재귀적으로 처리) + $remaining = $categories->whereNotNull('parent_id'); + $maxIterations = 10; + $iteration = 0; + + while ($remaining->isNotEmpty() && $iteration < $maxIterations) { + $processed = []; + foreach ($remaining as $cat) { + if (isset($idMap[$cat->parent_id])) { + $newId = \DB::table('global_categories')->insertGetId([ + 'parent_id' => $idMap[$cat->parent_id], + 'code_group' => $cat->code_group, + 'profile_code' => $cat->profile_code, + 'code' => $cat->code, + 'name' => $cat->name, + 'is_active' => $cat->is_active, + 'sort_order' => $cat->sort_order, + 'description' => $cat->description, + 'created_at' => now(), + 'updated_at' => now(), + ]); + $idMap[$cat->id] = $newId; + $processed[] = $cat->id; + } + } + $remaining = $remaining->whereNotIn('id', $processed); + $iteration++; + } + } +};