Files
sam-api/database/seeders/BpMesTenantStatFieldsSeeder.php
hskwon 342d15196e refactor: BP-MES Phase 1 하이브리드 구조 전환
- products 테이블: 6개 고정 필드 + attributes JSON
- product_components 테이블: 수식/조건 + attributes JSON
- tenant_stat_fields 테이블: 테넌트별 통계 필드 설정
- stat_snapshots 테이블: 통계 캐싱
- BP-MES CategoryFields Seeder: 제품/부품/절곡품 카테고리 필드
- BP-MES TenantStatFields Seeder: 통계 필드 설정

[변경 사항]
삭제:
- 2025_11_13_120000_extend_products_table_for_bp_mes.php
- 2025_11_13_120001_extend_product_components_table_for_bp_mes.php

추가:
- 2025_11_14_000001_add_hybrid_fields_to_products_table.php
- 2025_11_14_000002_add_attributes_to_product_components_table.php
- 2025_11_14_000003_create_tenant_stat_fields_table.php
- 2025_11_14_000004_create_stat_snapshots_table.php
- BpMesCategoryFieldsSeeder.php
- BpMesTenantStatFieldsSeeder.php

[배경]
멀티테넌트 시스템의 유연성 확보를 위해 고정 필드를 최소화하고
동적 필드 시스템(category_fields + attributes JSON)으로 전환.
통계 성능을 위해 자주 조회하는 분류 필드(product_category, part_type)는
고정 컬럼으로 유지하고 인덱싱.
2025-11-14 10:57:02 +09:00

175 lines
6.3 KiB
PHP

<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
/**
* BP-MES 테넌트 통계 필드 설정 시더
*
* 목적: BP-MES 테넌트가 통계를 내고 싶은 필드를 tenant_stat_fields 테이블에 선언
*
* 효과:
* - 일일 스케줄러가 이 필드들의 통계를 계산하여 stat_snapshots에 저장
* - 대시보드 및 통계 화면에서 빠른 조회 가능
* - 잠재적으로 MySQL Virtual Column 최적화 대상 식별
*
* 실행: php artisan db:seed --class=BpMesTenantStatFieldsSeeder
*
* @see /claudedocs/mes/ITEM_MANAGEMENT_MIGRATION_GUIDE.md
*/
class BpMesTenantStatFieldsSeeder extends Seeder
{
/**
* BP-MES 테넌트 ID (실제 환경에 맞게 수정 필요)
*/
private const TENANT_ID = 1;
public function run(): void
{
// 1. products 테이블의 통계 필드 정의
$productStatFields = [
// 마진율 통계 (중요 지표)
[
'target_table' => 'products',
'field_key' => 'margin_rate',
'field_name' => '마진율(%)',
'field_type' => 'decimal',
'aggregation_types' => ['avg', 'min', 'max'],
'is_critical' => true,
'display_order' => 1,
'description' => '제품별 마진율 통계 (평균, 최소, 최대)',
],
// 가공비 통계
[
'target_table' => 'products',
'field_key' => 'processing_cost',
'field_name' => '가공비(원)',
'field_type' => 'decimal',
'aggregation_types' => ['avg', 'sum', 'min', 'max'],
'is_critical' => true,
'display_order' => 2,
'description' => '가공비 통계 (평균, 합계, 최소, 최대)',
],
// 인건비 통계
[
'target_table' => 'products',
'field_key' => 'labor_cost',
'field_name' => '인건비(원)',
'field_type' => 'decimal',
'aggregation_types' => ['avg', 'sum', 'min', 'max'],
'is_critical' => true,
'display_order' => 3,
'description' => '인건비 통계 (평균, 합계, 최소, 최대)',
],
// 설치비 통계
[
'target_table' => 'products',
'field_key' => 'install_cost',
'field_name' => '설치비(원)',
'field_type' => 'decimal',
'aggregation_types' => ['avg', 'sum', 'min', 'max'],
'is_critical' => true,
'display_order' => 4,
'description' => '설치비 통계 (평균, 합계, 최소, 최대)',
],
// 절곡 길이 통계 (선택적)
[
'target_table' => 'products',
'field_key' => 'bending_length',
'field_name' => '절곡길이(mm)',
'field_type' => 'decimal',
'aggregation_types' => ['avg', 'min', 'max'],
'is_critical' => false,
'display_order' => 10,
'description' => '절곡품 길이 통계 (선택적 집계)',
],
// 조립 길이 통계 (선택적)
[
'target_table' => 'products',
'field_key' => 'assembly_length',
'field_name' => '조립길이(mm)',
'field_type' => 'decimal',
'aggregation_types' => ['avg', 'min', 'max'],
'is_critical' => false,
'display_order' => 11,
'description' => '부품 조립 길이 통계 (선택적 집계)',
],
// 측면 규격 통계 (선택적)
[
'target_table' => 'products',
'field_key' => 'side_spec_width',
'field_name' => '측면규격_폭(mm)',
'field_type' => 'decimal',
'aggregation_types' => ['avg', 'min', 'max'],
'is_critical' => false,
'display_order' => 12,
'description' => '측면 규격 폭 통계 (선택적 집계)',
],
[
'target_table' => 'products',
'field_key' => 'side_spec_height',
'field_name' => '측면규격_높이(mm)',
'field_type' => 'decimal',
'aggregation_types' => ['avg', 'min', 'max'],
'is_critical' => false,
'display_order' => 13,
'description' => '측면 규격 높이 통계 (선택적 집계)',
],
];
// 2. materials 테이블의 통계 필드 정의 (향후 확장용 예시)
$materialStatFields = [
// 예시: 자재 단가 통계
[
'target_table' => 'materials',
'field_key' => 'unit_price',
'field_name' => '단가(원)',
'field_type' => 'decimal',
'aggregation_types' => ['avg', 'min', 'max'],
'is_critical' => false,
'display_order' => 1,
'description' => '자재 단가 통계 (향후 활용)',
],
];
// 3. products 통계 필드 생성
foreach ($productStatFields as $field) {
$this->insertTenantStatField($field);
}
// 4. materials 통계 필드 생성 (향후 확장)
foreach ($materialStatFields as $field) {
$this->insertTenantStatField($field);
}
}
/**
* tenant_stat_fields 테이블에 필드 삽입
*/
private function insertTenantStatField(array $field): void
{
DB::table('tenant_stat_fields')->insert([
'tenant_id' => self::TENANT_ID,
'target_table' => $field['target_table'],
'field_key' => $field['field_key'],
'field_name' => $field['field_name'],
'field_type' => $field['field_type'],
'aggregation_types' => json_encode($field['aggregation_types']),
'is_critical' => $field['is_critical'],
'display_order' => $field['display_order'],
'description' => $field['description'],
'created_at' => now(),
'updated_at' => now(),
]);
}
}