diff --git a/solution/frontend/src/app/router.tsx b/solution/frontend/src/app/router.tsx
index f8f6066..2621c72 100644
--- a/solution/frontend/src/app/router.tsx
+++ b/solution/frontend/src/app/router.tsx
@@ -32,12 +32,18 @@ function Home() {
);
}
- if (user) return ;
+ /*
+ * ★ 로그인해도 랜딩을 보여 준다 (2026-09-04, 사장님 지적)
+ * 예전엔 여기서 /sites 로 튕겼다. 그러면 **로그인한 사장님은 랜딩·요금에 갈 길이 없다** —
+ * 로고가 '/' 를 걸고 있어도 눌리는 순간 목록으로 돌아온다.
+ * "로그인 직후엔 내 사이트로" 는 로그인·가입 화면이 직접 보낸다(LoginPage homePath).
+ */
+ void user;
return ;
}
export const router = createBrowserRouter([
- {path: '/login', element: },
+ {path: '/login', element: },
// 로그인 화면의 [회원가입] 이 여기로 온다. 이 줄이 없으면 링크는 있고 목적지만 404 다.
{path: '/signup', element: },
diff --git a/solution/frontend/src/components/layout/AppShell.tsx b/solution/frontend/src/components/layout/AppShell.tsx
index 990aba0..8fa7763 100644
--- a/solution/frontend/src/components/layout/AppShell.tsx
+++ b/solution/frontend/src/components/layout/AppShell.tsx
@@ -1,6 +1,6 @@
import type {ComponentType, ReactNode} from 'react';
import {Link, NavLink, useLocation, useNavigate} from 'react-router';
-import {LayoutGrid, LogIn, LogOut, Search, Store, Wand2} from 'lucide-react';
+import {LayoutGrid, LogIn, LogOut, Receipt, Search, Store, Wand2} from 'lucide-react';
import {cn} from '@/lib/utils';
import {userLabel, useAuthStore} from '@/stores/auth';
@@ -25,6 +25,15 @@ export type NavItem = {
const OWNER_NAV: NavItem[] = [
{to: '/sites', match: '/sites', label: '내 사이트', icon: Store},
{to: '/builder?new=1', match: '/builder', label: '새 사이트', icon: Wand2},
+ /*
+ * ★ 요금은 **로그인한 뒤에도** 갈 길이 있어야 한다 (2026-09-04, 사장님 지적)
+ * /pricing 은 살아 있는데 링크가 MarketingShell 과 랜딩에만 있었다. 둘 다 로그인하면
+ * 안 보이는 화면이라(로그인하면 / 가 /sites 로 간다), 사장님은 주소를 직접 쳐야 했다.
+ * 요금은 쓰는 도중에 확인하는 값이지 가입 전에만 보는 값이 아니다.
+ * ★ 목적지가 MarketingShell(사이드바 없는 문서형)이라 사이드바가 사라진다. 그래도 갇히지
+ * 않는다 — 저쪽 헤더가 로그인 상태를 알아보고 [내 사이트] 버튼을 세운다.
+ */
+ {to: '/pricing', match: '/pricing', label: '요금', icon: Receipt},
];
export function AppShell({children, nav = OWNER_NAV}: {children: ReactNode; nav?: NavItem[]}) {
@@ -87,7 +96,8 @@ export function AppShell({children, nav = OWNER_NAV}: {children: ReactNode; nav?
// 눌러도 아무 일이 없는 것처럼 보인다 — 로그인 화면으로 보낸다.
onClick={() => {
signOut();
- navigate('/login');
+ // ★ 로그인 화면이 아니라 랜딩으로. 나간 사람에게 다시 로그인 폼을 들이밀지 않는다.
+ navigate('/');
}}
className="flex w-full cursor-pointer items-center gap-1.5 rounded-md px-2 py-1.5 text-xs text-sidebar-foreground transition-colors hover:bg-sidebar-accent/60"
>
diff --git a/solution/frontend/src/components/layout/MarketingShell.tsx b/solution/frontend/src/components/layout/MarketingShell.tsx
index e52aa77..2acf72b 100644
--- a/solution/frontend/src/components/layout/MarketingShell.tsx
+++ b/solution/frontend/src/components/layout/MarketingShell.tsx
@@ -47,6 +47,11 @@ export function MarketingShell({children}: {children: ReactNode}) {
{/* ★ 이미 사이트를 가진 사장님에게 [로그인] 을 다시 보여주지 않는다 — 갈 곳은 내 사이트다. */}
+ {/*
+ ★ [무료로 만들기] 를 뺐다 (2026-09-04, 사장님 지시)
+ 히어로의 큰 입력 카드가 이미 그 자리다 — 시작하는 문이 한 화면에 둘이면
+ 어느 쪽이 진짜인지 고르게 만든다. 헤더는 로그인만 받는다.
+ */}
{user ? (
) : (
- <>
- {/* 아임웹처럼 둘 다 버튼이다 — 로그인만 맨 텍스트면 눌리는 것으로 안 보인다. */}
-
- 로그인
-
-
- 무료로 만들기
-
- >
+
+ 로그인
+
)}
diff --git a/solution/frontend/src/pages/LoginPage.tsx b/solution/frontend/src/pages/LoginPage.tsx
index 863eb26..08478b3 100644
--- a/solution/frontend/src/pages/LoginPage.tsx
+++ b/solution/frontend/src/pages/LoginPage.tsx
@@ -17,7 +17,21 @@ import {useAuthStore} from '@/stores/auth';
* 우리가 만들어 준다. 가입 링크를 두 곳에 다 두면 admin 라우터에 없는 `/signup` 으로 보내
* 404 가 난다(admin/src/app/router.tsx 에 그 경로는 없다).
*/
-export function LoginPage({selfServe = true}: {selfServe?: boolean}) {
+export function LoginPage({
+ selfServe = true,
+ homePath = '/',
+}: {
+ selfServe?: boolean;
+ /**
+ * 로그인 직후 도착지.
+ *
+ * ★ 예전엔 '/' 로 보내고 각 앱의 '/' 리다이렉트가 알아서 가르게 했다. 그런데 사장님 앱에서
+ * 그 관문이 **로그인한 사람에게 랜딩을 영영 못 보게** 만들었다 — 로고를 눌러도 '/' 가
+ * /sites 로 튕긴다(사장님 지적). 관문을 걷고 도착지를 여기서 받는다.
+ * ★ 기본값은 '/' 다. 내부 운영 앱은 자기 '/' 가 사업장 목록으로 보내므로 그대로 맞는다.
+ */
+ homePath?: string;
+}) {
const navigate = useNavigate();
const location = useLocation();
const user = useAuthStore((s) => s.user);
@@ -28,9 +42,8 @@ export function LoginPage({selfServe = true}: {selfServe?: boolean}) {
const [password, setPassword] = useState('');
const [isSubmitting, setIsSubmitting] = useState(false);
- // ★ 기본 도착지를 '/' 로 둔다. 앱마다 홈이 다르고(사장님 → 빌더, 내부 → 사업장 목록)
- // 각 라우터의 '/' 리다이렉트가 이미 그걸 안다. 여기 경로를 박으면 한쪽에서 404 다.
- const from = (location.state as {from?: string} | null)?.from ?? '/';
+ // 원래 가려던 곳이 있으면 그리로, 없으면 앱이 준 홈으로.
+ const from = (location.state as {from?: string} | null)?.from ?? homePath;
if (user) return ;
@@ -82,11 +95,10 @@ export function LoginPage({selfServe = true}: {selfServe?: boolean}) {
className="w-full max-w-sm space-y-4 rounded-2xl border border-border bg-card p-7"
>
-
+ {/* 로고는 어디서든 랜딩으로 돌아가는 문이다. 로그인 화면에서 나갈 길이 여기뿐이었다. */}
+
+
+