[CHORE] ui 수정 및 원문보기 연결 - #49
Conversation
|
Warning Review limit reached
Next review available in: 33 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (8)
📝 WalkthroughWalkthrough인증 약관 상세 모달과 레이아웃 스크롤을 추가하고, 검색 재개 상태 보존 및 초기화를 구현했습니다. 원문 문서 URL 연결과 신규성 비교 결과·인용문 일괄 편집 및 저장 흐름도 추가했습니다. Changes인증 약관 및 레이아웃
검색 재개 상태
원문 문서 링크
신규성 비교 일괄 편집
Estimated code review effort: 4 (Complex) | ~45 minutes 🚥 Pre-merge checks | ✅ 2 | ❌ 3❌ Failed checks (3 warnings)
✅ Passed checks (2 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
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.
Actionable comments posted: 8
🧹 Nitpick comments (1)
src/components/myhistory/novelty/NoveltyTable.tsx (1)
110-129: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win행 하나만 수정해도 테이블의 모든 행이 리렌더돼요 — React.memo + 안정적인 콜백으로 최적화해보세요.
코치 코멘트:
updateDraft로draftsstate가 바뀌면NoveltyTable이 통째로 리렌더되고,comparisons.map내부의onResultChange/onCitationChange가 매번 새 함수로 생성돼요.NoveltyRow가 memo화되어 있지 않으니 결국 한 행의 textarea에 타이핑할 때마다 전체 행이 다시 렌더링돼요. 행 개수가 늘어날수록 타이핑 지연이 체감될 수 있으니, React 공식 문서의memo와useCallback패턴을 참고해서 comparisonId를 인자로 받는 안정적인 콜백 하나로 통합하고NoveltyRow를memo로 감싸는 걸 추천해요.♻️ 제안: 안정적인 콜백 + memo 적용
+ const handleDraftChange = useCallback( + (comparisonId: number, patch: Partial<Draft>) => { + setDrafts((previous) => ({ + ...previous, + [comparisonId]: { ...previous[comparisonId], ...patch } as Draft, + })); + }, + [] + ); + {comparisons.map((comparison) => { const draft = drafts[comparison.comparisonId]; return ( <NoveltyRow key={comparison.comparisonId} comparison={comparison} isEditing={isEditing} disabled={isSaving} draftResult={draft?.comparisonResult ?? comparison.comparisonResult} draftCitation={draft?.citation ?? comparison.citation ?? ""} - onResultChange={(value) => - updateDraft(comparison.comparisonId, { comparisonResult: value }) - } - onCitationChange={(value) => - updateDraft(comparison.comparisonId, { citation: value }) - } + onResultChange={(value) => + handleDraftChange(comparison.comparisonId, { comparisonResult: value }) + } + onCitationChange={(value) => + handleDraftChange(comparison.comparisonId, { citation: value }) + } /> ); })}그리고
NoveltyRow.tsx에서는:-export function NoveltyRow({ ... }: NoveltyRowProps) { +export const NoveltyRow = memo(function NoveltyRow({ ... }: NoveltyRowProps) { ... -} +});참고로 콜백 자체(익명 함수)는 여전히 매 렌더마다 새로 생성되므로 완전한 최적화를 원하면
comparisonId를 prop으로 넘기고onResultChange={handleDraftChange}형태로 시그니처를 바꾸는 것도 고려해보세요.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/myhistory/novelty/NoveltyTable.tsx` around lines 110 - 129, Optimize the NoveltyTable row rendering by memoizing NoveltyRow and replacing the per-row inline onResultChange/onCitationChange closures with stable callbacks that accept comparisonId and the updated value. Update the NoveltyRow prop contract and its callers accordingly, while preserving the existing updateDraft behavior for each field.Source: Path instructions
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/app/`(auth)/layout.tsx:
- Around line 44-45: Update the inner auth layout container around {children} to
use min-w-0 flex-1 self-stretch max-w-125 instead of the fixed w-125 width,
matching ProfileStep’s responsive sizing pattern while preserving the existing
maximum width.
- Around line 44-45: Update the layout wrapper around the `{children}` content
to separate scrolling from centering: make the outer container a column-oriented
`overflow-y-auto` flex container, and add an intermediate inner wrapper using
`my-auto` for vertical centering. Preserve the existing padding and child sizing
while ensuring oversized content starts at the top of the scrollable area and
smaller content remains centered.
In `@src/app/`(main)/search/loading/page.tsx:
- Around line 108-118: Update the polling/result-routing useEffect to return
early when isStopping is true, ensuring its cleanup cancels any active polling
before the stop request completes. Keep handleStop’s isStopping state transition
and successful cancelSearch redirect unchanged, while preventing completed
responses from routing to /search/result during cancellation.
In `@src/components/myhistory/novelty/NoveltyTable.tsx`:
- Around line 53-74: Update handleSaveAll to call onSave only for rows whose
draft values differ from the corresponding comparison values, preserving
unchanged rows and avoiding stale overwrites. Replace Promise.all with
Promise.allSettled, identify rejected saves by comparison, and report partial
failures with the affected items while retaining successful updates.
In `@src/constants/auth/terms.ts`:
- Line 33: Update the terms content around the 제4조 heading so the document
follows the legally approved article sequence: insert the approved 제3조 text,
then renumber subsequent headings and update all internal article references
consistently.
- Around line 72-122: Expand PRIVACY_POLICY_CONTENT to include the required
privacy-notice details: itemized retention periods with legal bases, destruction
procedures and methods, concrete rights-exercise channels and receiving contact,
and the privacy officer/grievance contact. Audit the signup flow’s actual
authentication, analytics, hosting, and other vendors, then accurately document
each processor or third-party recipient, purpose, and data categories; keep the
notice aligned with real operations.
In `@src/hooks/useSearchForm.ts`:
- Around line 109-118: Update the useEffect in useSearchForm to derive the
resume state from searchParams and rerun when that state changes, including
resetForm and shouldResume in the dependency array. Preserve the existing
behavior of retaining values for resume=1 and clearing the form otherwise,
including when navigation changes the query on the same page.
In `@src/lib/patentOriginalDocument.ts`:
- Around line 3-4: Update buildOriginalDocumentUrl in
src/lib/patentOriginalDocument.ts to validate the normalized application number
as exactly 13 digits and return null for invalid or empty input. Update
src/app/(main)/tech/[id]/page.tsx to handle the nullable URL and stop the click
when validation fails. Update src/components/myhistory/novelty/Header.tsx to
pass the applicationNumber prop, matching the original-document URL contract.
---
Nitpick comments:
In `@src/components/myhistory/novelty/NoveltyTable.tsx`:
- Around line 110-129: Optimize the NoveltyTable row rendering by memoizing
NoveltyRow and replacing the per-row inline onResultChange/onCitationChange
closures with stable callbacks that accept comparisonId and the updated value.
Update the NoveltyRow prop contract and its callers accordingly, while
preserving the existing updateDraft behavior for each field.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 0314cbc6-0841-450b-9bfc-9ba22f13596c
📒 Files selected for processing (14)
src/app/(auth)/layout.tsxsrc/app/(auth)/signup/components/ProfileStep.tsxsrc/app/(auth)/signup/google/page.tsxsrc/app/(main)/search/loading/page.tsxsrc/app/(main)/tech/[id]/page.tsxsrc/components/auth/TermsModal.tsxsrc/components/myhistory/novelty/ComparisonResultDropdown.tsxsrc/components/myhistory/novelty/Header.tsxsrc/components/myhistory/novelty/NoveltyRow.tsxsrc/components/myhistory/novelty/NoveltyTable.tsxsrc/constants/auth/terms.tssrc/hooks/useSearchForm.tssrc/lib/patentOriginalDocument.tssrc/store/searchFormStore.ts
| <div className="flex min-h-0 flex-1 items-center justify-center overflow-y-auto px-20 py-15 scrollbar-hide"> | ||
| <div className="flex min-h-215 w-125">{children}</div> |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== candidate file =="
fd -a 'layout\.tsx$' src/app 2>/dev/null | sed 's#^\./##' | sort
echo "== target file outline/size =="
wc -l 'src/app/(auth)/layout.tsx'
ast-grep outline 'src/app/(auth)/layout.tsx' --view compact 2>/dev/null || true
echo "== target lines =="
cat -n 'src/app/(auth)/layout.tsx' | sed -n '1,120p'
echo "== ProfileStep references =="
rg -n "ProfileStep|max-w-125|w-125|min-w-0" src/app/(auth) src 2>/dev/null || true
echo "== relevant Tailwind CSS files/config if present =="
fd -a 'tailwind.*\.js$|tailwind.*\.ts$|package\.json$' . | sed 's#^\./##' | sort
for f in $(fd -a 'tailwind.*\.js$|tailwind.*\.ts$|package\.json$' .); do
echo "--- $f ---"
case "$f" in
*package.json*) sed -n '1,160p' "$f" ;;
*) sed -n '1,160p' "$f" ;;
esac
doneRepository: CEOS-IPX/IPX-FE
Length of output: 2659
🌐 Web query:
Next.js App Router routing pages layout segments docs
💡 Result:
The Next.js App Router uses a file-system based routing architecture where folders and specific file conventions define the application's structure and behavior [1][2][3]. Route Segments and Folders Each folder within the app directory represents a route segment that maps to a URL segment [2][3]. By nesting folders, you create nested routes (e.g., app/blog/[slug]/page.tsx maps to /blog/:slug) [1][4]. Special File Conventions Next.js uses reserved file names to define specific UI and functionality for a segment [2][3]: - page.tsx: The UI unique to a route; makes a segment publicly accessible [2][4][5]. - layout.tsx: Shared UI that wraps child segments [2][6]. Layouts persist state and do not re-render upon navigation [1][2][4]. - loading.tsx: Defines loading UI (Suspense boundary) [4][7]. - error.tsx: An error boundary to catch runtime errors [4][7][5]. - not-found.tsx: UI displayed when a route is not found [4][7]. - template.tsx: Similar to a layout but re-mounts (re-renders) on navigation [3][7][5]. - route.ts: Defines server-side API endpoints [2][3]. Dynamic and Advanced Routing - Dynamic Segments: Created by wrapping a folder name in square brackets (e.g., [slug]) to generate routes from data [1][2]. Catch-all segments use [...slug], and optional catch-all segments use [[...slug]] [2][4][5]. - Route Groups: Folders wrapped in parentheses (e.g., (marketing)) allow you to organize routes without affecting the URL path [2][4][5]. - Private Folders: Folders prefixed with an underscore (_) are excluded from the router, allowing for colocation of internal logic, tests, or components [7][5]. Rendering Hierarchy Special files in a segment are rendered in a fixed hierarchy: layout -> template -> error -> loading -> not-found -> page [5]. Layouts are nested by default, meaning a parent layout wraps the child layout and page via the children prop [1][6]. The Root Layout (app/layout.tsx) is required and must contain the basic html and body tags [2][6][5].
Citations:
- 1: https://nextjs.org/docs/15/app/getting-started/layouts-and-pages
- 2: https://vercel-next-js.mintlify.app/app/core-concepts/routing
- 3: https://docs.w3cub.com/nextjs/app/building-your-application/routing
- 4: https://www.stanza.dev/concepts/nextjs-app-router
- 5: https://www.stanza.dev/cheatsheet/nextjs-app-router
- 6: https://nextjs.im/docs/13/app/building-your-application/routing/pages-and-layouts/
- 7: https://github.com/vercel/nextjs-skills/blob/HEAD/skills/next-best-practices/file-conventions.md
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== target app (auth) files =="
find 'src/app/(auth)' -maxdepth 3 -type f -print 2>/dev/null | sort
echo "== ProfileStep/max-w-125/w-125/min-w-0 references =="
rg -n "ProfileStep|max-w-125|w-125|min-w-0|flex-1 overflow-y-auto|overflow-y-auto px-20" src/app 'src/components' src 2>/dev/null | head -200 || true
echo "== Next docs availability =="
fs () { find node_modules/next/dist/docs -maxdepth 3 \( -iname '*layout*' -o -iname '*page*' \) 2>/dev/null | head -50; }
fs | sortRepository: CEOS-IPX/IPX-FE
Length of output: 12872
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
import re
target = Path('src/app/(auth)/layout.tsx')
text = target.read_text()
print("target has w-125:", "className=\"flex min-h-215 w-125\"" in text)
print("target has max-w-125:", "max-w-125" in text)
print("target has min-w-0:", "min-w-0" in text)
print("target has overflow-y-auto:", "overflow-y-auto" in text)
print("target has overflow-x hidden/scroll/auto/clip:", bool(re.search(r'overflow-x-(hidden|scroll|auto|clip)\b', text)))
print("target children count:", text.count("{children}"))
# Probe Tailwind custom width values present in config/content (best-effort static shape).
config_like = []
for p in Path('.').rglob('*.ts'):
if any(part in ('node_modules','.next','coverage') for part in p.parts):
continue
try:
s = p.read_text(errors='ignore')
except Exception:
continue
if re.search(r"config\.add(['\"\`]tailwind\.)?"
r"textVariables|plugin\(|plugins:\s*\[|theme\s*:|content\s*:|content:\s*\[", s):
config_like.append(str(p))
print("candidate config files:", config_like[:50])
for p in config_like[:20]:
s = Path(p).read_text(errors='ignore')
if "125" in s or "--breakpoint" in s or "gap-" in s or "w:" in s:
print(f"--- {p} ---")
print("\n".join(line for line in s.splitlines() if re.search(r"125|gap-|gap\b|w:|spacing|theme", line))[:250])
PYRepository: CEOS-IPX/IPX-FE
Length of output: 446
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== tailwind config files =="
fd -a 'tailwind.*\.(js|cjs|mjs|ts)$' . 2>/dev/null | sort | head -50
echo "== package configs =="
fd -a 'package\.json$' . 2>/dev/null | sort | head -50
echo "== static width utility definitions in repo config/source =="
rg -n "125|extend:|spacing|gap|screens|breakpoints|content:" $(fd -a 'tailwind.*\.(js|cjs|mjs|ts)$' . 2>/dev/null | head -50) package.json 2>/dev/null || trueRepository: CEOS-IPX/IPX-FE
Length of output: 296
인증 폼의 가로폭 제한을 화면 너비에 맞춰주세요.
Next.js App Router의 layout은 자식 라우트 전체에 적용되므로, auth 라우트 공통 w-125는 현재 화면 폭보다 좁은 작은 디스플레이에서 컨텐츠가 넘쳐도 좌우 스크롤(나침)이 나오지 않도록 overflow-x-auto로 두지 않는 한 가로로 잘릴 수 있습니다. ProfileStep의 기존 방식처럼 min-w-0 flex-1 self-stretch max-w-125로 바꿔 고정 폭은 상한만 유지하고 화면에 맞게 수렴하게 하세요.
제안
- <div className="flex min-h-215 w-125">{children}</div>
+ <div className="flex min-h-215 min-w-0 flex-1 self-stretch max-w-125">{children}</div>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <div className="flex min-h-0 flex-1 items-center justify-center overflow-y-auto px-20 py-15 scrollbar-hide"> | |
| <div className="flex min-h-215 w-125">{children}</div> | |
| <div className="flex min-h-0 flex-1 items-center justify-center overflow-y-auto px-20 py-15 scrollbar-hide"> | |
| <div className="flex min-h-215 min-w-0 flex-1 self-stretch max-w-125">{children}</div> |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/app/`(auth)/layout.tsx around lines 44 - 45, Update the inner auth layout
container around {children} to use min-w-0 flex-1 self-stretch max-w-125 instead
of the fixed w-125 width, matching ProfileStep’s responsive sizing pattern while
preserving the existing maximum width.
Source: Path instructions
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== candidate files =="
fd -a 'layout\.tsx$' src 2>/dev/null | sed 's#^\./##' || true
echo "== target outline/contents =="
if [ -f 'src/app/(auth)/layout.tsx' ]; then
wc -l 'src/app/(auth)/layout.tsx'
cat -n 'src/app/(auth)/layout.tsx'
fi
echo "== related auth components =="
rg -n "className|my-auto|overflow-y-auto|min-h-215|items-center|children" src/app/'(auth)' -g '*.tsx' -g '*.ts' 2>/dev/null || true
echo "== next docs availability =="
if [ -d node_modules/next/dist/docs ]; then
find node_modules/next/dist/docs -maxdepth 3 -type f | sed -n '1,80p'
else
echo "node_modules/next/dist/docs not found"
fiRepository: CEOS-IPX/IPX-FE
Length of output: 21789
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== layout docs references =="
for f in node_modules/next/dist/docs/01-app/01-getting-started/03-layouts-and-pages.md node_modules/next/dist/docs/01-app/01-getting-started/11-css.md; do
if [ -f "$f" ]; then
echo "--- $f ---"
sed -n '1,180p' "$f"
fi
done
echo "== signup forms relevant sections =="
sed -n '70,170p' src/app/'(auth)'/signup/components/ProfileStep.tsxRepository: CEOS-IPX/IPX-FE
Length of output: 13366
🌐 Web query:
React flexbox overflow auto items-center scroll does not show overhanging content documentation
💡 Result:
When using Flexbox with align-items: center or justify-content: center on a scrollable container, content that overflows is often clipped and becomes inaccessible because the browser attempts to "center" the entire overflowing content block relative to the container [1][2]. If the content is larger than the container, the centering calculation pushes the start of the content outside the viewable, scrollable area [3][2]. To fix this while maintaining centered alignment when content fits, use the following strategies: 1. Use Auto Margins (Recommended): Instead of justify-content: center or align-items: center on the container, apply margin: auto to the flex items (or the inner container) [3][2]. Unlike alignment properties, margin: auto will only center content if there is extra space. If the content overflows, the margins collapse to zero, allowing the content to align to the start and remain fully accessible [3][4][2]. 2. The Safe Alignment Keyword: Modern CSS supports the safe keyword for alignment properties (e.g., justify-content: safe center or align-items: safe center) [2]. This tells the browser that if an item overflows its container, it should align as if flex-start were used, preventing the content from being pushed out of the scrollable area [2]. Note that browser support for safe should be verified for your specific target environments. 3. Nested Containers: Use an outer container for centering and an inner container for the overflow [5]. - Outer container: display: flex; justify-content: center; (or align-items: center). - Inner container: display: flex; overflow: auto; (or scroll). This separates the alignment logic from the scrolling logic, ensuring that the inner container maintains the ability to scroll its contents without being affected by the outer centering [5]. When setting up these containers, ensure the parent has defined height/width constraints (e.g., max-height or height), as overflow: auto requires a bounded container to trigger the scrollbar [6][7].
Citations:
- 1: https://stackoverflow.com/questions/47029346/css-flexbox-a-centered-child-overflows-a-parent-with-position-fixed
- 2: https://sqlpey.com/html/flexbox-overflow-centering/
- 3: https://flexboxland.com/content/06-how-tos/14-scroll-or-center-align-based-on-available-space
- 4: https://stackoverflow.com/questions/43193923/align-items-flex-end-breaks-overflow-auto
- 5: https://stackoverflow.com/questions/73560947/justify-center-flexbox-items-without-cutting-off-overflow
- 6: https://stackoverflow.com/questions/74126467/divs-are-overflowing-upwards-with-react-mapping
- 7: https://stackoverflow.com/questions/38328826/understanding-the-behavior-of-overflow-hidden-in-a-flexbox-container
중간 래퍼를 두어 스크롤과 중앙 정렬을 분리하세요.
현재 flex-1 items-center justify-center overflow-y-auto에 min-h-215가 꽉 차면, React의 flexbox 스크롤-중첩 문제와 마찬가지로 콘텐츠 상단이 중앙 기준 스크롤 시작 위치 아래로 내려가서 약관 동의 같은 첫 필드가 보이지 않습니다. React App Router CSS 기반으로 작은 콘텐츠는 여전히 중앙 정렬되도록 외곽은 flex-col overflow-y-auto, 내부 컨테이너는 my-auto를 사용해 보세요.
제안
- <div className="flex min-h-0 flex-1 items-center justify-center overflow-y-auto px-20 py-15 scrollbar-hide">
- <div className="flex min-h-215 w-125">{children}</div>
+ <div className="flex min-h-0 flex-1 flex-col overflow-y-auto px-20 py-15 scrollbar-hide">
+ <div className="flex min-h-full w-full flex-col items-center">
+ <div className="my-auto flex min-h-215 w-full min-w-0 max-w-125">
+ {children}
+ </div>
+ </div>
</div>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <div className="flex min-h-0 flex-1 items-center justify-center overflow-y-auto px-20 py-15 scrollbar-hide"> | |
| <div className="flex min-h-215 w-125">{children}</div> | |
| <div className="flex min-h-0 flex-1 flex-col overflow-y-auto px-20 py-15 scrollbar-hide"> | |
| <div className="flex min-h-full w-full flex-col items-center"> | |
| <div className="my-auto flex min-h-215 w-full min-w-0 max-w-125"> | |
| {children} | |
| </div> | |
| </div> | |
| </div> |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/app/`(auth)/layout.tsx around lines 44 - 45, Update the layout wrapper
around the `{children}` content to separate scrolling from centering: make the
outer container a column-oriented `overflow-y-auto` flex container, and add an
intermediate inner wrapper using `my-auto` for vertical centering. Preserve the
existing padding and child sizing while ensuring oversized content starts at the
top of the scrollable area and smaller content remains centered.
Source: Path instructions
| ], | ||
| }, | ||
| { | ||
| heading: "제4조 (이용자의 의무)", |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
약관 조항 번호를 연속되게 정리해주세요.
제2조 다음이 제4조라서 제3조가 누락된 문서로 보입니다. 법무 승인본 기준으로 제3조를 추가하거나 이후 조항 번호를 재정렬해주세요.
제안
제3조의 실제 승인 문구를 삽입한 뒤, 모든 조항 번호와 내부 참조를 함께 검토해주세요.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/constants/auth/terms.ts` at line 33, Update the terms content around the
제4조 heading so the document follows the legally approved article sequence:
insert the approved 제3조 text, then renumber subsequent headings and update all
internal article references consistently.
| export const PRIVACY_POLICY_CONTENT: TermsContent = { | ||
| title: "IPX 개인정보 처리방침", | ||
| sections: [ | ||
| { | ||
| heading: "1. 수집하는 개인정보 항목", | ||
| paragraphs: ["IPX는 다음과 같은 개인정보를 수집할 수 있습니다."], | ||
| bullets: [ | ||
| "이메일 주소", | ||
| "이름 또는 닉네임", | ||
| "로그인 정보", | ||
| "서비스 이용 기록", | ||
| "접속 로그 및 기기 정보", | ||
| ], | ||
| }, | ||
| { | ||
| heading: "2. 개인정보 수집 목적", | ||
| paragraphs: ["수집한 개인정보는 다음 목적을 위해 사용됩니다."], | ||
| bullets: [ | ||
| "회원 식별 및 계정 관리", | ||
| "서비스 제공 및 운영", | ||
| "사용자 문의 대응", | ||
| "서비스 개선 및 통계 분석", | ||
| "부정 이용 방지", | ||
| ], | ||
| }, | ||
| { | ||
| heading: "3. 개인정보 보관 및 이용 기간", | ||
| paragraphs: [ | ||
| "개인정보는 회원 탈퇴 시까지 보관하며, 관련 법령에 따라 일정 기간 보관이 필요한 경우 해당 기간 동안 보관됩니다.", | ||
| ], | ||
| }, | ||
| { | ||
| heading: "4. 개인정보 제3자 제공", | ||
| paragraphs: [ | ||
| "IPX는 이용자의 개인정보를 외부에 제공하지 않습니다. 단, 법령에 따른 요청이 있는 경우 예외로 합니다.", | ||
| ], | ||
| }, | ||
| { | ||
| heading: "5. 개인정보 보호", | ||
| paragraphs: ["IPX는 개인정보 보호를 위해 합리적인 보안 조치를 시행합니다."], | ||
| }, | ||
| { | ||
| heading: "6. 이용자의 권리", | ||
| paragraphs: ["이용자는 언제든지 자신의 개인정보를 조회, 수정, 삭제 요청할 수 있습니다."], | ||
| }, | ||
| { | ||
| heading: "7. 개인정보처리방침 변경", | ||
| paragraphs: ["본 방침은 변경될 수 있으며, 변경 시 서비스 내 공지합니다."], | ||
| }, | ||
| ], | ||
| }; |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== Locate terms file =="
git ls-files | rg '(^|/)terms\.ts$|(^|/)auth/' || true
echo "== terms.ts outline/section =="
if [ -f src/constants/auth/terms.ts ]; then
wc -l src/constants/auth/terms.ts
sed -n '1,180p' src/constants/auth/terms.ts
fi
echo "== Search for terms component usages and consent UI =="
rg -n "PRIVACY_POLICY_CONTENT|TermsContent|Terms|개인정보처리방침|개인정보 처리방침|동의" src -S || trueRepository: CEOS-IPX/IPX-FE
Length of output: 9316
🌐 Web query:
개인정보 보호법 제30조 개인정보 처리방침 공개 항목 파기 방법 권리행사 방법 보호책임자 연락처
💡 Result:
개인정보 보호법 제30조는 개인정보처리자가 수립하여 공개해야 하는 개인정보 처리방침의 필수 포함 항목을 규정하고 있습니다[1][2]. 요청하신 항목들에 대한 법적 근거와 세부 내용은 다음과 같습니다. 1. 개인정보의 파기 절차 및 방법 개인정보 처리방침에는 개인정보의 파기 절차 및 파기 방법이 포함되어야 합니다[1][3]. 다만, 다른 법령에 따라 개인정보를 보존해야 하는 경우에는 그 보존 근거와 보존하는 개인정보 항목을 함께 명시해야 합니다[1]. 파기 시에는 복구 또는 재생되지 않도록 조치해야 하며, 보존이 필요한 경우에는 다른 개인정보와 분리하여 저장·관리해야 합니다[4]. 2. 정보주체의 권리·의무 및 행사 방법 개인정보 처리방침에는 정보주체와 법정대리인의 권리 및 의무와 그 행사 방법에 관한 사항을 포함해야 합니다[5][1]. 정보주체는 개인정보의 열람, 정정, 삭제, 처리 정지 등을 요구할 수 있으며, 이러한 권리 행사를 위한 구체적인 신청 방법(이메일, 서면, 전화 등)을 안내해야 합니다[2]. 3. 개인정보 보호책임자의 연락처 개인정보 처리방침에는 개인정보 보호책임자의 성명, 또는 개인정보 보호업무 및 관련 고충사항을 처리하는 부서의 명칭과 전화번호 등 연락처를 기재해야 합니다[1][3]. 개인정보 처리방침은 정보주체가 쉽게 확인할 수 있도록 홈페이지 등에 지속적으로 게재하는 등 대통령령으로 정하는 방법에 따라 공개해야 합니다[6]. 해당 항목 누락 시 과태료 등의 행정 처분 대상이 될 수 있으므로 주의가 필요합니다[2].
Citations:
- 1: https://casenote.kr/%EB%B2%95%EB%A0%B9/%EA%B0%9C%EC%9D%B8%EC%A0%95%EB%B3%B4_%EB%B3%B4%ED%98%B8%EB%B2%95/%EC%A0%9C30%EC%A1%B0
- 2: https://k-incorp.org/blog/corporate-privacy-policy-writing-guide-2026
- 3: https://itwiki.kr/w/%EA%B0%9C%EC%9D%B8%EC%A0%95%EB%B3%B4_%EB%B3%B4%ED%98%B8%EB%B2%95_%EC%A0%9C30%EC%A1%B0
- 4: http://www.law.go.kr/LSW/lsLinkProc.do?chrClsCd=010202&datClsCd=010102&gubun=admRul&joNo=002100000%5E003700004&lsId=2073298&lsNm=%EA%B0%9C%EC%9D%B8%EC%A0%95%EB%B3%B4%EB%B3%B4%ED%98%B8%EB%B2%95&mode=10
- 5: https://www.law.go.kr/LSW/lsLinkCommonInfo.do?ancYnChk=&chrClsCd=010202&lsJoLnkSeq=1020398435
- 6: https://platum.kr/archives/203619
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== App Router docs availability =="
find node_modules/next/dist/docs -maxdepth 3 -type d 2>/dev/null | sort | head -80 || true
echo "== Next docs files related to layout/page/rsc/server components =="
find node_modules/next/dist/docs -maxdepth 3 -type f 2>/dev/null | sort | rg 'page|layout|array|client|server|next' | head -120 || true
echo "== Next docs excerpt search for Server Components / App Router =="
python3 - <<'PY'
from pathlib import Path
p=Path('node_modules/next/dist/docs')
if not p.exists():
print('node_modules/next/dist/docs not found')
else:
hits=0
for q in ['RSC', 'server components', 'Server Components', 'App Router', 'app router']:
for file in sorted(p.rglob('*')):
if file.is_file():
try:
txt=file.read_text(errors='ignore')
except Exception:
continue
for i,line in enumerate(txt.splitlines(),1):
if q in line:
print(f'[{file}:{i}] {line.strip()}')
hits += 1
if hits >= 40:
break
if hits >= 40:
break
print('total hits', hits)
PYRepository: CEOS-IPX/IPX-FE
Length of output: 21986
🌐 Web query:
site:law.go.kr 개인정보보호법 제30조 개인정보처리방침공개 항목 삭제 방법 보존 기간 연락처
💡 Result:
개인정보보호법 제30조(개인정보 처리방침의 수립 및 공개)에 따라 개인정보처리자는 반드시 개인정보 처리방침을 수립하여 공개해야 하며, 법령에서 요구하는 필수 기재 항목을 임의로 삭제하거나 누락할 수 없습니다 [1]. 개인정보 처리방침의 주요 기재 항목 및 관리 방법은 다음과 같습니다. 1. 필수 기재 항목 관리 법령에 따라 개인정보 처리방침에는 개인정보의 처리 목적, 개인정보의 처리 및 보유 기간, 개인정보의 제3자 제공, 위탁, 정보주체의 권리·의무 및 행사 방법, 인터넷 접속정보파일(쿠키 등)의 수집 및 거부 등에 관한 사항이 포함되어야 합니다 [1]. 이러한 항목들은 정보주체의 알 권리를 보장하기 위한 법적 의무 사항이므로, 법령상 기재가 요구되는 항목을 임의로 삭제하는 방법은 존재하지 않습니다 [1]. 2. 보존 기간 설정 개인정보의 보유 및 이용 기간은 원칙적으로 개인정보의 수집 및 이용 목적이 달성된 때까지입니다 [1][2]. 다만, 다른 법령에서 별도의 보존 기간을 명시하고 있거나 정보주체의 별도 동의를 받은 경우에는 해당 기간 동안 보존할 수 있습니다 [2]. 개인정보처리자는 처리방침에 해당 기간을 명확히 기재해야 합니다 [1]. 3. 연락처 및 책임자 기재 개인정보 처리방침에는 개인정보 보호책임자의 성명 또는 개인정보 보호업무 관련 부서의 명칭과 전화번호 등 연락처를 포함하여 정보주체가 쉽게 연락할 수 있도록 안내해야 합니다 [1]. 4. 수정 및 변경 절차 개인정보 처리방침의 내용이 변경되는 경우(항목 추가, 삭제, 정정 등), 정보주체가 쉽게 확인할 수 있도록 변경 시행 7일 전부터 공지사항 등을 통해 고지해야 합니다 [3]. 결론적으로, 법적 필수 기재 항목을 삭제하는 방법은 없으며, 운영 목적의 변화에 따라 항목을 수정하거나 최신화해야 하는 경우 관련 법령 준수 여부를 확인한 후 적법한 공지 절차를 거쳐 반영해야 합니다 [1][3]. 구체적인 작성 및 수정 시에는 개인정보보호위원회가 제공하는 개인정보 처리방침 작성지침을 참고하시기 바랍니다 [1].
Citations:
- 1: https://www.law.go.kr/LSW/lsLinkCommonInfo.do?ancYnChk=&chrClsCd=010202&lsJoLnkSeq=1020398435
- 2: http://www.law.go.kr/LSW/lsLawLinkInfo.do?chrClsCd=010202&lsJoLnkSeq=900079620
- 3: https://www.law.go.kr/LSW/flDownload.do?bylClsCd=200201&flNm=%5B%EB%B3%84%ED%91%9C+1%5D+%EA%B0%9C%EC%9D%B8%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EB%B0%A9%EC%B9%A8+%28%EC%98%88%EC%8B%9C%29&flSeq=133015775
개인정보 처리방침의 필수 고지 항목을 추가해주세요.
PRIVACY_POLICY_CONTENT는 수집·보관·제3자 제공·권리·변경 항목은 있지만, src/app/(auth)/signup의 필수 동의 흐름에서 사용자에게 알리기 insufficient합니다. 개인정보 보호법 제30조가 요구하는 파기 절차·방법, 권리 행사 방법 및 접수처, 보호책임자·고충처리 연락처를 누락하지 말고 실제 운영과 일치하는 위탁/제3자 제공 항목도 명시해주세요.
제안
- 보존 기간은 탈퇴일 기준 외에 법령 의무 보존대상은 항목별 기간과 근거를 함께 표기해주세요.
- 권리 요청 절차는 이메일·전화·서면 등 실제 접수처를 넣어야 합니다.
- 외부 인증·분석·호스팅 등 실제로 이용하는 서비스라면 위탁자의 명칭·목적·제공 항목을 고지하거나, 운영상 사실과 다르면 문구를 맞췄어야 합니다.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/constants/auth/terms.ts` around lines 72 - 122, Expand
PRIVACY_POLICY_CONTENT to include the required privacy-notice details: itemized
retention periods with legal bases, destruction procedures and methods, concrete
rights-exercise channels and receiving contact, and the privacy
officer/grievance contact. Audit the signup flow’s actual authentication,
analytics, hosting, and other vendors, then accurately document each processor
or third-party recipient, purpose, and data categories; keep the notice aligned
with real operations.
[CHORE] ui 수정 및 원문보기 연결
📌 작업 내용
✅ 변경 사항
🔗 관련 이슈
Closes #7
Closes #10
Closes #14
Closes #21
🧪 체크리스트
📸 스크린샷
없음
💬 리뷰 요청 사항
기타
Summary by CodeRabbit