feat: sam_stat 통계 DB 인프라 구축 (Phase 1)

- sam_stat DB 연결 설정 (config/database.php, .env)
- 메타 테이블 마이그레이션 (stat_definitions, stat_job_logs)
- dim_date 차원 테이블 + DimDateSeeder (2020~2030, 4018건)
- 기반 모델: BaseStatModel, StatDefinition, StatJobLog, DimDate
- 집계 커맨드: stat:aggregate-daily, stat:aggregate-monthly
- StatAggregatorService + StatDomainServiceInterface 골격

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-29 17:13:36 +09:00
parent 4f2a329e4e
commit c88048db67
13 changed files with 628 additions and 0 deletions

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
protected $connection = 'sam_stat';
public function up(): void
{
Schema::connection($this->connection)->create('stat_definitions', function (Blueprint $table) {
$table->id();
$table->string('code', 100)->unique()->comment('통계 코드 (sales_daily_revenue)');
$table->string('domain', 50)->index()->comment('도메인 (sales, finance, production)');
$table->string('name', 200)->comment('통계명 (일일 매출액)');
$table->text('description')->nullable();
$table->json('source_tables')->comment('원본 테이블 목록');
$table->string('aggregation', 20)->default('daily')->index()->comment('집계 주기');
$table->text('query_template')->nullable()->comment('집계 SQL 템플릿');
$table->boolean('is_active')->default(true)->index();
$table->json('config')->nullable()->comment('추가 설정 (임계값, 단위 등)');
$table->timestamps();
});
}
public function down(): void
{
Schema::connection($this->connection)->dropIfExists('stat_definitions');
}
};

View File

@@ -0,0 +1,36 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
protected $connection = 'sam_stat';
public function up(): void
{
Schema::connection($this->connection)->create('stat_job_logs', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('tenant_id')->comment('테넌트 ID');
$table->string('job_type', 100)->comment('작업 유형 (sales_daily, finance_monthly)');
$table->date('target_date')->comment('집계 대상 날짜');
$table->enum('status', ['pending', 'running', 'completed', 'failed'])->default('pending');
$table->unsignedInteger('records_processed')->default(0);
$table->text('error_message')->nullable();
$table->timestamp('started_at')->nullable();
$table->timestamp('completed_at')->nullable();
$table->unsignedInteger('duration_ms')->nullable();
$table->timestamp('created_at')->nullable();
$table->index(['tenant_id', 'job_type']);
$table->index('status');
$table->index('target_date');
});
}
public function down(): void
{
Schema::connection($this->connection)->dropIfExists('stat_job_logs');
}
};

View File

@@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
protected $connection = 'sam_stat';
public function up(): void
{
Schema::connection($this->connection)->create('dim_date', function (Blueprint $table) {
$table->date('date_key')->primary()->comment('날짜 키');
$table->smallInteger('year')->comment('연도');
$table->tinyInteger('quarter')->comment('분기 (1~4)');
$table->tinyInteger('month')->comment('월');
$table->tinyInteger('week')->comment('ISO 주차');
$table->tinyInteger('day_of_week')->comment('요일 (1:월~7:일)');
$table->tinyInteger('day_of_month')->comment('일');
$table->boolean('is_weekend')->comment('주말 여부');
$table->boolean('is_holiday')->default(false)->comment('공휴일 여부');
$table->string('holiday_name', 100)->nullable()->comment('공휴일명');
$table->smallInteger('fiscal_year')->nullable()->comment('회계연도');
$table->tinyInteger('fiscal_quarter')->nullable()->comment('회계분기');
});
}
public function down(): void
{
Schema::connection($this->connection)->dropIfExists('dim_date');
}
};