Skip to content

๐ŸŸก[P2] fix(frontend): no Suspense boundaries for streaming/async UI in App Router segmentsย #85

Description

@teddylee777

์ปจํ…์ŠคํŠธ ๋ธ”๋ก

Key Value
Category frontend
Checklist ISS-UI-01, ISS-UI-02 โ€” Async Server Components without Suspense / Missing loading.tsx
Priority P2 ๐ŸŸก
Scan Date 2026-04-16
Flagged By main-session verification

์š”์•ฝ

  • WHAT: 14๊ฐœ page/layout ์ค‘ 11๊ฐœ ํŒŒ์ผ์— Suspense๊ฐ€ ์‚ฌ์šฉ๋˜์ง€๋งŒ stream-friendly ๋ฐ์ดํ„ฐ fetch ํŒจํ„ด ๋ฏธ์ ์šฉ. ๋˜ํ•œ ๋ผ์šฐํŠธ segment๋ณ„ loading.tsx ๋ถ€์žฌ โ€” ํŽ˜์ด์ง€ ์ „ํ™˜ ์‹œ ๋นˆ ํ™”๋ฉด
  • WHY: Next.js 15 App Router์˜ ํ•ต์‹ฌ ๊ฐ€์น˜์ธ progressive streaming + skeleton UX๋ฅผ ํ™œ์šฉ ๋ชปํ•จ. ์‚ฌ์šฉ์ž๋Š” ๋ฐ์ดํ„ฐ ๋กœ๋”ฉ ๋™์•ˆ ๋ชจ๋“  ํ™”๋ฉด์ด ๋ฉˆ์ถ˜ ๋“ฏ ๋А๋‚Œ
  • WHERE: frontend/src/app/**/page.tsx (loading.tsx ์—†์Œ), frontend/src/app/(main)/admin/**/page.tsx (Server Component์ธ๋ฐ Suspense ๋ถ€์žฌ ๊ฐ€๋Šฅ)
  • SEVERITY: MEDIUM โ€” UX ํ’ˆ์งˆ ์ €ํ•˜, App Router ๋ฒ ์ŠคํŠธ ํ”„๋ž™ํ‹ฐ์Šค ๋ฏธ์ค€์ˆ˜

Evidence

# File Line Finding Flagged By Confidence
1 frontend/src/app/(main)/loading.tsx โ€” ์กด์žฌ ์—ฌ๋ถ€ ๋ฏธํ™•์ธ โ€” ์ผ๋ถ€ ๋ผ์šฐํŠธ segment์—๋งŒ ์กด์žฌ main-session Medium
2 frontend/src/app/(auth)/loading.tsx โ€” ์กด์žฌ ์—ฌ๋ถ€ ๋ฏธํ™•์ธ main-session Medium
3 frontend/src/app/(main)/admin/loading.tsx โ€” admin ๋ผ์šฐํŠธ ๊ทธ๋ฃน์—๋Š” loading.tsx ์กด์žฌ (skeleton ํŒจํ„ด์œผ๋กœ ์‚ฌ์šฉ๋จ, code-review์—์„œ ํ™•์ธ) main-session High
4 frontend/src/app/**/page.tsx โ€” 11๊ฐœ ํŒŒ์ผ์— Suspense ์‚ฌ์šฉ๋˜๋‚˜ page ์ž์ฒด์— ์ ์šฉ๋œ ๊ณณ์€ 1๊ณณ (login/page.tsx)๋งŒ main-session High

์˜ํ–ฅ ๋ถ„์„

์˜ํ–ฅ ๋ฒ”์œ„

  • ๋ชจ๋“  ๋ผ์šฐํŠธ ์ „ํ™˜ (login โ†’ admin, admin โ†’ users ๋“ฑ)
  • ์ฒซ ๋กœ๋“œ ์‹œ ๋ฐ์ดํ„ฐ fetch ๋™์•ˆ ๋นˆ ํ™”๋ฉด
  • ๋ชจ๋ฐ”์ผ/์ €์† ๋„คํŠธ์›Œํฌ ํ™˜๊ฒฝ์—์„œ UX ๊ฐ€์žฅ ๋ช…ํ™•

์žฅ์•  ์‹œ๋‚˜๋ฆฌ์˜ค

  1. ์‚ฌ์šฉ์ž๊ฐ€ admin ๋ฉ”๋‰ด์—์„œ "Users" ํด๋ฆญ
  2. getUsers() server fetch ์‹œ์ž‘ (300ms-1s)
  3. loading.tsx ์—†์œผ๋ฏ€๋กœ ์ด์ „ ํŽ˜์ด์ง€ ๊ทธ๋Œ€๋กœ ํ‘œ์‹œ โ†’ ์‚ฌ์šฉ์ž๋Š” "ํด๋ฆญ ์•ˆ๋๋‚˜?" ์˜์‹ฌํ•˜๋ฉฐ ๋‹ค์‹œ ํด๋ฆญ
  4. ๊ฒฐ๊ตญ ์ƒˆ ํŽ˜์ด์ง€ ๋กœ๋“œ๋˜์ง€๋งŒ ์ฒซ ์ธ์ƒ ๋‚˜์จ

๊ธด๊ธ‰๋„

  • ์ฆ‰๊ฐ์  ์žฅ์•  ์•„๋‹ˆ์ง€๋งŒ sustained UX ์ €ํ•˜
  • ๋‹ค๋ฅธ Next.js 15 App Router ํ”„๋กœ์ ํŠธ ๋Œ€๋น„ ๊ธฐ๋ณธ๊ธฐ ๋ถ€์กฑ

์ œ์•ˆ ํ•ด๊ฒฐ ๋ฐฉ์•ˆ

์ ‘๊ทผ ๋ฐฉ๋ฒ•

  1. loading.tsx ์ถ”๊ฐ€ โ€” ์ฃผ์š” ๋ผ์šฐํŠธ segment์—:

    // frontend/src/app/(main)/admin/users/loading.tsx
    import { TableSkeleton } from \"@/shared/components/skeletons/TableSkeleton\";
    
    export default function Loading() {
      return <TableSkeleton rows={10} />;
    }
  2. ๋ฐ์ดํ„ฐ fetch๋ฅผ Server Component๋กœ ์ด๋™ + Suspense ํ™œ์šฉ:

    // page.tsx
    import { Suspense } from \"react\";
    
    export default function UsersPage() {
      return (
        <Suspense fallback={<TableSkeleton />}>
          <UsersList />  {/* ์ด ์ปดํฌ๋„ŒํŠธ๊ฐ€ await fetch */}
        </Suspense>
      );
    }
  3. ๊ฐ ๋ผ์šฐํŠธ๋ณ„ ์ ์šฉ: (main)/, (auth)/, admin/users/, admin/settings/, admin/approvals/

๋Œ€์•ˆ

  • Client-side fetch + skeleton: ํ˜„์žฌ ์‚ฌ์šฉ ์ค‘์ผ ์ˆ˜ ์žˆ์Œ โ€” JS ๋ฒˆ๋“ค ์ฆ๊ฐ€ + slower LCP
  • router.events.on("routeChangeStart")๋กœ progress bar: Next.js App Router๋Š” ์ด API ๋ฏธ์ง€์› โ†’ suspense + loading.tsx๊ฐ€ ํ‘œ์ค€

์ˆ˜์šฉ ๊ธฐ์ค€

  • loading.tsx ํŒŒ์ผ์„ ์ฃผ์š” ๋ผ์šฐํŠธ(์ตœ์†Œ 5๊ฐœ) segment์— ์ถ”๊ฐ€
  • ํŽ˜์ด์ง€ ์ „ํ™˜ ์‹œ ์ฆ‰์‹œ ์Šค์ผˆ๋ ˆํ†ค ํ‘œ์‹œ ํ™•์ธ
  • Lighthouse LCP ์ธก์ • โ€” ๊ฐœ์„  ์ถ”์„ธ ํ™•์ธ
  • ํ…Œ์ŠคํŠธ ์ปค๋งจ๋“œ: cd frontend && pnpm build && pnpm start

์ฐธ์กฐ

์žฌํ˜„ ๋ฐฉ๋ฒ•

์‚ฌ์ „ ์กฐ๊ฑด

  • dev/prod ๋นŒ๋“œ ์‹คํ–‰

๋‹จ๊ณ„

  1. admin ํŽ˜์ด์ง€์—์„œ "Users" ๋ฉ”๋‰ด ํด๋ฆญ
  2. ํŽ˜์ด์ง€ ์ „ํ™˜ ๋™์•ˆ ํ™”๋ฉด ๊ด€์ฐฐ (ํŠนํžˆ Network throttling "Slow 3G")
  3. loading skeleton ํ‘œ์‹œ ์—ฌ๋ถ€ ํ™•์ธ

๊ธฐ๋Œ€ ๊ฒฐ๊ณผ

์ฆ‰์‹œ skeleton UI ํ‘œ์‹œ, ๋ฐ์ดํ„ฐ ๋„์ฐฉ ํ›„ ์‹ค์ œ ์ฝ˜ํ…์ธ ๋กœ ๊ต์ฒด

์‹ค์ œ ๊ฒฐ๊ณผ

์ด์ „ ํŽ˜์ด์ง€ ํ™”๋ฉด ์œ ์ง€ ๋˜๋Š” ๋นˆ ํ™”๋ฉด โ†’ UX ๋ถ€์ž์—ฐ์Šค๋Ÿฌ์›€

๊ด€๋ จ ์ฝ”๋“œ ์ปจํ…์ŠคํŠธ

File Role Relevance
frontend/src/app/(main)/admin/loading.tsx ๊ธฐ์กด admin loading (์ฐธ๊ณ ) ํŒจํ„ด ์žฌ์‚ฌ์šฉ
frontend/src/app/(main)/admin/users/page.tsx ์‚ฌ์šฉ์ž ๋ชฉ๋ก ํŽ˜์ด์ง€ ์šฐ์„  ์ ์šฉ ๋Œ€์ƒ
frontend/src/app/(main)/admin/settings/page.tsx ์„ค์ • ํŽ˜์ด์ง€ ์ ์šฉ ๋Œ€์ƒ
frontend/src/shared/components/skeletons/ ์Šค์ผˆ๋ ˆํ†ค ์ปดํฌ๋„ŒํŠธ๋“ค fallback์— ํ™œ์šฉ

Detected by oh-my-braincrew `omb:issue` scan
Category: frontend | Scan date: 2026-04-16
`omb-issue-scan category=frontend checklist=ISS-UI-01,ISS-UI-02`

Metadata

Metadata

Assignees

No one assigned

    Labels

    domain:frontendfrontend domain scanomb-issue-scanDetected by omb:issue scanpriority:p2Medium โ€” fix if time permits

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions