Frontend Migration
NiceGUI 서버사이드 UI를 Next.js 클라이언트사이드로 점진 전환하는 프로젝트입니다.
기존 NiceGUI(18080)와 FastAPI(8600)는 그대로 유지하며, 페이지 단위로 하나씩 Next.js(18081)로 이전합니다.
왜 전환하는가
| 항목 | NiceGUI (현재) | Next.js (전환) |
|---|---|---|
| 렌더링 | 서버사이드 (Python → Quasar) | 클라이언트사이드 (React) |
| 상태 관리 | 서버 메모리 (세션별) | 브라우저 (localStorage + React state) |
| 연결 방식 | WebSocket 상시 연결 | HTTP (REST API 호출) |
| 확장성 | 싱글 프로세스, 수직만 | 무상태, 수평 확장 가능 |
| 빌드/배포 | Python 프로세스 | 정적 빌드 + CDN 가능 |
| 개발 생산성 | Python UI 코드 | React 생태계 + TypeScript |
전환 전략
점진적 전환 (Strangler Fig 패턴)
NiceGUI를 한 번에 끄지 않고, 페이지 단위로 Next.js에 구현한 뒤 트래픽을 이전합니다. 모든 페이지가 전환 완료되면 NiceGUI를 종료합니다. FastAPI 백엔드(8600)는 변경 없이 그대로 공유합니다.
셋업 + 인증 + 대시보드
프로젝트 셋업, 로그인, 레이아웃(사이드바+헤더), 대시보드 페이지. 나머지는 스텁.
핵심 Studio 페이지
이상 목록, 규칙 관리, 감지 로그, 플레이북/진단/액션/검증 Studio.
AI Chat + 도구
AI Chat (SSE 스트리밍), Tool Studio, 지식베이스, 질문 흐름, 매크로.
관리 + Agent 페이지
사용자/설정/활동로그/LLM사용량 + 4 AI Agent 채팅 페이지.
파이프라인 + 나머지
파이프라인 모니터, 테이블 이관, 채팅 이력, 도구 요청.
NiceGUI 종료
전체 전환 완료 확인 후 NiceGUI 프로세스 제거. 18080 포트 해제.
시스템 구조
rewrites로 /api/* 요청을 FastAPI(8600)로 프록시하므로 CORS 설정 불필요.
두 프론트엔드가 동일한 백엔드를 공유합니다.
포트 할당
API 프록시
next.config.ts의 rewrites로 모든 API 호출을 FastAPI로 전달합니다.
// next.config.ts
const nextConfig: NextConfig = {
async rewrites() {
return [{
source: "/api/:path*",
destination: `${process.env.NEXT_PUBLIC_API_URL}/api/:path*`,
}];
},
};왜 rewrites인가?
브라우저 → Next.js(18081) → FastAPI(8600) 프록시로 동작하므로 CORS 헤더 설정이 필요 없고, 쿠키도 same-origin으로 자연스럽게 전달됩니다. 프로덕션에서는 Nginx/Cloudflare에서 경로 기반 라우팅으로 교체 가능합니다.
인증 흐름
nav 배열을 사이드바가 그대로 렌더링합니다.
역할별 접근 권한 필터링은 백엔드(get_nav_items())에서 완료됩니다.
Phase 1 범위
- 프로젝트 셋업 — Next.js 15 + TypeScript + Tailwind v4 + Recharts + Lucide React
- 테마 + 상수 — CSS 변수(라이트/다크), 글래스모피즘, 아이콘 매핑, 색상 상수
- API 클라이언트 — fetch 래퍼 (Bearer 자동 첨부, 401 리다이렉트, 타입 제네릭)
- 인증 + 테마 — AuthProvider (localStorage), ThemeProvider (dark 클래스 토글)
- 로그인 페이지 — 글래스모피즘 로그인 카드 + 에러 표시
- 레이아웃 셸 — 사이드바(240px, 그룹 접기/펼치기) + 헤더(50px, 헬스점, 테마토글)
- 대시보드 — KPI 4행 + 도넛 차트 + 최근 이상 + 인기 도구 + 카테고리별 이상
디렉토리 구조
기술 스택
| 항목 | 선택 | 이유 |
|---|---|---|
| 프레임워크 | Next.js 15 (App Router) | 파일 기반 라우팅, 정적 빌드 지원 |
| UI | React 19 | 생태계 + 인력 풀 |
| 언어 | TypeScript | 타입 안전성 |
| 스타일 | Tailwind CSS v4 | 유틸리티 우선, CSS 변수 네이티브 |
| 차트 | Recharts | React 네이티브, 도넛/바/라인 지원 |
| 아이콘 | Lucide React | Material Icons 대체, 트리셰이킹 |
| 빌드 | Turbopack | HMR 속도 개선 |
테마 설계
라이트 기본 + 다크 전환
<html> 클래스에 dark 추가/제거로 전환합니다.
CSS 변수가 자동으로 전환되어 모든 컴포넌트에 반영됩니다.
사용자 선택은 localStorage "flopi_theme"에 저장됩니다.
/* globals.css */
@custom-variant dark (&:where(.dark, .dark *));
:root {
--flopi-bg: #f8fafc;
--flopi-card: rgba(255,255,255,0.85);
--flopi-primary: #059669;
--flopi-text: #1f2937;
}
.dark {
--flopi-bg: #030712;
--flopi-card: rgba(17,24,39,0.6);
--flopi-primary: #10b981;
--flopi-text: #f3f4f6;
}글래스모피즘
NiceGUI의 .glass-card 스타일을 CSS 변수 기반으로 재구현했습니다.
.glass-card {
background: var(--flopi-card);
backdrop-filter: blur(16px) saturate(180%);
border: 1px solid var(--flopi-border);
border-radius: 16px;
box-shadow: 0 1px 3px rgba(0,0,0,0.06);
}대시보드
NiceGUI 대시보드와 동일한 구조를 React로 재현합니다.
| 섹션 | API | 컴포넌트 |
|---|---|---|
| 시스템 개요 | /api/dashboard/overview | KpiCard × 4 |
| 플랫폼 활동 | /api/dashboard/platform-stats | KpiCard × 5 |
| AI 엔진 | /api/dashboard/platform-stats | KpiCard × 3 |
| 도구 요청 | /api/tool-requests/stats | KpiCard × 4 |
| 인기 도구 | /api/dashboard/platform-stats | 리스트 |
| 카테고리별 이상 | /api/dashboard/platform-stats | 리스트 |
| 상태 분포 | /api/dashboard/overview | 도넛 차트 (Recharts) |
| 최근 이상 | /api/anomalies?limit=5 | GlassCard + Badge |
전체 페이지 목록 (25개)
| 경로 | 페이지 | 그룹 | 상태 |
|---|---|---|---|
/ | 대시보드 | - | 완료 |
/pipeline-monitor | 파이프라인 | - | 스텁 |
/ai-chat | AI Chat | - | 스텁 |
/tool-studio | 도구 | - | 스텁 |
/knowledge-base | 지식베이스 | - | 스텁 |
/question-flows | 질문 흐름 | - | 스텁 |
/chat-scenarios | 매크로 | - | 스텁 |
/anomalies | 이상 목록 | 이상감지 | 스텁 |
/logs | 감지 로그 | 이상감지 | 스텁 |
/rules | 규칙 관리 | 이상감지 | 스텁 |
/agent/sentinel | Sentinel | 이상감지 | 스텁 |
/playbook-studio | 플레이북 | 원인분석 | 스텁 |
/diagnosis-studio | 진단 케이스 | 원인분석 | 스텁 |
/agent/diagnostician | Diagnostician | 원인분석 | 스텁 |
/action-studio | 액션 | 조치 제안 | 스텁 |
/agent/advisor | Advisor | 조치 제안 | 스텁 |
/validation-studio | 검증 | 대안 검증 | 스텁 |
/agent/validator | Validator | 대안 검증 | 스텁 |
/chat-history | 채팅 이력 | 관리 | 스텁 |
/tool-requests | 도구 요청 | 관리 | 스텁 |
/llm-usage | LLM 사용량 | 관리 | 스텁 |
/activity-log | 활동 로그 | 관리 | 스텁 |
/users | 사용자 관리 | 관리 | 스텁 |
/system-settings | 설정 | 관리 | 스텁 |
/migration | 테이블 이관 | 관리 | 스텁 |
페이지 추가 방법
스텁 페이지를 실제 구현으로 전환하는 절차입니다.
-
API 타입 추가 —
lib/types.ts에 해당 페이지의 API 응답 타입을 정의합니다. -
API 함수 추가 —
lib/api.ts에 fetch 래퍼 함수를 추가합니다. 경로는/api/...로 시작하면 자동 프록시됩니다. -
컴포넌트 작성 — 필요한 컴포넌트를
components/에 추가합니다. 기존GlassCard,KpiCard,SeverityBadge등을 재활용하세요. -
페이지 구현 —
app/(dashboard)/경로/page.tsx의 스텁을 실제 코드로 교체합니다."use client"디렉티브를 유지하고,useAuth()로 사용자 정보를 접근합니다. -
테스트 —
npm run dev로 확인 후npm run build로 빌드 검증합니다.
페이지 코드 템플릿
"use client";
import { useEffect, useState } from "react";
import GlassCard from "@/components/GlassCard";
import EmptyState from "@/components/EmptyState";
export default function MyPage() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch("/api/my-endpoint")
.then(res => res.json())
.then(setData)
.finally(() => setLoading(false));
}, []);
if (loading) return <Spinner />;
return (
<div className="space-y-6 animate-in">
<h1 className="text-xl font-bold"
style={{ color: "var(--flopi-text)" }}>
페이지 제목
</h1>
<GlassCard>
{data ? <Content /> : <EmptyState message="데이터 없음" />}
</GlassCard>
</div>
);
}코딩 규칙
| 항목 | 규칙 |
|---|---|
| 컴포넌트 | PascalCase, "use client" 디렉티브 필수 |
| 스타일 | Tailwind 유틸리티 + CSS 변수 (var(--flopi-*)) |
| 색상 | 하드코딩 금지 — 반드시 CSS 변수 또는 constants.ts 사용 |
| API 호출 | lib/api.ts의 래퍼 함수 사용 (직접 fetch 금지) |
| 인증 | useAuth() 훅으로 접근, 직접 localStorage 접근 금지 |
| 테마 | useTheme() 훅, .dark variant 사용 |
| 아이콘 | Lucide React, constants.ts의 ICON_MAP 참조 |
| 타입 | lib/types.ts에 정의, any 금지 |
| ���러 처리 | API 실패 시 빈 상태 표시 (EmptyState), 페이지 크래시 방지 |
개발 서버
# 의존성 설치
cd FLOPI/frontend && npm install
# 개발 서버 (포트 18081, Turbopack)
npm run dev
# 빌드 검증
npm run build
# 프로덕션 실행
npm run startlocalhost:8600에서 실행 중이어야 합니다.
API 프록시가 동작하지 않으면 로그인 및 데이터 로딩이 실패합니다.
검증 체크리스트
| # | 항목 | 확인 |
|---|---|---|
| 1 | /login → 로그인 폼 표시 | admin / fab-admin |
| 2 | 로그인 성공 → / 대시보드 리다이렉트 | |
| 3 | 사이드바 25개 네비게이션 표시 | |
| 4 | 헤더 헬스 점 녹색 (30초 폴링) | |
| 5 | 다크/라이트 토글 동작 | |
| 6 | 대시보드 KPI + 도넛차트 표시 | |
| 7 | 로그아웃 → /login 리다이렉트 | |
| 8 | NiceGUI(18080) 정상 동작 확인 |