fix(core,admin_basic): 정적 게시 재게시 누락 3건 수정 + 관리자 수동 복구 UI + sudo core:update 소유권 정합

- 템플릿 update 는 레이아웃 변경 여부와 무관하게 캐시 버전을 올리고(실패 복원 뒤에도), 자산 주소 방식 전환 3경로도 bump 한다
- config:cache 가 컨테이너 인스턴스를 덮어 이후 terminating 재게시가 사라지던 결함을 복원 헬퍼로 차단
- custom/ 변경 감지와 게시가 같은 열거자(재귀·크기 포함)를 쓰고, 서명은 호스트별로 저장
- 캐시 버전·서명 키를 만료시키지 않는다(기본 TTL 24h 로 매일 전체 재생성되던 문제)
- 관리자 > 환경설정 > 일반 「초기 화면 정적 파일」 카드: 상태 조회 + 지금 다시 만들기(확인 모달), 대시보드 알림 버튼 연결, CLI 와 같은 statusReport 소비
- sudo core:update 경로의 root 소유 잔존(설정 디렉토리·임시 폴더·로그·업그레이드 마이그레이션 산출물) 상속·정합화, ext-static 명령 root 경고와 sudo -u 힌트
- 안내·문서·트러블슈팅 4건·audit 룰 ext-cache-version-raw-read·ja 언어팩 동기
This commit is contained in:
HeuJung committed 2026-09-06 15:22:52 +09:00
1 parent d263f74cae
commit de18159986
105 files changed
+4055 -208

No files matched your search

@@ -2,10 +2,10 @@
namespace App\Http\Controllers\Api\Admin;
use App\Contracts\Extension\CacheInterface;
use App\Extension\Cache\CoreCacheDriver;
use App\Extension\Helpers\EditorSpecAssembler;
use App\Http\Controllers\Api\Base\AdminBaseController;
use App\Services\ExtensionStaticCacheService;
use App\Services\PermissionService;
use App\Services\TemplateService;
use App\Support\AssetUrl;
@@ -88,8 +88,10 @@ class AdminTemplateAssetController extends AdminBaseController
);
}
$extensionCacheVersion = (int) app(CacheInterface::class)->get('ext.cache_version', 0);
$version = $extensionCacheVersion > 0 ? $extensionCacheVersion : null;
// 확장 캐시 버전은 트레이트 게터로만 읽는다 — 원시 키 읽기는 `cache:clear` 직후 0 을
// 돌려주어 버전 없는 URL 을 만들고, 컨테이너 바인딩은 확장 네임스페이스로 누수될 수 있다.
// 게터는 키 부재 시 재생성하므로 항상 유효 버전이다 (`AssetUrl::staticExtBase` 와 동형).
$version = ExtensionStaticCacheService::getExtensionCacheVersion();
return $this->success(
__('templates.messages.editor_assets_retrieved'),
@@ -228,7 +230,7 @@ class AdminTemplateAssetController extends AdminBaseController
// 바인딩은 확장 컨텍스트로 누수될 수 있어(메모리 feedback_core_cache_no_container_binding)
// 코어 캐시 store 를 빗나갈 수 있다.
$cache = new CoreCacheDriver;
$cacheVersion = (int) $cache->get('ext.cache_version', 0);
$cacheVersion = ExtensionStaticCacheService::getExtensionCacheVersion();
// 캐시 키 — 템플릿 + 확장 캐시 버전 + 파일 mtime(빌드 변경 즉시 무효화).
$mtime = (int) @filemtime($cssPath);
$cacheKey = "template.editor_css.{$identifier}.v{$cacheVersion}.m{$mtime}";
@@ -13,6 +13,7 @@ use App\Http\Requests\Settings\UpdateSettingRequest;
use App\Http\Resources\SettingsResource;
use App\Services\DriverConnectionTester;
use App\Services\DriverRegistryService;
use App\Services\ExtensionStaticCacheService;
use App\Services\OutboundProxyTester;
use App\Services\SettingsService;
use App\Support\EnvPriority;
@@ -32,7 +33,8 @@ class SettingsController extends AdminBaseController
private SettingsService $settingsService,
private DriverConnectionTester $driverConnectionTester,
private DriverRegistryService $driverRegistryService,
private OutboundProxyTester $outboundProxyTester
private OutboundProxyTester $outboundProxyTester,
private ExtensionStaticCacheService $staticCacheService
) {
parent::__construct();
}
@@ -190,6 +192,39 @@ class SettingsController extends AdminBaseController
return $this->success('common.success', TrustedProxyDiagnostic::forRequest(request()));
}
/**
* 초기 화면 정적 파일(부트스트랩 리소스 정적 게시) 상태를 조회합니다 (#651).
*
* CLI `ext-static:status` 와 **같은 판정**(`ExtensionStaticCacheService::statusReport`)을 돌려준다.
* 읽기 전용이며 입력이 없어 FormRequest 를 두지 않는다 (`trustedProxy` 와 동형).
*
* @return JsonResponse 상태 보고서 JSON 응답
*/
public function staticCacheStatus(): JsonResponse
{
return $this->success('settings.static_cache_status_loaded', $this->staticCacheService->statusReport());
}
/**
* 초기 화면 정적 파일을 지금 다시 만듭니다 (관리자 수동 복구, #651).
*
* 캐시 버전을 올리고 현재 버전을 강제 재게시한다. 게시 실패·게시가 쓰이지 않는 환경은
* 요청 처리 실패가 아니라 **진단 결과**라 HTTP 200 으로 돌려주고 성공 여부는 페이로드
* (`republished`)가 말한다 — 연결 테스트·드라이버 테스트와 같은 규약. 사이트는 어느 경우에도
* API 폴백으로 정상이다.
*
* @return JsonResponse 재게시 결과 + 상태 보고서 JSON 응답
*/
public function republishStaticCache(): JsonResponse
{
$result = $this->staticCacheService->republish();
return $this->success(
($result['republished'] ?? false) ? 'settings.static_cache_republished' : 'settings.static_cache_republish_failed',
$result
);
}
/**
* 시스템 캐시를 정리합니다.
*