feat(web): redirect logged-in users from / to /issues via server-side proxy

Use a lightweight cookie (multica_logged_in) + Next.js 16 proxy to
302-redirect authenticated users visiting / straight to /issues.
Unauthenticated visitors (and search engine crawlers) continue to see
the full landing page with zero flash.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Naiyuan Qing 2026-04-01 18:20:57 +08:00
parent 8db970cd17
commit f1e5bc7925
4 changed files with 30 additions and 0 deletions

View file

@ -0,0 +1,9 @@
const COOKIE_NAME = "multica_logged_in";
export function setLoggedInCookie() {
document.cookie = `${COOKIE_NAME}=1; path=/; max-age=31536000; samesite=lax`;
}
export function clearLoggedInCookie() {
document.cookie = `${COOKIE_NAME}=; path=/; max-age=0`;
}

View file

@ -5,6 +5,7 @@ import { useAuthStore } from "./store";
import { useWorkspaceStore } from "@/features/workspace";
import { api } from "@/shared/api";
import { createLogger } from "@/shared/logger";
import { setLoggedInCookie, clearLoggedInCookie } from "./auth-cookie";
const logger = createLogger("auth");
@ -16,6 +17,7 @@ export function AuthInitializer({ children }: { children: ReactNode }) {
useEffect(() => {
const token = localStorage.getItem("multica_token");
if (!token) {
clearLoggedInCookie();
useAuthStore.setState({ isLoading: false });
return;
}
@ -29,6 +31,7 @@ export function AuthInitializer({ children }: { children: ReactNode }) {
Promise.all([mePromise, wsPromise])
.then(([user, wsList]) => {
setLoggedInCookie();
useAuthStore.setState({ user, isLoading: false });
useWorkspaceStore.getState().hydrateWorkspace(wsList, wsId);
})
@ -38,6 +41,7 @@ export function AuthInitializer({ children }: { children: ReactNode }) {
api.setWorkspaceId(null);
localStorage.removeItem("multica_token");
localStorage.removeItem("multica_workspace_id");
clearLoggedInCookie();
useAuthStore.setState({ user: null, isLoading: false });
});
}, []);

View file

@ -3,6 +3,7 @@
import { create } from "zustand";
import type { User } from "@/shared/types";
import { api } from "@/shared/api";
import { setLoggedInCookie, clearLoggedInCookie } from "./auth-cookie";
interface AuthState {
user: User | null;
@ -48,6 +49,7 @@ export const useAuthStore = create<AuthState>((set) => ({
const { token, user } = await api.verifyCode(email, code);
localStorage.setItem("multica_token", token);
api.setToken(token);
setLoggedInCookie();
set({ user });
return user;
},
@ -57,6 +59,7 @@ export const useAuthStore = create<AuthState>((set) => ({
localStorage.removeItem("multica_workspace_id");
api.setToken(null);
api.setWorkspaceId(null);
clearLoggedInCookie();
set({ user: null });
},

14
apps/web/proxy.ts Normal file
View file

@ -0,0 +1,14 @@
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
export function proxy(request: NextRequest) {
const loggedIn = request.cookies.has("multica_logged_in");
if (loggedIn) {
return NextResponse.redirect(new URL("/issues", request.url));
}
return NextResponse.next();
}
export const config = {
matcher: ["/"],
};