Files
sam-manage/app/Models/Admin/AdminApiFlowRun.php
hskwon ff943ab728 feat: API Flow Tester 기능 기반 구조 추가
- 모델: AdminApiFlow, AdminApiFlowRun
- 컨트롤러: FlowTesterController
- 뷰: index, create, edit, history, run-detail
- 사이드바 메뉴에 "개발 도구" 그룹 추가
- 라우트 설정
2025-11-27 19:02:18 +09:00

174 lines
4.2 KiB
PHP

<?php
namespace App\Models\Admin;
use App\Models\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
/**
* API Flow Tester - 실행 이력 모델
*
* @property int $id
* @property int $flow_id
* @property string $status
* @property \Carbon\Carbon|null $started_at
* @property \Carbon\Carbon|null $completed_at
* @property int|null $duration_ms
* @property int|null $total_steps
* @property int $completed_steps
* @property int|null $failed_step
* @property array|null $execution_log
* @property array|null $input_variables
* @property string|null $error_message
* @property int|null $executed_by
* @property \Carbon\Carbon $created_at
*/
class AdminApiFlowRun extends Model
{
// 상태 상수
public const STATUS_PENDING = 'PENDING';
public const STATUS_RUNNING = 'RUNNING';
public const STATUS_SUCCESS = 'SUCCESS';
public const STATUS_FAILED = 'FAILED';
public const STATUS_PARTIAL = 'PARTIAL';
protected $table = 'admin_api_flow_runs';
public $timestamps = false; // created_at만 사용
protected $fillable = [
'flow_id',
'status',
'started_at',
'completed_at',
'duration_ms',
'total_steps',
'completed_steps',
'failed_step',
'execution_log',
'input_variables',
'error_message',
'executed_by',
];
protected $casts = [
'flow_id' => 'integer',
'started_at' => 'datetime',
'completed_at' => 'datetime',
'duration_ms' => 'integer',
'total_steps' => 'integer',
'completed_steps' => 'integer',
'failed_step' => 'integer',
'execution_log' => 'array',
'input_variables' => 'array',
'executed_by' => 'integer',
];
/**
* 상태별 필터링
*/
public function scopeStatus($query, string $status)
{
return $query->where('status', $status);
}
/**
* 성공한 실행만 조회
*/
public function scopeSuccessful($query)
{
return $query->where('status', self::STATUS_SUCCESS);
}
/**
* 실패한 실행만 조회
*/
public function scopeFailed($query)
{
return $query->where('status', self::STATUS_FAILED);
}
/**
* 관계: 플로우
*/
public function flow(): BelongsTo
{
return $this->belongsTo(AdminApiFlow::class, 'flow_id');
}
/**
* 관계: 실행자
*/
public function executor(): BelongsTo
{
return $this->belongsTo(User::class, 'executed_by');
}
/**
* 실행 중인지 확인
*/
public function isRunning(): bool
{
return $this->status === self::STATUS_RUNNING;
}
/**
* 완료되었는지 확인 (성공/실패/부분 포함)
*/
public function isCompleted(): bool
{
return in_array($this->status, [
self::STATUS_SUCCESS,
self::STATUS_FAILED,
self::STATUS_PARTIAL,
]);
}
/**
* 진행률 반환 (0-100)
*/
public function getProgressAttribute(): int
{
if (! $this->total_steps || $this->total_steps === 0) {
return 0;
}
return (int) round(($this->completed_steps / $this->total_steps) * 100);
}
/**
* 상태 라벨 반환 (한글)
*/
public function getStatusLabelAttribute(): string
{
return match ($this->status) {
self::STATUS_PENDING => '대기 중',
self::STATUS_RUNNING => '실행 중',
self::STATUS_SUCCESS => '성공',
self::STATUS_FAILED => '실패',
self::STATUS_PARTIAL => '부분 성공',
default => $this->status,
};
}
/**
* 상태 색상 반환 (Tailwind CSS class)
*/
public function getStatusColorAttribute(): string
{
return match ($this->status) {
self::STATUS_PENDING => 'badge-ghost',
self::STATUS_RUNNING => 'badge-info',
self::STATUS_SUCCESS => 'badge-success',
self::STATUS_FAILED => 'badge-error',
self::STATUS_PARTIAL => 'badge-warning',
default => 'badge-ghost',
};
}
}