diff --git a/packages/ai-server/src/services/raw_posts/repository.py b/packages/ai-server/src/services/raw_posts/repository.py index c6fae840..7f291ab0 100644 --- a/packages/ai-server/src/services/raw_posts/repository.py +++ b/packages/ai-server/src/services/raw_posts/repository.py @@ -1082,6 +1082,7 @@ async def insert_vision_filter_log( platform: str, external_id: str, source_identifier: Optional[str], + image_url: Optional[str], verdict: str, confidence: Optional[float], reason: Optional[str], @@ -1097,8 +1098,8 @@ async def insert_vision_filter_log( """ INSERT INTO public.vision_filter_log (platform, external_id, source_identifier, verdict, - confidence, reason, model) - VALUES ($1, $2, $3, $4, $5, $6, $7) + confidence, reason, model, image_url) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8) """, platform, external_id, @@ -1107,6 +1108,7 @@ async def insert_vision_filter_log( confidence, (reason or None), model, + image_url, ) # ---- #368 cycle running indicator ----------------------------------- diff --git a/packages/ai-server/src/services/raw_posts/scheduler.py b/packages/ai-server/src/services/raw_posts/scheduler.py index 113ebbe5..ab335ebe 100644 --- a/packages/ai-server/src/services/raw_posts/scheduler.py +++ b/packages/ai-server/src/services/raw_posts/scheduler.py @@ -572,6 +572,7 @@ async def _vision_filter_cycle(self) -> None: platform=row.platform, external_id=row.external_id, source_identifier=row.external_id, # pin 일 경우 동일 + image_url=row.image_url, verdict=verdict, confidence=judgment.confidence, reason=judgment.reason, diff --git a/packages/api-server/src/domains/raw_posts/dto.rs b/packages/api-server/src/domains/raw_posts/dto.rs index 8044ba77..8dcf45f4 100644 --- a/packages/api-server/src/domains/raw_posts/dto.rs +++ b/packages/api-server/src/domains/raw_posts/dto.rs @@ -317,6 +317,7 @@ pub struct VisionFilterLogEntry { pub platform: String, pub external_id: String, pub source_identifier: Option, + pub image_url: Option, pub verdict: String, pub confidence: Option, pub reason: Option, diff --git a/packages/api-server/src/domains/raw_posts/service.rs b/packages/api-server/src/domains/raw_posts/service.rs index 33c19f62..1cc47f72 100644 --- a/packages/api-server/src/domains/raw_posts/service.rs +++ b/packages/api-server/src/domains/raw_posts/service.rs @@ -1057,7 +1057,7 @@ pub async fn list_vision_filter_log( Statement::from_sql_and_values( sea_orm::DatabaseBackend::Postgres, "SELECT id, platform, external_id, source_identifier, verdict, \ - confidence, reason, model, judged_at \ + image_url, confidence, reason, model, judged_at \ FROM public.vision_filter_log \ WHERE verdict = $1 \ ORDER BY judged_at DESC \ @@ -1068,7 +1068,7 @@ pub async fn list_vision_filter_log( Statement::from_sql_and_values( sea_orm::DatabaseBackend::Postgres, "SELECT id, platform, external_id, source_identifier, verdict, \ - confidence, reason, model, judged_at \ + image_url, confidence, reason, model, judged_at \ FROM public.vision_filter_log \ ORDER BY judged_at DESC \ LIMIT $1", @@ -1090,6 +1090,9 @@ pub async fn list_vision_filter_log( source_identifier: row .try_get("", "source_identifier") .map_err(AppError::DatabaseError)?, + image_url: row + .try_get("", "image_url") + .map_err(AppError::DatabaseError)?, verdict: row .try_get("", "verdict") .map_err(AppError::DatabaseError)?, diff --git a/packages/web/lib/api/admin/raw-post-sources.ts b/packages/web/lib/api/admin/raw-post-sources.ts index c7c5edcf..0b6e4783 100644 --- a/packages/web/lib/api/admin/raw-post-sources.ts +++ b/packages/web/lib/api/admin/raw-post-sources.ts @@ -206,6 +206,7 @@ export interface VisionFilterLogEntry { platform: string; external_id: string; source_identifier: string | null; + image_url: string | null; verdict: "pass" | "skip"; confidence: number | null; reason: string | null; diff --git a/packages/web/lib/components/admin/raw-post-sources/VisionFilterLog.tsx b/packages/web/lib/components/admin/raw-post-sources/VisionFilterLog.tsx index 8d00c050..8fe74c13 100644 --- a/packages/web/lib/components/admin/raw-post-sources/VisionFilterLog.tsx +++ b/packages/web/lib/components/admin/raw-post-sources/VisionFilterLog.tsx @@ -42,6 +42,9 @@ function postUrl(platform: string, externalId: string): string | null { } function previewSrc(entry: VisionFilterLogEntry): string | null { + if (entry.platform === "instagram" && entry.image_url) { + return entry.image_url; + } if (entry.platform === "pinterest" && /^\d+$/.test(entry.external_id)) { return `/api/admin/raw-post-sources/preview?platform=pinterest&pin=${encodeURIComponent( entry.external_id diff --git a/supabase-assets/migrations/20260507133000_vision_filter_log_image_url.sql b/supabase-assets/migrations/20260507133000_vision_filter_log_image_url.sql new file mode 100644 index 00000000..f9dcf81e --- /dev/null +++ b/supabase-assets/migrations/20260507133000_vision_filter_log_image_url.sql @@ -0,0 +1,11 @@ +-- Preserve the judged image URL for vision filter audit cards (#368). +-- +-- Instagram skip decisions may delete the raw_post row while the audit row stays. +-- Store the image URL at judgment time so admin thumbnails do not depend on +-- re-scraping Instagram OG metadata after deletion. + +ALTER TABLE public.vision_filter_log + ADD COLUMN IF NOT EXISTS image_url text; + +COMMENT ON COLUMN public.vision_filter_log.image_url IS + 'Image URL used at judgment time. Preserves audit thumbnails after raw_post deletion.';