feat: [demo] 데모 테넌트 운영 자동화 (Phase 2)
- DemoLimitMiddleware: 쇼케이스 읽기전용, 만료 체크, 외부연동 차단 - DemoTenantService: 파트너/체험 테넌트 생성, 기간 연장, 정식 전환 - ResetDemoShowcaseCommand: 매일 자정 데이터 리셋 + 샘플 재시드 - ManufacturingPresetSeeder: 부서/거래처/품목/견적/수주 샘플 데이터 - 스케줄러 등록 (00:00 demo:reset-showcase --seed) - 미들웨어 별칭 등록 (demo.limit)
This commit is contained in:
167
app/Services/Demo/DemoTenantService.php
Normal file
167
app/Services/Demo/DemoTenantService.php
Normal file
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Demo;
|
||||
|
||||
use App\Models\Tenants\Tenant;
|
||||
use App\Services\Service;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* 데모 테넌트 생성/관리 서비스
|
||||
*
|
||||
* 기존 코드 영향 없음: 데모 전용 로직만 포함
|
||||
*
|
||||
* @see docs/features/sales/demo-tenant-policy.md
|
||||
*/
|
||||
class DemoTenantService extends Service
|
||||
{
|
||||
/**
|
||||
* 기본 데모 수량 제한
|
||||
*/
|
||||
private const DEFAULT_DEMO_LIMITS = [
|
||||
'max_items' => 100,
|
||||
'max_orders' => 50,
|
||||
'max_productions' => 30,
|
||||
'max_users' => 5,
|
||||
'max_storage_gb' => 1,
|
||||
'max_ai_tokens' => 100000,
|
||||
];
|
||||
|
||||
/**
|
||||
* 사용 가능한 프리셋 목록
|
||||
*/
|
||||
private const AVAILABLE_PRESETS = [
|
||||
'manufacturing', // 제조업 기본
|
||||
// 향후 추가 예정:
|
||||
// 'blinds', // 블라인드/스크린
|
||||
// 'construction', // 시공/건설
|
||||
// 'distribution', // 유통/도소매
|
||||
];
|
||||
|
||||
/**
|
||||
* 파트너 데모 테넌트 생성 (Tier 2)
|
||||
* 파트너 승인 시 호출
|
||||
*/
|
||||
public function createPartnerDemo(int $partnerId, string $preset = 'manufacturing'): Tenant
|
||||
{
|
||||
$tenant = new Tenant;
|
||||
$tenant->forceFill([
|
||||
'company_name' => '파트너데모_'.$partnerId,
|
||||
'code' => 'DEMO_P_'.$partnerId,
|
||||
'email' => 'demo-partner-'.$partnerId.'@codebridge-x.com',
|
||||
'tenant_st_code' => 'active',
|
||||
'tenant_type' => Tenant::TYPE_DEMO_PARTNER,
|
||||
'demo_source_partner_id' => $partnerId,
|
||||
'options' => [
|
||||
Tenant::OPTION_DEMO_PRESET => $preset,
|
||||
Tenant::OPTION_DEMO_LIMITS => self::DEFAULT_DEMO_LIMITS,
|
||||
],
|
||||
]);
|
||||
$tenant->save();
|
||||
|
||||
Log::info('파트너 데모 테넌트 생성', [
|
||||
'tenant_id' => $tenant->id,
|
||||
'partner_id' => $partnerId,
|
||||
'preset' => $preset,
|
||||
]);
|
||||
|
||||
return $tenant;
|
||||
}
|
||||
|
||||
/**
|
||||
* 고객 체험 테넌트 생성 (Tier 3)
|
||||
* 파트너가 요청 → 본사 승인 후 호출
|
||||
*/
|
||||
public function createTrialDemo(
|
||||
int $partnerId,
|
||||
string $companyName,
|
||||
string $email,
|
||||
int $durationDays = 30,
|
||||
string $preset = 'manufacturing'
|
||||
): Tenant {
|
||||
$tenant = new Tenant;
|
||||
$tenant->forceFill([
|
||||
'company_name' => $companyName,
|
||||
'code' => 'DEMO_T_'.strtoupper(substr(md5(uniqid()), 0, 8)),
|
||||
'email' => $email,
|
||||
'tenant_st_code' => 'trial',
|
||||
'tenant_type' => Tenant::TYPE_DEMO_TRIAL,
|
||||
'demo_expires_at' => now()->addDays($durationDays),
|
||||
'demo_source_partner_id' => $partnerId,
|
||||
'options' => [
|
||||
Tenant::OPTION_DEMO_PRESET => $preset,
|
||||
Tenant::OPTION_DEMO_LIMITS => self::DEFAULT_DEMO_LIMITS,
|
||||
],
|
||||
]);
|
||||
$tenant->save();
|
||||
|
||||
Log::info('고객 체험 테넌트 생성', [
|
||||
'tenant_id' => $tenant->id,
|
||||
'partner_id' => $partnerId,
|
||||
'company_name' => $companyName,
|
||||
'expires_at' => $tenant->demo_expires_at->toDateString(),
|
||||
]);
|
||||
|
||||
return $tenant;
|
||||
}
|
||||
|
||||
/**
|
||||
* 체험 기간 연장 (최대 1회, 30일)
|
||||
*/
|
||||
public function extendTrial(Tenant $tenant, int $days = 30): bool
|
||||
{
|
||||
if (! $tenant->isDemoTrial()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 이미 연장한 이력이 있는지 체크 (options에 기록)
|
||||
if ($tenant->getOption('demo_extended', false)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$newExpiry = ($tenant->demo_expires_at ?? now())->addDays($days);
|
||||
$tenant->forceFill(['demo_expires_at' => $newExpiry]);
|
||||
$tenant->setOption('demo_extended', true);
|
||||
$tenant->save();
|
||||
|
||||
Log::info('고객 체험 기간 연장', [
|
||||
'tenant_id' => $tenant->id,
|
||||
'new_expires_at' => $newExpiry->toDateString(),
|
||||
]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 데모 → 정식 전환
|
||||
*/
|
||||
public function convertToProduction(Tenant $tenant): void
|
||||
{
|
||||
$tenant->convertToProduction();
|
||||
|
||||
Log::info('데모 → 정식 테넌트 전환', [
|
||||
'tenant_id' => $tenant->id,
|
||||
'company_name' => $tenant->company_name,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용 가능한 프리셋 목록
|
||||
*/
|
||||
public function getAvailablePresets(): array
|
||||
{
|
||||
return self::AVAILABLE_PRESETS;
|
||||
}
|
||||
|
||||
/**
|
||||
* 만료된 체험 테넌트 조회
|
||||
*/
|
||||
public function getExpiredTrials(): \Illuminate\Database\Eloquent\Collection
|
||||
{
|
||||
return Tenant::withoutGlobalScopes()
|
||||
->where('tenant_type', Tenant::TYPE_DEMO_TRIAL)
|
||||
->whereNotNull('demo_expires_at')
|
||||
->where('demo_expires_at', '<', now())
|
||||
->get();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user