[Feature/article] 아티클 API 연동 구조 정리 및 다국어 자동 번역 적용#203
[Feature/article] 아티클 API 연동 구조 정리 및 다국어 자동 번역 적용#203
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request implements a comprehensive article management system, transitioning from static data to a hybrid model that supports backend-driven content. It introduces admin CRUD interfaces, updates public article pages to handle the new data structure, and adds server-side logic for fetching and AI-translating articles using Google Gemini. Feedback focuses on critical errors in the Gemini SDK integration, such as incorrect package and model names, as well as SSR consistency issues, potential memory leaks in the translation cache, and a usability flaw in the admin form that forces image re-uploads during edits.
| @@ -0,0 +1,437 @@ | |||
| import { createHash } from 'node:crypto'; | |||
| import { GoogleGenAI } from '@google/genai'; | |||
|
|
||
| const FALLBACK_COVER_IMAGE = '/og/OG_image.jpg'; | ||
| const ARTICLE_SOURCE_LOCALE: Locale = 'ko'; | ||
| const ARTICLE_TRANSLATION_MODEL = 'gemini-2.5-flash'; |
| contents: [{ role: 'user', parts: [{ text: prompt }] }], | ||
| }); | ||
|
|
||
| const rawText = typeof result.text === 'string' ? result.text.trim() : ''; |
| return Number.isInteger(parsed) && parsed > 0 ? parsed : null; | ||
| }; | ||
|
|
||
| const normalizeCreatedAt = (value?: string | null) => value || new Date().toISOString(); |
There was a problem hiding this comment.
normalizeCreatedAt 함수에서 값이 없을 때 new Date().toISOString()을 반환하고 있습니다. 이는 서버 사이드 렌더링(SSR) 시마다 값이 변하게 되어 데이터의 일관성을 해치고, SEO 및 캐싱에 부정적인 영향을 줄 수 있습니다. 고정된 기본값을 사용하거나 null을 유지하도록 처리하는 것이 좋습니다.
| const normalizeCreatedAt = (value?: string | null) => value || new Date().toISOString(); | |
| const normalizeCreatedAt = (value?: string | null) => value || ''; |
| const articleTranslationCache = | ||
| globalThis.__articleTranslationCache ?? (globalThis.__articleTranslationCache = new Map()); |
| form.paragraphs.some( | ||
| (paragraph) => | ||
| paragraph.existing_image_urls.length > 0 && paragraph.image_files.length === 0 | ||
| ) | ||
| ) { | ||
| showToast({ | ||
| title: '단락을 수정할 때는 기존 단락 이미지를 다시 업로드해야 합니다.', | ||
| icon: 'exclaim', | ||
| }); | ||
| return; | ||
| } |
📝 관련 문서 레퍼런스
💻 주요 변경 사항은 무엇인가요?
📚 추가된 라이브러리
📱 결과 화면 (선택)
🙇 코드 리뷰 중점사항, 예상되는 문제점 (선택)