admin/ 이 프론트 파일만 널려 있는 폴더였다. :9801 을 띄우는 코드도 solution/backend 안에 얹혀 있어서, 폴더만 봐서는 admin 에 백엔드가 있다는 걸 몰랐다. admin/backend/ main.py · app.py (:9801 진입점. 도메인 코드는 PYTHONPATH 로 solution/backend) admin/frontend/ 운영 화면 패키지 이름도 폴더에 맞췄다: @o2o/front → @o2o/frontend. 이미지 빌드 컨텍스트를 레포 루트로 올렸다 — 진입점(admin/)과 도메인 코드(solution/)가 한 이미지에 들어와야 한다. 루트 .dockerignore 로 프론트·문서·시크릿을 잘라냈다. ★ 실측으로 잡은 것: 패키지명을 바꾸면서 compose 의 `-w @o2o/front` 를 안 고쳐 web 컨테이너가 `No workspaces found` 로 재기동 루프에 빠져 있었다. 주석은 짧게 줄였다. 검증: lint·build 6개 전부 0. 컨테이너 5개 엔드포인트(9800·9801·3000·3002·80) 전부 200. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019uYhHQdssRubirPirrdJJC
48 lines
1.8 KiB
TypeScript
48 lines
1.8 KiB
TypeScript
import {Building2, CalendarDays} from 'lucide-react';
|
|
import {createBrowserRouter, Navigate, Outlet} from 'react-router';
|
|
import {AppShell, type NavItem} from '@/components/layout/AppShell';
|
|
import {RequireAuth} from '@/components/layout/RequireAuth';
|
|
import {LocalContentPage} from '@admin/pages/LocalContentPage';
|
|
import {LoginPage} from '@/pages/LoginPage';
|
|
import {NotFoundPage} from '@/pages/NotFoundPage';
|
|
import {PlaceDetailPage} from '@admin/pages/PlaceDetailPage';
|
|
import {PlaceListPage} from '@admin/pages/PlaceListPage';
|
|
import {SeoAuditPage} from '@admin/pages/SeoAuditPage';
|
|
|
|
/**
|
|
* ★ 내부 메뉴는 여기 있다. AppShell(사장님 앱 소유)에 두면 이 경로 이름들이
|
|
* 사장님 번들에 문자열로 남는다 — 앱을 가른 이유가 사라진다.
|
|
*/
|
|
const ADMIN_NAV: NavItem[] = [
|
|
{to: '/places', match: '/places', label: '사업장', icon: Building2},
|
|
{to: '/local-content', match: '/local-content', label: '지역 콘텐츠', icon: CalendarDays},
|
|
];
|
|
|
|
/**
|
|
* 내부 운영 화면. **전부 RequireAuth 뒤에 둔다** — 예외를 하나 두는 순간
|
|
* 그 예외가 기본값이 된다. 사장님 앱과 앱을 가른 이유가 이 규칙을 지키기 위해서다.
|
|
*/
|
|
export const router = createBrowserRouter([
|
|
{path: '/login', element: <LoginPage />},
|
|
|
|
{path: '/', element: <Navigate to="/places" replace />},
|
|
|
|
{
|
|
element: (
|
|
<RequireAuth>
|
|
<AppShell nav={ADMIN_NAV}>
|
|
<Outlet />
|
|
</AppShell>
|
|
</RequireAuth>
|
|
),
|
|
children: [
|
|
{path: '/places', element: <PlaceListPage />},
|
|
{path: '/places/:placeId', element: <PlaceDetailPage />},
|
|
{path: '/places/:placeId/seo', element: <SeoAuditPage />},
|
|
{path: '/local-content', element: <LocalContentPage />},
|
|
],
|
|
},
|
|
|
|
{path: '*', element: <NotFoundPage />},
|
|
]);
|