1e65654114
The object spine becomes definable (data model was designed-for from day one):
- Division and Product entities (Product carries kind: Product|Service, optional DivisionId);
Team gains nullable ProductId — pre-structure teams keep working. AddDivisionsAndProducts
migration; org-scoped validation; owner-only writes (audited); list endpoints.
- /structure page: define divisions, products/services (with division), teams (under a
product). Org chart now renders the full spine — org → divisions → products → teams →
seats — with parentless layers linking up to the org.
- BYOK custom URL: the SeatsPage model-connection form gains a Base URL field (provider
list: stub/openai/ollama/vllm/custom). Backend already supported it end to end —
ApiConfig.Endpoint flows into the OpenAI-compatible adapter ({base}/v1/chat/completions),
so any OpenAI-compatible gateway or self-hosted model works; the config list shows it.
Verified: ArchitectureTests 8/8, IntegrationTests 45/45 (new OrgStructureTests: spine
creation, kind tags, org-scoped validation 400s, Member 403), client build green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
37 lines
1.9 KiB
TypeScript
37 lines
1.9 KiB
TypeScript
import { Navigate, Route, Routes } from 'react-router'
|
|
import { Toaster } from '@/components/ui/sonner'
|
|
import { AnalyticsPage } from '@/pages/AnalyticsPage'
|
|
import { BoardPage } from '@/pages/BoardPage'
|
|
import { CartablePage } from '@/pages/CartablePage'
|
|
import { LoginPage } from '@/pages/LoginPage'
|
|
import { MembersPage } from '@/pages/MembersPage'
|
|
import { OrgChartPage } from '@/pages/OrgChartPage'
|
|
import { PerformancePage } from '@/pages/PerformancePage'
|
|
import { ReviewsPage } from '@/pages/ReviewsPage'
|
|
import { SeatsPage } from '@/pages/SeatsPage'
|
|
import { StructurePage } from '@/pages/StructurePage'
|
|
import { useAuth } from '@/store/auth'
|
|
|
|
export default function App() {
|
|
const token = useAuth((state) => state.token)
|
|
|
|
return (
|
|
<>
|
|
<Routes>
|
|
<Route path="/login" element={token ? <Navigate to="/" replace /> : <LoginPage />} />
|
|
<Route path="/" element={token ? <BoardPage /> : <Navigate to="/login" replace />} />
|
|
<Route path="/seats" element={token ? <SeatsPage /> : <Navigate to="/login" replace />} />
|
|
<Route path="/reviews" element={token ? <ReviewsPage /> : <Navigate to="/login" replace />} />
|
|
<Route path="/analytics" element={token ? <AnalyticsPage /> : <Navigate to="/login" replace />} />
|
|
<Route path="/cartable" element={token ? <CartablePage /> : <Navigate to="/login" replace />} />
|
|
<Route path="/members" element={token ? <MembersPage /> : <Navigate to="/login" replace />} />
|
|
<Route path="/org" element={token ? <OrgChartPage /> : <Navigate to="/login" replace />} />
|
|
<Route path="/structure" element={token ? <StructurePage /> : <Navigate to="/login" replace />} />
|
|
<Route path="/performance" element={token ? <PerformancePage /> : <Navigate to="/login" replace />} />
|
|
<Route path="*" element={<Navigate to="/" replace />} />
|
|
</Routes>
|
|
<Toaster richColors position="top-right" />
|
|
</>
|
|
)
|
|
}
|