세션 평가·라이브코치·교수자 분석 라운드 마감 + 문서 정리 + 코드품질 리팩터
- 누적 작업트리 커밋: 회기 평가 복구·durable 저장, 라이브 코치 이력/근거, 교수자 학생분석, 음성 비언어 메타, PII 마스킹, 운영 티켓/헬스 등 - 문서: 완료 기록 docs/archive/ 냉동 보관, docs/ 단일 인덱스(docs/README.md)+통합 TODO(docs/TODO.md)로 정리 - 리팩터(행위 보존): Stage enum SSOT(taxonomy 소유·state_machine re-export), store recent/masked_turns 중복 제거, speaker_ko_label 단일 헬퍼, _list_sessions N+1 제거(state/turns 배치 + 턴평가 하이드레이션 배치) - 검증: 백엔드 pytest 352 passed, _list_sessions E2E chromium-single-run 2 passed
This commit is contained in:
parent
7c41c3ce79
commit
778e8526d4
108 changed files with 6457 additions and 455 deletions
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
import type { ReactNode } from "react";
|
||||
import { BrowserRouter, Navigate, Route, Routes, useLocation } from "react-router-dom";
|
||||
import { AuthProvider, canAccessRole, useAuth, roleHomePath, type Role } from "./lib/auth";
|
||||
import { AuthProvider, canAccessRole, useAuth, roleHomePath, type AuthUser, type Role } from "./lib/auth";
|
||||
|
||||
import Login from "./pages/Login";
|
||||
import Onboarding from "./pages/Onboarding";
|
||||
|
|
@ -74,6 +74,17 @@ function RequireAuth({
|
|||
return <>{children}</>;
|
||||
}
|
||||
|
||||
function isAdminWorkspacePath(path: string) {
|
||||
return path === "/admin" || path.startsWith("/admin/");
|
||||
}
|
||||
|
||||
function approvedHomePath(user: AuthUser) {
|
||||
if (user.onboardingCompletedAt == null) {
|
||||
return canAccessRole(user, "admin") ? "/admin" : "/onboarding";
|
||||
}
|
||||
return roleHomePath(user.role);
|
||||
}
|
||||
|
||||
function OnboardingGate({ children }: { children: ReactNode }) {
|
||||
const { user, loading } = useAuth();
|
||||
const location = useLocation();
|
||||
|
|
@ -82,6 +93,9 @@ function OnboardingGate({ children }: { children: ReactNode }) {
|
|||
if (loading) return <BootScreen />;
|
||||
if (path === "/pending") return <>{children}</>;
|
||||
if (user && user.onboardingCompletedAt == null && path !== "/onboarding") {
|
||||
if (isAdminWorkspacePath(path) && canAccessRole(user, "admin")) {
|
||||
return <>{children}</>;
|
||||
}
|
||||
return <Navigate to="/onboarding" replace state={{ from: path }} />;
|
||||
}
|
||||
if (user && user.onboardingCompletedAt != null && (path === "/login" || path === "/onboarding")) {
|
||||
|
|
@ -100,12 +114,7 @@ function PendingApprovalGate({ children }: { children: ReactNode }) {
|
|||
return <Navigate to="/pending" replace state={{ from: path }} />;
|
||||
}
|
||||
if (user && user.accountStatus === "approved" && path === "/pending") {
|
||||
return (
|
||||
<Navigate
|
||||
to={user.onboardingCompletedAt == null ? "/onboarding" : roleHomePath(user.role)}
|
||||
replace
|
||||
/>
|
||||
);
|
||||
return <Navigate to={approvedHomePath(user)} replace />;
|
||||
}
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
|
@ -118,7 +127,7 @@ function RootRedirect() {
|
|||
return <Navigate to="/pending" replace />;
|
||||
}
|
||||
if (user && user.onboardingCompletedAt == null) {
|
||||
return <Navigate to="/onboarding" replace />;
|
||||
return <Navigate to={approvedHomePath(user)} replace />;
|
||||
}
|
||||
return <Navigate to={user ? roleHomePath(user.role) : "/login"} replace />;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue