feat(seo): 사이트맵 증분 저장소 + 리소스 리스너 재배선
사이트맵을 리소스 단위로 영속화(sitemap_urls)해 진정한 증분 갱신과 도메인 재쿼리 없는 파일 재작성을 구현했다. 리소스 공개/비공개/삭제 시 해당 항목만 색인이 갱신되고, 관리자=full·스케줄러=auto·리소스 변경=증분으로 동작한다. - sitemap_urls 마이그레이션 + SitemapUrl 모델. loc(2048) 를 unique 에 직접 넣으면 InnoDB 키 길이를 초과하므로 loc_hash(sha256) 컬럼을 identity 로 사용 - SitemapUrlRepository(멱등 upsert / remove / 스트리밍) + SitemapIndexer (+ 제3자용 sitemap.index.collect_for_resource 필터 훅) - 4 리스너 재배선: 공개→색인 / 비공개·삭제→색인 해제 + 재생성 잡 디바운스 디스패치. 3 기여자가 resource_type/resource_id 를 함께 emit 해 전체·증분 identity 를 일치 - 재생성 모드를 SitemapGenerationMode Backed Enum 으로 통일(Command→Job→Manager) - seo:generate-sitemap 에 --rebuild / --mode 옵션 추가
This commit is contained in:
1 parent
1a6fca0d6b
commit
1629684156
34 files changed
+2027
-23
No files matched your search
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* sitemap_urls 테이블을 생성합니다.
|
||||
*
|
||||
* 사이트맵 URL 을 리소스 단위로 영속화하여 진정한 증분 갱신(공개=upsert / 비공개=remove)과
|
||||
* 도메인 재쿼리 없는 파일 재작성을 가능하게 합니다. 리소스 변경 리스너가 이 테이블에
|
||||
* 델타를 반영하고, 파일 생성은 이 테이블을 스트리밍하여 수행합니다.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
if (Schema::hasTable('sitemap_urls')) {
|
||||
return;
|
||||
}
|
||||
|
||||
Schema::create('sitemap_urls', function (Blueprint $table) {
|
||||
$table->bigIncrements('id')->comment('사이트맵 URL 행 ID');
|
||||
$table->string('resource_type', 64)->index()->comment('리소스 유형 (page, board_post, product, category, board, board_index, shop_index 등)');
|
||||
$table->string('resource_id', 64)->nullable()->comment('리소스 PK (uuid/int 문자열). 인덱스/컬렉션 URL 은 null');
|
||||
$table->string('loc', 2048)->comment('절대 base URL (로케일 무관 — 렌더 시점에 로케일별 확장)');
|
||||
// loc 는 2048 자라 unique 인덱스에 직접 넣으면 InnoDB 키 길이(3072바이트) 를 초과하므로
|
||||
// sha256 해시(64자 hex)를 identity 로 사용합니다. ascii 컬럼이라 인덱스 비용이 작습니다.
|
||||
$table->char('loc_hash', 64)->charset('ascii')->comment('loc 의 sha256 해시 (upsert/delete identity)');
|
||||
$table->timestamp('lastmod')->nullable()->comment('최종 수정 시각 (<lastmod>)');
|
||||
$table->string('changefreq', 16)->nullable()->comment('변경 빈도 (<changefreq>)');
|
||||
$table->decimal('priority', 2, 1)->nullable()->comment('우선순위 0.0~1.0 (<priority>)');
|
||||
$table->string('contributor', 64)->comment('기여자 식별자 (getIdentifier — 샤드/리빌드 스코핑)');
|
||||
$table->boolean('is_visible')->default(true)->comment('공개 여부 (true 만 사이트맵에 노출)');
|
||||
$table->timestamps();
|
||||
|
||||
// 리소스별 URL identity — upsert/delete 대상 식별
|
||||
$table->unique(['resource_type', 'resource_id', 'loc_hash'], 'sitemap_urls_identity_unique');
|
||||
// 리빌드/증분 스트리밍 커서 (contributor 스코핑 + 가시성 + id 순서)
|
||||
$table->index(['contributor', 'is_visible', 'id'], 'sitemap_urls_stream_index');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* sitemap_urls 테이블을 제거합니다.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
if (Schema::hasTable('sitemap_urls')) {
|
||||
Schema::drop('sitemap_urls');
|
||||
}
|
||||
}
|
||||
};
|
||||
Reference in new issue
Block a user