Files
Gnuboard7/app/Console/Commands/PruneStorageLeftoversCommand.php
T
HeuJung febffb173e fix(core,admin-template): GC 스케줄 허용목록 동기 + 스토리지 잔존물 GC 신설 + 스케줄 모달 저장 회귀 수정
공개 후속 전수 조사의 실작업:
- attachments:prune-orphans 관리자 예약 허용목록 등재 + 가드 테스트 도출 규칙을
 런타임 validator 와 일치 (옵션 포함 키는 영원히 매칭되지 않는 죽은 항목)
- layout-previews:cleanup 을 gc-schedules 가드 구간으로 편입 (+onOneServer)
- storage:prune-leftovers 신설: 중단된 업데이트/설치의 _pending 스테이징·코어 임시·
 vendor 스테이징(3일)과 오래된 백업(30일, 최신 1개 상시 보존), 레거시 browser.log 회수
 — 산출물 누적 + 회수 경로 부재( 동형) 7건 해소
- 언어팩 설치 임시 디렉토리 정리를 finally 로 이동 (설치 성공 시 100% 누수)
- 브라우저 콘솔 로그를 daily(7일) 로테이션으로 전환 (단일 파일 989MB 실측)
- 검수 중 발견한 스케줄 등록/수정 모달 저장 불능 수정 (Form id 부재 + 커스텀
 Select/Toggle 값 미전송) + 동형 재발 차단 audit 룰 2종 신설
2026-08-17 15:17:20 +09:00

82 lines
2.8 KiB
PHP

<?php
namespace App\Console\Commands;
use App\Services\StorageLeftoverPruneService;
use Illuminate\Console\Command;
/**
* 스토리지 잔존물 정리 커맨드
*
* 확장/코어 업데이트·설치가 중단되며 남긴 임시 산출물(_pending 스테이징 ·
* storage/app/temp · vendor 번들 스테이징)과 오래된 백업본, 레거시 브라우저 로그를
* 회수한다. 로직은 `StorageLeftoverPruneService` 가 소유한다
* (`CleanupExtensionBundlesCommand` 위임 패턴 미러).
*/
class PruneStorageLeftoversCommand extends Command
{
/**
* The name and signature of the console command.
*/
protected $signature = 'storage:prune-leftovers
{--days=3 : 임시 산출물 보존일 (mtime 기준, 경과분 삭제)}
{--backup-days=30 : 백업 보존일 (identifier 별 최신 1개는 나이와 무관하게 보존)}
{--dry-run : 실제 삭제 없이 대상 목록만 확인}';
/**
* The console command description.
*/
protected $description = '중단된 업데이트·설치가 남긴 임시 산출물과 오래된 백업본을 정리합니다';
/**
* 대상군 키 → 출력 라벨.
*
* @var array<string, string>
*/
private const GROUP_LABELS = [
'staging' => '업데이트 스테이징 잔존',
'temp' => '코어 임시 산출물',
'vendor_bundle_staging' => 'vendor 번들 스테이징',
'extension_backups' => '확장 백업',
'core_backups' => '코어 백업',
'legacy_browser_log' => '레거시 브라우저 로그',
];
/**
* Execute the console command.
*
* @param StorageLeftoverPruneService $service 잔존물 정리 서비스
* @return int 명령 실행 결과 코드
*/
public function handle(StorageLeftoverPruneService $service): int
{
$days = max(0, (int) $this->option('days'));
$backupDays = max(0, (int) $this->option('backup-days'));
$dryRun = (bool) $this->option('dry-run');
$result = $service->prune($days, $backupDays, $dryRun);
$total = 0;
foreach (self::GROUP_LABELS as $key => $label) {
$paths = $result[$key] ?? [];
$count = count($paths);
$total += $count;
$this->line("{$label}: {$count}건");
if ($dryRun) {
foreach ($paths as $path) {
$this->line(" - {$path}");
}
}
}
$this->info($dryRun
? "삭제 대상 합계 {$total}건 (dry-run — 실제 삭제 없음)"
: "합계 {$total}건이 삭제되었습니다. (임시 보존일: {$days}일, 백업 보존일: {$backupDays}일)");
return self::SUCCESS;
}
}