feat: [tenant] 데모 테넌트 지원 추가 (Phase 1)
- tenants.tenant_type ENUM 확장: DEMO_SHOWCASE, DEMO_PARTNER, DEMO_TRIAL - demo_expires_at, demo_source_partner_id 컬럼 추가 - Tenant 모델에 데모 관련 메서드 추가 (isDemoTenant, isDemoShowcase 등) - getOption/setOption 헬퍼 메서드 추가 - 데모→정식 전환 convertToProduction() 메서드
This commit is contained in:
@@ -18,6 +18,32 @@ class Tenant extends Model
|
||||
{
|
||||
use ModelTrait, SoftDeletes;
|
||||
|
||||
// 데모 테넌트 유형 상수
|
||||
const TYPE_STD = 'STD';
|
||||
|
||||
const TYPE_TPL = 'TPL';
|
||||
|
||||
const TYPE_HQ = 'HQ';
|
||||
|
||||
const TYPE_DEMO_SHOWCASE = 'DEMO_SHOWCASE';
|
||||
|
||||
const TYPE_DEMO_PARTNER = 'DEMO_PARTNER';
|
||||
|
||||
const TYPE_DEMO_TRIAL = 'DEMO_TRIAL';
|
||||
|
||||
const DEMO_TYPES = [
|
||||
self::TYPE_DEMO_SHOWCASE,
|
||||
self::TYPE_DEMO_PARTNER,
|
||||
self::TYPE_DEMO_TRIAL,
|
||||
];
|
||||
|
||||
// 데모 options 키 상수
|
||||
const OPTION_DEMO_PRESET = 'demo_preset';
|
||||
|
||||
const OPTION_DEMO_LIMITS = 'demo_limits';
|
||||
|
||||
const OPTION_DEMO_READ_ONLY = 'demo_read_only';
|
||||
|
||||
protected $fillable = [
|
||||
'company_name',
|
||||
'code',
|
||||
@@ -34,6 +60,9 @@ class Tenant extends Model
|
||||
'options',
|
||||
'tenant_st_code',
|
||||
'billing_tp_code',
|
||||
'tenant_type',
|
||||
'demo_expires_at',
|
||||
'demo_source_partner_id',
|
||||
];
|
||||
|
||||
protected $guarded = [
|
||||
@@ -47,6 +76,7 @@ class Tenant extends Model
|
||||
|
||||
protected $casts = [
|
||||
'trial_ends_at' => 'datetime',
|
||||
'demo_expires_at' => 'datetime',
|
||||
'expires_at' => 'datetime',
|
||||
'last_paid_at' => 'datetime',
|
||||
'max_users' => 'integer',
|
||||
@@ -244,4 +274,132 @@ private function formatBytes(int $bytes): string
|
||||
|
||||
return round($bytes, 2).' '.$units[$pow];
|
||||
}
|
||||
|
||||
// ─── options 헬퍼 메서드 ───
|
||||
|
||||
public function getOption(string $key, mixed $default = null): mixed
|
||||
{
|
||||
return data_get($this->options, $key, $default);
|
||||
}
|
||||
|
||||
public function setOption(string $key, mixed $value): self
|
||||
{
|
||||
$options = $this->options ?? [];
|
||||
data_set($options, $key, $value);
|
||||
$this->options = $options;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
// ─── 데모 테넌트 관련 메서드 ───
|
||||
|
||||
/**
|
||||
* 데모 테넌트인지 확인 (모든 데모 유형)
|
||||
*/
|
||||
public function isDemoTenant(): bool
|
||||
{
|
||||
return in_array($this->tenant_type, self::DEMO_TYPES);
|
||||
}
|
||||
|
||||
/**
|
||||
* 데모 쇼케이스(공용 읽기전용)인지 확인
|
||||
*/
|
||||
public function isDemoShowcase(): bool
|
||||
{
|
||||
return $this->tenant_type === self::TYPE_DEMO_SHOWCASE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 파트너 데모인지 확인
|
||||
*/
|
||||
public function isDemoPartner(): bool
|
||||
{
|
||||
return $this->tenant_type === self::TYPE_DEMO_PARTNER;
|
||||
}
|
||||
|
||||
/**
|
||||
* 고객 체험 데모인지 확인
|
||||
*/
|
||||
public function isDemoTrial(): bool
|
||||
{
|
||||
return $this->tenant_type === self::TYPE_DEMO_TRIAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 데모 만료 여부 확인
|
||||
*/
|
||||
public function isDemoExpired(): bool
|
||||
{
|
||||
if (! $this->isDemoTenant()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 쇼케이스는 만료 없음
|
||||
if ($this->isDemoShowcase()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->demo_expires_at && now()->gt($this->demo_expires_at);
|
||||
}
|
||||
|
||||
/**
|
||||
* 데모 읽기전용인지 확인
|
||||
*/
|
||||
public function isDemoReadOnly(): bool
|
||||
{
|
||||
return $this->isDemoShowcase()
|
||||
|| $this->getOption(self::OPTION_DEMO_READ_ONLY, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 데모 테넌트만 조회하는 스코프
|
||||
*/
|
||||
public function scopeDemo($query)
|
||||
{
|
||||
return $query->whereIn('tenant_type', self::DEMO_TYPES);
|
||||
}
|
||||
|
||||
/**
|
||||
* 데모 프리셋 조회
|
||||
*/
|
||||
public function getDemoPreset(): ?string
|
||||
{
|
||||
return $this->getOption(self::OPTION_DEMO_PRESET);
|
||||
}
|
||||
|
||||
/**
|
||||
* 데모 수량 제한 조회
|
||||
*/
|
||||
public function getDemoLimits(): array
|
||||
{
|
||||
return $this->getOption(self::OPTION_DEMO_LIMITS, [
|
||||
'max_items' => 100,
|
||||
'max_orders' => 50,
|
||||
'max_productions' => 30,
|
||||
'max_users' => 5,
|
||||
'max_storage_gb' => 1,
|
||||
'max_ai_tokens' => 100000,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 데모 → 정식 테넌트로 전환
|
||||
*/
|
||||
public function convertToProduction(): void
|
||||
{
|
||||
$this->update([
|
||||
'tenant_type' => self::TYPE_STD,
|
||||
'demo_expires_at' => null,
|
||||
'demo_source_partner_id' => null,
|
||||
]);
|
||||
|
||||
// options에서 데모 관련 키 제거
|
||||
$options = $this->options ?? [];
|
||||
unset(
|
||||
$options[self::OPTION_DEMO_PRESET],
|
||||
$options[self::OPTION_DEMO_LIMITS],
|
||||
$options[self::OPTION_DEMO_READ_ONLY]
|
||||
);
|
||||
$this->update(['options' => $options ?: null]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user