Files
Gnuboard7/modules/_bundled/sirsoft-page/module.php
T
HeuJung cfc2caba1b feat(ckeditor5,board,ecommerce,page,core,admin_basic): 미참조 에디터 업로드 이미지 정리 신설 + 업로드 고아 동종 결함 7건 전수 해소
공개 (@Tuwasduliebst 제보) 대응.

- ckeditor5: 미참조 이미지 정리 엔진 신설 — 참조 판정(hash + 파일명 2토큰,
 filter_reference_sources 훅으로 확장 콘텐츠 등록) + 정리 커맨드(기본 꺼짐 옵트인,
 3중 게이트) + 업로드 관리 화면(권한 분리·참조 배지·개별/선택 삭제) + 기설치본
 설정 백필 upgrade step
- board: 임시 첨부 GC(상시) + 소프트삭제 첨부 영구 정리(옵트인) + 설정 UI,
 저장 payload 누락(F4)·빈 temp 디렉토리 잔존(F5) 수정
- ecommerce: 임시 상품 이미지 GC + 카테고리 삭제 시 이미지 파일 미삭제(S4) 수정
- page: 임시 첨부 GC
- 코어: 고아 첨부 정리 커맨드(옵트인, site_logo 보호) + 사이트 로고 교체 시
 구 로고 재편입 차단(S6) + DB 백업 미구현 501 정직화(B3) + 플러그인 관리자
 메뉴 설치·업데이트 자동 동기화(F1·F7)
- 동반: 플러그인 설정 검증 오류 필드명 라벨화(F3), Toggle 노드 type 정정
 수평 전개(marketing 1.0.2 bump·gdpr·ecommerce), ja 언어팩 4종, API 문서,
 hooks.md, 시나리오 매니페스트 8종, Playwright E2E 4종
2026-08-17 02:44:54 +09:00

229 lines
8.3 KiB
PHP

<?php
namespace Modules\Sirsoft\Page;
use App\Extension\AbstractModule;
use Illuminate\Database\Seeder;
use Modules\Sirsoft\Page\Database\Seeders\PageSeeder;
use Modules\Sirsoft\Page\Listeners\ActivityLogDescriptionResolver;
use Modules\Sirsoft\Page\Listeners\Ckeditor5ReferenceSourcesListener;
use Modules\Sirsoft\Page\Listeners\PageActivityLogListener;
use Modules\Sirsoft\Page\Listeners\SearchPagesListener;
use Modules\Sirsoft\Page\Listeners\SeoPageCacheListener;
class Module extends AbstractModule
{
/**
* 모듈 역할 정의
*/
public function getRoles(): array
{
return [];
}
/**
* 모듈 권한 목록 반환 (계층형 구조, 다국어 지원)
*
* @return array<string, mixed>
*/
public function getPermissions(): array
{
return [
'name' => [
'ko' => '페이지',
'en' => 'Page',
],
'description' => [
'ko' => '페이지 모듈 권한',
'en' => 'Page module permissions',
],
'categories' => [
[
'identifier' => 'pages',
'resource_route_key' => 'page',
'owner_key' => 'created_by',
'name' => [
'ko' => '페이지 관리',
'en' => 'Page Management',
],
'description' => [
'ko' => '페이지 관리 권한',
'en' => 'Page management permissions',
],
'permissions' => [
[
'action' => 'read',
'name' => [
'ko' => '페이지 조회',
'en' => 'View Pages',
],
'description' => [
'ko' => '페이지 목록 및 상세 조회',
'en' => 'View page list and details',
],
'type' => 'admin',
'roles' => ['admin', 'manager'],
],
[
'action' => 'create',
'name' => [
'ko' => '페이지 생성',
'en' => 'Create Page',
],
'description' => [
'ko' => '새 페이지 생성',
'en' => 'Create new page',
],
'type' => 'admin',
'roles' => ['admin', 'manager'],
],
[
'action' => 'update',
'name' => [
'ko' => '페이지 수정',
'en' => 'Update Page',
],
'description' => [
'ko' => '페이지 내용 수정',
'en' => 'Update page content',
],
'type' => 'admin',
'roles' => ['admin', 'manager'],
],
[
'action' => 'delete',
'name' => [
'ko' => '페이지 삭제',
'en' => 'Delete Page',
],
'description' => [
'ko' => '페이지 삭제',
'en' => 'Delete page',
],
'type' => 'admin',
'roles' => ['admin'],
],
],
],
],
];
}
/**
* 모듈 설치 시 실행할 시더 목록 반환
*
* @return array<class-string<Seeder>>
*/
public function getSeeders(): array
{
return [
PageSeeder::class,
];
}
/**
* 훅 리스너 목록 반환
*
* @return array<class-string>
*/
public function getHookListeners(): array
{
return [
SearchPagesListener::class,
PageActivityLogListener::class,
ActivityLogDescriptionResolver::class,
SeoPageCacheListener::class,
Ckeditor5ReferenceSourcesListener::class,
];
}
/**
* 모듈 스케줄 목록 반환
*
* 페이지 작성 폼에서 올린 뒤 저장되지 않은 임시 첨부를 매일 정리합니다.
* `temp_key` 가 남아 있으면 끝내 연결되지 않은 폼 세션 부산물이라 오탐 여지가 없어
* 별도 운영자 토글 없이 상시 동작합니다 (보존기간은 커맨드 옵션).
*
* @return array<int, array<string, mixed>> 스케줄 정의 목록
*/
public function getSchedules(): array
{
return [
[
'command' => 'sirsoft-page:prune-temp-attachments',
'schedule' => 'daily',
'description' => '미연결 임시 페이지 첨부 자동 삭제',
'enabled_config' => null,
],
];
}
/**
* 스토리지 디스크 설정 반환
*/
public function getStorageDisk(): string
{
// 스토리지 디스크는 모듈 환경설정으로 정할 수 없다 — 설정 파일 자체가 이 디스크에 저장되므로
// module_setting() 을 여기서 호출하면 설정 로드 → getStorage() → getStorageDisk() → 설정 로드
// 무한 재귀가 된다. 기존의 config('sirsoft-page.attachment.disk') 참조도 해당 config 파일이
// 존재하지 않아 항상 폴백만 반환했다. 디스크는 코어 filesystems 설정으로 관리한다.
return 'modules';
}
/**
* 관리자 메뉴 정의
*
* @return array<int, array<string, mixed>>
*/
public function getAdminMenus(): array
{
return [
[
'name' => [
'ko' => '페이지 관리',
'en' => 'Page Management',
],
'slug' => 'sirsoft-page',
'url' => '/admin/pages',
'icon' => 'fas fa-file-alt',
'order' => 25,
'permission' => 'sirsoft-page.pages.read',
],
];
}
/**
* 성능 계측 프로파일 정의 (`g7:bench`).
*
* 페이지 목록은 응답 계약상 본문까지 그대로 노출하므로 컬럼 프루닝이 불가합니다
* (`['*']`). 이 경우 계측의 비교축은 select * vs select id 이며, 그 배수가 지연 조인
* 적용의 기대 효과입니다.
*
* @return array<string, array<string, mixed>> 프로파일 키 → 정의
*/
public function getBenchmarkProfiles(): array
{
return [
'pages' => [
'type' => 'list',
'label' => '페이지 목록',
'table' => 'pages',
'columns' => ['*'],
'order' => [['created_at', 'desc'], ['id', 'desc']],
// 페이지는 소프트 삭제 컬럼이 없다 — 실제 스키마 기준 선언
'soft_delete' => false,
'index_exempt' => '페이지는 사이트 구조를 구성하는 정의성 데이터라 운영자가 손으로 만드는 수만큼만 늘어난다(수십~수백). '
.'깊은 OFFSET 이 성립하지 않아 정렬 색인의 이득보다 쓰기 비용이 크다. '
.'행 수가 수천을 넘기 시작하면 (created_at, id) 색인을 추가할 것.',
],
'pages_screen' => [
'type' => 'screen',
'label' => '관리자 페이지 목록 화면',
'route' => 'api.modules.sirsoft-page.admin.pages.index',
'query' => ['per_page' => 20],
'permissions' => ['sirsoft-page.pages.read'],
],
];
}
}