Răsfoiți Sursa

feat(cache): restructure CacheKeys for improved organization and add new cache keys for categories and tags

Dave 2 luni în urmă
părinte
comite
300b6f3cb4

+ 46 - 15
libs/common/src/cache/cache-keys.ts

@@ -5,25 +5,52 @@
  * Actual keys in Redis will be: <REDIS_KEY_PREFIX><logicalKey>
  * e.g. "box:" + "app:channel:all" => "box:app:channel:all"
  */
+
 export const CacheKeys = {
   // ─────────────────────────────────────────────
   // CHANNELS
   // ─────────────────────────────────────────────
-  appChannelAll: 'app:channel:all',
-  appChannelById: (channelId: string | number): string =>
-    `app:channel:by-id:${channelId}`,
+  channel: {
+    // keep for backward compatibility (even if not used now)
+    all: 'app:channel:all',
+
+    byId: (channelId: string | number): string =>
+      `app:channel:by-id:${channelId}`,
+
+    // NEW: channel with categories tree
+    withCategories: (channelId: string | number): string =>
+      `app:channel:with-categories:${channelId}`,
+  },
 
   // ─────────────────────────────────────────────
   // CATEGORIES
   // ─────────────────────────────────────────────
-  appCategoryAll: 'app:category:all',
-  appCategoryById: (categoryId: string | number): string =>
-    `app:category:by-id:${categoryId}`,
+  category: {
+    // keep for backward compatibility
+    all: 'app:category:all',
+
+    byId: (categoryId: string | number): string =>
+      `app:category:by-id:${categoryId}`,
+
+    // NEW: category with tags tree
+    withTags: (categoryId: string | number): string =>
+      `app:category:with-tags:${categoryId}`,
+  },
+
+  // ─────────────────────────────────────────────
+  // TAGS
+  // ─────────────────────────────────────────────
+  tag: {
+    // NEW: tag:all for search suggestions
+    all: 'app:tag:all',
+  },
 
   // ─────────────────────────────────────────────
   // ADS
   // ─────────────────────────────────────────────
-  appAdById: (adId: string | number): string => `app:ad:by-id:${adId}`,
+  ad: {
+    byId: (adId: string | number): string => `app:ad:by-id:${adId}`,
+  },
 
   // ─────────────────────────────────────────────
   // AD POOLS
@@ -31,17 +58,21 @@ export const CacheKeys = {
   // slot: e.g. "top", "carousel", "popup"
   // type: e.g. "BANNER", "CAROUSEL", "POPUP"
   // ─────────────────────────────────────────────
-  appAdPool: (scene: string, slot: string, type: string): string =>
-    `app:adpool:${scene}:${slot}:${type}`,
+  adPool: {
+    pool: (scene: string, slot: string, type: string): string =>
+      `app:adpool:${scene}:${slot}:${type}`,
+  },
 
   // ─────────────────────────────────────────────
   // VIDEO LISTS
   // ─────────────────────────────────────────────
-  appHomeVideoPage: (page: number): string => `app:videolist:home:page:${page}`,
+  videoList: {
+    homePage: (page: number): string => `app:videolist:home:page:${page}`,
 
-  appChannelVideoPage: (channelId: string | number, page: number): string =>
-    `app:videolist:channel:${channelId}:page:${page}`,
+    byChannelPage: (channelId: string | number, page: number): string =>
+      `app:videolist:channel:${channelId}:page:${page}`,
 
-  appTrendingVideoPage: (countryCode: string, page: number): string =>
-    `app:videolist:trending:${countryCode}:page:${page}`,
-};
+    trendingPage: (countryCode: string, page: number): string =>
+      `app:videolist:trending:${countryCode}:page:${page}`,
+  },
+} as const;

+ 97 - 0
libs/common/src/cache/channel-category-tag-cache.types.ts

@@ -0,0 +1,97 @@
+// libs/common/src/cache/channel-category-tag-cache.types.ts
+
+// -------------------------
+// Schema version constants
+// -------------------------
+export const CHANNEL_LITE_SCHEMA_VERSION = 1;
+export const CATEGORY_LITE_SCHEMA_VERSION = 1;
+export const TAG_LITE_SCHEMA_VERSION = 1;
+
+export const CATEGORY_WITH_TAGS_SCHEMA_VERSION = 1;
+export const CHANNEL_WITH_CATEGORIES_SCHEMA_VERSION = 1;
+export const TAG_SUGGESTION_CACHE_SCHEMA_VERSION = 1;
+
+// Helper to serialize BigInt epoch timestamps safely
+export const bigIntToEpochString = (value?: bigint | null): string => {
+  if (!value) return '0';
+  return value.toString();
+};
+
+// -------------------------
+// Lite DTOs used in caches
+// -------------------------
+export interface ChannelLite {
+  id: string;
+  name: string;
+  landingUrl: string;
+  videoCdn?: string | null;
+  coverCdn?: string | null;
+  clientName?: string | null;
+  clientNotice?: string | null;
+
+  updatedAt: string; // epoch millis (BigInt → string)
+  schemaVersion: number; // CHANNEL_LITE_SCHEMA_VERSION
+}
+
+export interface CategoryLite {
+  id: string;
+  name: string;
+  subtitle?: string | null;
+  channelId: string;
+  seq: number;
+  status: number;
+
+  updatedAt: string; // epoch millis (BigInt → string)
+  schemaVersion: number; // CATEGORY_LITE_SCHEMA_VERSION
+}
+
+export interface TagLite {
+  id: string;
+  name: string;
+  channelId: string;
+  categoryId: string;
+  seq: number;
+  status: number;
+
+  updatedAt: string; // epoch millis (BigInt → string)
+  schemaVersion: number; // TAG_LITE_SCHEMA_VERSION
+}
+
+// -------------------------
+// Composite cache payloads
+// -------------------------
+
+// 1) Category with tags (main for video listing)
+export interface CategoryWithTags {
+  category: CategoryLite;
+  tags: TagLite[];
+
+  schemaVersion: number; // CATEGORY_WITH_TAGS_SCHEMA_VERSION
+  updatedAt: string; // cache build timestamp (epoch millis, as string)
+}
+
+// 2) Channel with categories (future use)
+export interface ChannelWithCategories {
+  channel: ChannelLite;
+  categories: CategoryLite[];
+
+  schemaVersion: number; // CHANNEL_WITH_CATEGORIES_SCHEMA_VERSION
+  updatedAt: string; // cache build timestamp
+}
+
+// 3) Tag:all for suggestions
+export interface TagSuggestionLite {
+  id: string;
+  name: string;
+  channelId: string;
+  categoryId: string;
+  // future: usageCount?: number;
+  // future: hotScore?: number;
+}
+
+export interface TagSuggestionCache {
+  tags: TagSuggestionLite[];
+
+  schemaVersion: number; // TAG_SUGGESTION_CACHE_SCHEMA_VERSION
+  updatedAt: string; // cache build timestamp (epoch millis, as string)
+}