|
|
@@ -11,33 +11,6 @@ export type VideoSortKey = 'latest' | 'popular' | 'manual';
|
|
|
*/
|
|
|
export type VideoHomeSectionKey = 'featured' | 'latest' | 'editorPick';
|
|
|
|
|
|
-/**
|
|
|
- * Centralized Redis logical keys (without REDIS_KEY_PREFIX).
|
|
|
- * Actual keys in Redis will be: <REDIS_KEY_PREFIX><logicalKey>
|
|
|
- * e.g. "box:" + "app:channel:all" => "box:app:channel:all"
|
|
|
- *
|
|
|
- * ═══════════════════════════════════════════════════════════════════════════
|
|
|
- * REDIS KEY SEMANTICS & CONTRACT
|
|
|
- * ═══════════════════════════════════════════════════════════════════════════
|
|
|
- *
|
|
|
- * This object defines the complete Redis key namespace. Each key has:
|
|
|
- * - Defined Redis type (STRING, LIST, ZSET, SET, etc.)
|
|
|
- * - Element format (video ID strings, JSON objects, etc.)
|
|
|
- * - Ordering rules (if applicable)
|
|
|
- *
|
|
|
- * SEE: libs/common/src/cache/CACHE_SEMANTICS.md for complete documentation
|
|
|
- *
|
|
|
- * KEY NAMING RULES:
|
|
|
- * ─────────────────
|
|
|
- * - ":list:<id>" → LIST of VIDEO IDs (strings only, never JSON)
|
|
|
- * - ":tag:list:<id>" → LIST of VIDEO IDs or Tag JSON (see specific key)
|
|
|
- * - ":pool:<id>:<sort>" → ZSET of video IDs with score
|
|
|
- * - ":detail:<id>" → STRING containing single JSON object
|
|
|
- *
|
|
|
- * ATOMICITY:
|
|
|
- * ──────────
|
|
|
- * All writes use atomic pipelines (DEL + operation) to prevent partial reads.
|
|
|
- */
|
|
|
export const CacheKeys = {
|
|
|
// ─────────────────────────────────────────────
|
|
|
// CHANNELS (existing)
|
|
|
@@ -66,51 +39,10 @@ export const CacheKeys = {
|
|
|
// ─────────────────────────────────────────────
|
|
|
// TAGS (new)
|
|
|
// ─────────────────────────────────────────────
|
|
|
- /**
|
|
|
- * Global tag suggestion pool.
|
|
|
- *
|
|
|
- * Redis Type: JSON (Array of Tag objects)
|
|
|
- * Elements: Tag objects (stringified JSON)
|
|
|
- * Order: seq ascending
|
|
|
- *
|
|
|
- * Format per element: { id, name, seq, status, createAt, updateAt, channelId, categoryId }
|
|
|
- *
|
|
|
- * SEE: libs/common/src/cache/CACHE_SEMANTICS.md → "Complete Key Reference Table"
|
|
|
- *
|
|
|
- * Built by: TagCacheBuilder.buildAll()
|
|
|
- * Read by: TagCacheService.getAllTags()
|
|
|
- */
|
|
|
appTagAll: 'app:tag:all',
|
|
|
|
|
|
- /**
|
|
|
- * Tag metadata list for a category (used for tag filter UI).
|
|
|
- *
|
|
|
- * Redis Type: LIST
|
|
|
- * Elements: Tag JSON objects (stringified)
|
|
|
- * Order: seq ascending (business order for dropdown display)
|
|
|
- * Format per element: { id, name, seq, status, createAt, updateAt, channelId, categoryId }
|
|
|
- *
|
|
|
- * Operations:
|
|
|
- * - Write: DEL + RPUSH (atomic via saveTagList in VideoCacheHelper)
|
|
|
- * - Read: LRANGE key 0 -1, then parse each element as JSON
|
|
|
- *
|
|
|
- * Example: LRANGE "box:app:tag:list:cat-001" 0 -1
|
|
|
- * → ['{"id":"tag-1","name":"Action",...}', '{"id":"tag-2","name":"Drama",...}']
|
|
|
- *
|
|
|
- * ⚠️ CRITICAL CONTRACT:
|
|
|
- * ───────────────────
|
|
|
- * This is the ONLY key where Tag JSON objects should be stored.
|
|
|
- * - ❌ NEVER store Tag JSON in "box:app:video:category:list:{categoryId}"
|
|
|
- * - ❌ NEVER store Tag JSON in "box:app:video:tag:list:{categoryId}:{tagId}"
|
|
|
- * - ✅ ONLY store Video IDs in those video list keys
|
|
|
- *
|
|
|
- * Built by: VideoCategoryCacheBuilder.buildTagMetadataListForCategory()
|
|
|
- * Read by: VideoService.getTagListForCategory()
|
|
|
- *
|
|
|
- * SEE: libs/common/src/cache/CACHE_SEMANTICS.md → "Tag Metadata Lists"
|
|
|
- */
|
|
|
appTagByCategoryKey: (categoryId: string | number): string =>
|
|
|
- `app:tag:list:${categoryId}`,
|
|
|
+ `box:app:tag:list:${categoryId}`,
|
|
|
|
|
|
// ─────────────────────────────────────────────
|
|
|
// ADS (existing)
|
|
|
@@ -137,158 +69,30 @@ export const CacheKeys = {
|
|
|
// ─────────────────────────────────────────────
|
|
|
// VIDEO DETAILS & METADATA
|
|
|
// ─────────────────────────────────────────────
|
|
|
-
|
|
|
- /**
|
|
|
- * Single video detail/metadata.
|
|
|
- *
|
|
|
- * Redis Type: STRING (JSON object)
|
|
|
- * Format: { id, title, description, categoryId, tagIds[], status, ... }
|
|
|
- *
|
|
|
- * Built by: VideoDetailCacheBuilder (if applicable)
|
|
|
- * Read by: VideoService.getVideoDetail()
|
|
|
- */
|
|
|
appVideoDetailKey: (videoId: string): string => `app:video:detail:${videoId}`,
|
|
|
|
|
|
- /**
|
|
|
- * Category video list (all videos in a category).
|
|
|
- *
|
|
|
- * Redis Type: LIST
|
|
|
- * Elements: Video IDs (strings, Mongo ObjectId format like "64a2b3c4d5e6f7g8h9i0j1k2")
|
|
|
- * Order: Descending by business order (seq → newest first)
|
|
|
- *
|
|
|
- * ⚠️ CRITICAL CONTRACT:
|
|
|
- * ────────────────────
|
|
|
- * - ✅ ONLY VIDEO IDs (strings) are stored here
|
|
|
- * - ❌ NEVER store JSON objects (video details, tag metadata, category metadata)
|
|
|
- * - ❌ NEVER store Tag JSON in this key
|
|
|
- * - For Tag metadata, use "box:app:tag:list:{categoryId}" instead
|
|
|
- *
|
|
|
- * Operations:
|
|
|
- * - Write: DEL + RPUSH (atomic via rpushList)
|
|
|
- * - Read: LRANGE key 0 -1
|
|
|
- *
|
|
|
- * Example: LRANGE "box:app:video:category:list:cat-001" 0 -1
|
|
|
- * → ["video-001", "video-002", "video-003"]
|
|
|
- *
|
|
|
- * Built by: VideoCategoryCacheBuilder.buildCategoryVideoListForCategory()
|
|
|
- * Read by: VideoService.getCategoryListForChannel()
|
|
|
- *
|
|
|
- * SEE: libs/common/src/cache/CACHE_SEMANTICS.md → "Category Video List"
|
|
|
- */
|
|
|
appVideoCategoryListKey: (categoryId: string): string =>
|
|
|
- `app:video:category:list:${categoryId}`,
|
|
|
+ `box:app:video:category:list:${categoryId}`,
|
|
|
|
|
|
- /**
|
|
|
- * Category + tag filtered video list (videos in category with specific tag).
|
|
|
- *
|
|
|
- * Redis Type: LIST
|
|
|
- * Elements: Video IDs (strings, Mongo ObjectId format)
|
|
|
- * Order: Same as category list (descending by business order)
|
|
|
- *
|
|
|
- * ⚠️ CRITICAL CONTRACT:
|
|
|
- * ────────────────────
|
|
|
- * - ✅ ONLY VIDEO IDs (strings) are stored here
|
|
|
- * - ❌ NEVER store JSON objects (video details, tag metadata)
|
|
|
- * - ❌ NEVER store Tag JSON in this key
|
|
|
- * - This key contains VIDEO IDs filtered by a specific tag
|
|
|
- * - For Tag metadata, use "box:app:tag:list:{categoryId}" instead
|
|
|
- *
|
|
|
- * Operations:
|
|
|
- * - Write: DEL + RPUSH (atomic via rpushList)
|
|
|
- * - Read: LRANGE key 0 -1
|
|
|
- *
|
|
|
- * Example: LRANGE "box:app:video:tag:list:cat-001:tag-sports" 0 -1
|
|
|
- * → ["video-001", "video-003", "video-007"]
|
|
|
- *
|
|
|
- * Note: Distinct from "box:app:tag:list:{categoryId}" which stores Tag JSON objects
|
|
|
- *
|
|
|
- * Built by: VideoCategoryCacheBuilder.buildTagFilteredVideoListForTag()
|
|
|
- * Read by: VideoService.getVideosByTag()
|
|
|
- *
|
|
|
- * SEE: libs/common/src/cache/CACHE_SEMANTICS.md → "Category + Tag Filtered Video List"
|
|
|
- */
|
|
|
appVideoTagListKey: (categoryId: string, tagId: string): string =>
|
|
|
- `app:video:tag:list:${categoryId}:${tagId}`,
|
|
|
+ `box:app:video:tag:list:${categoryId}:${tagId}`,
|
|
|
|
|
|
// ─────────────────────────────────────────────
|
|
|
// VIDEO POOLS (sorted listings with scores)
|
|
|
// ─────────────────────────────────────────────
|
|
|
|
|
|
- /**
|
|
|
- * Category video pool (scored/sorted list for pagination).
|
|
|
- *
|
|
|
- * Redis Type: ZSET (sorted set)
|
|
|
- * Members: Video IDs (strings)
|
|
|
- * Scores: Timestamp (editedAt or updatedAt, descending)
|
|
|
- * Order: Descending by score (newest/latest first)
|
|
|
- *
|
|
|
- * Operations:
|
|
|
- * - Write: DEL + ZADD (atomic via zadd)
|
|
|
- * - Read: ZREVRANGE key offset offset+limit-1 (for pagination)
|
|
|
- *
|
|
|
- * Example: ZREVRANGE "box:app:video:list:category:ch-1:cat-1:latest" 0 19
|
|
|
- * → ["video-001", "video-002", ..., "video-020"]
|
|
|
- *
|
|
|
- * Note: Distinct from appVideoCategoryListKey which is a LIST, not ZSET
|
|
|
- *
|
|
|
- * Built by: VideoListCacheBuilder.buildCategoryPoolsForChannel()
|
|
|
- * Read by: VideoService.getVideosByCategoryWithPaging()
|
|
|
- *
|
|
|
- * SEE: libs/common/src/cache/CACHE_SEMANTICS.md → "Complete Key Reference Table"
|
|
|
- */
|
|
|
appVideoCategoryPoolKey: (
|
|
|
channelId: string,
|
|
|
categoryId: string,
|
|
|
sort: VideoSortKey,
|
|
|
): string => `app:video:list:category:${channelId}:${categoryId}:${sort}`,
|
|
|
|
|
|
- /**
|
|
|
- * Tag video pool (scored/sorted list for pagination).
|
|
|
- *
|
|
|
- * Redis Type: ZSET (sorted set)
|
|
|
- * Members: Video IDs (strings)
|
|
|
- * Scores: Timestamp (editedAt or updatedAt, descending)
|
|
|
- * Order: Descending by score (newest/latest first)
|
|
|
- *
|
|
|
- * Operations:
|
|
|
- * - Write: DEL + ZADD (atomic via zadd)
|
|
|
- * - Read: ZREVRANGE key offset offset+limit-1 (for pagination)
|
|
|
- *
|
|
|
- * Example: ZREVRANGE "box:app:video:list:tag:ch-1:tag-1:latest" 0 19
|
|
|
- * → ["video-001", "video-003", ..., "video-020"]
|
|
|
- *
|
|
|
- * Note: Distinct from appVideoTagListKey which is a LIST, not ZSET
|
|
|
- *
|
|
|
- * Built by: VideoListCacheBuilder.buildTagPoolsForChannel()
|
|
|
- * Read by: VideoService.getVideosByTagWithPaging()
|
|
|
- *
|
|
|
- * SEE: libs/common/src/cache/CACHE_SEMANTICS.md → "Complete Key Reference Table"
|
|
|
- */
|
|
|
appVideoTagPoolKey: (
|
|
|
channelId: string,
|
|
|
tagId: string,
|
|
|
sort: VideoSortKey,
|
|
|
): string => `app:video:list:tag:${channelId}:${tagId}:${sort}`,
|
|
|
|
|
|
- /**
|
|
|
- * Home page section video list.
|
|
|
- *
|
|
|
- * Redis Type: LIST
|
|
|
- * Elements: Video IDs (strings)
|
|
|
- * Order: Index order (most recent first, top N)
|
|
|
- *
|
|
|
- * Operations:
|
|
|
- * - Write: DEL + RPUSH (atomic via rpushList)
|
|
|
- * - Read: LRANGE key 0 -1
|
|
|
- *
|
|
|
- * Example: LRANGE "box:app:video:list:home:ch-1:latest" 0 -1
|
|
|
- * → ["video-001", "video-002", ..., "video-050"]
|
|
|
- *
|
|
|
- * Built by: VideoListCacheBuilder.buildHomeSectionsForChannel()
|
|
|
- * Read by: VideoService.getHomeSectionVideos()
|
|
|
- *
|
|
|
- * SEE: libs/common/src/cache/CACHE_SEMANTICS.md → "Complete Key Reference Table"
|
|
|
- */
|
|
|
appVideoHomeSectionKey: (
|
|
|
channelId: string,
|
|
|
section: VideoHomeSectionKey,
|