feat: app shell, Storybook, and CI/CD pipeline#819
Conversation
WalkthroughAdds an application shell and dashboard developer tooling. Introduces React Router with lazy-loaded routes and four guards (AuthGuard, SetupGuard, GuestGuard, SetupCompleteGuard), an AppLayout with Sidebar and StatusBar, PlaceholderPage, SidebarNavItem, many placeholder page components and NotFound, a centralized ROUTES constant and AppRouter, and a typed Zustand setup store exposing fetchSetupStatus. Adds Storybook config, stories, npm scripts and web/.npmrc, test utilities and extensive Vitest/RTL tests, a .gitignore entry for storybook-static, a Dockerfile change to include web/.npmrc during install, and a CI job to build Storybook wired into the ci-pass gate. Suggested labels
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request establishes the foundational user interface and routing infrastructure for the web dashboard, integrating a complete application shell with dynamic navigation and robust authentication/setup guards. It also introduces Storybook for component development and enhances the CI/CD pipeline to support these new frontend capabilities, significantly advancing the project's frontend development readiness. Highlights
Ignored Files
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
Dependency ReviewThe following issues were found:
|
There was a problem hiding this comment.
Code Review
This pull request significantly refactors the web dashboard's routing and UI structure. It introduces React Router for navigation, implementing authentication and setup guards to manage access. A new AppLayout component is added, featuring a Sidebar and StatusBar, along with numerous placeholder page components for various routes. Storybook is integrated for UI component development, including configuration, dependencies, and initial stories for Sidebar and Button. Testing utilities for router components are introduced, and existing tests are updated. The .gitignore and CLAUDE.md documentation are updated to reflect Storybook integration. A new Zustand store for managing application setup status is also implemented. Review comments suggest improvements such as using decorators for Storybook initial state setup, extracting duplicated loading UI into a shared component, removing redundant CSS classes, and improving type safety in test store updates.
| const user = userEvent.setup() | ||
| const logoutSpy = vi.fn() | ||
| setup() | ||
| useAuthStore.setState({ logout: logoutSpy } as never) |
There was a problem hiding this comment.
The as never type assertion is used here to bypass TypeScript's type checking for a partial store update. While this works for the test, it's not type-safe and can make the test brittle if the store's structure changes.
A safer approach is to spread the existing state to ensure the full type is satisfied, only overriding the properties relevant to the test.
| useAuthStore.setState({ logout: logoutSpy } as never) | |
| useAuthStore.setState({ ...useAuthStore.getState(), logout: logoutSpy }) |
| interface RenderWithRouterOptions { | ||
| initialEntries?: string[] | ||
| routes?: RouteObject[] | ||
| } |
There was a problem hiding this comment.
The routes property in the RenderWithRouterOptions interface is not used within the renderWithRouter function. The function's implementation is designed to wrap a single element in a wildcard route. The separate renderRoutes function is correctly designed to handle a full array of RouteObjects.
To avoid confusion and make the interface accurately reflect its usage, the routes property should be removed.
interface RenderWithRouterOptions {
initialEntries?: string[]
}
| export const Expanded: Story = { | ||
| play: () => { | ||
| localStorage.setItem('sidebar_collapsed', 'false') | ||
| }, | ||
| } | ||
|
|
||
| export const Collapsed: Story = { | ||
| play: () => { | ||
| localStorage.setItem('sidebar_collapsed', 'true') | ||
| }, | ||
| decorators: [ | ||
| (Story) => { | ||
| localStorage.setItem('sidebar_collapsed', 'true') | ||
| return <Story /> | ||
| }, | ||
| ], | ||
| } |
There was a problem hiding this comment.
The play functions in the Expanded and Collapsed stories are being used to set up initial state in localStorage. The play function is intended for simulating user interactions after a story renders. For setting up initial state or context, decorators are the more appropriate and idiomatic Storybook feature.
The Collapsed story is also redundant, as it sets the same localStorage key in both the play function and a decorator.
To improve consistency and correctness, I recommend using decorators for both stories and removing the play functions.
| export const Expanded: Story = { | |
| play: () => { | |
| localStorage.setItem('sidebar_collapsed', 'false') | |
| }, | |
| } | |
| export const Collapsed: Story = { | |
| play: () => { | |
| localStorage.setItem('sidebar_collapsed', 'true') | |
| }, | |
| decorators: [ | |
| (Story) => { | |
| localStorage.setItem('sidebar_collapsed', 'true') | |
| return <Story /> | |
| }, | |
| ], | |
| } | |
| export const Expanded: Story = { | |
| decorators: [ | |
| (Story) => { | |
| localStorage.setItem('sidebar_collapsed', 'false') | |
| return <Story /> | |
| }, | |
| ], | |
| } | |
| export const Collapsed: Story = { | |
| decorators: [ | |
| (Story) => { | |
| localStorage.setItem('sidebar_collapsed', 'true') | |
| return <Story /> | |
| }, | |
| ], | |
| } |
| <div className="text-sm font-medium text-surface-700 truncate"> | ||
| {user.username} | ||
| </div> |
There was a problem hiding this comment.
The truncate class on this div is redundant because its parent div on line 205 already has the truncate class. CSS utility classes for truncation apply to the container, so applying it again on a direct child has no additional effect and adds unnecessary clutter.
| <div className="text-sm font-medium text-surface-700 truncate"> | |
| {user.username} | |
| </div> | |
| <div className="text-sm font-medium text-surface-700"> | |
| {user.username} | |
| </div> |
| if (setupComplete === null || loading) { | ||
| return ( | ||
| <div className="flex h-screen items-center justify-center"> | ||
| <div className="text-surface-500 text-sm">Loading...</div> | ||
| </div> | ||
| ) | ||
| } |
There was a problem hiding this comment.
This loading indicator UI is duplicated in SetupCompleteGuard (lines 87-93) and is also very similar to the suspense fallbacks used elsewhere (e.g., in router/index.tsx).
To improve maintainability and ensure a consistent loading experience across the application, this UI should be extracted into a shared component, for example a FullScreenLoader.
You could create a new component like this:
// src/components/common/FullScreenLoader.tsx
export function FullScreenLoader() {
return (
<div className="flex h-screen items-center justify-center">
<div className="text-surface-500 text-sm">Loading...</div>
</div>
);
}Then you could use <FullScreenLoader /> here and in SetupCompleteGuard to reduce duplication.
There was a problem hiding this comment.
Actionable comments posted: 11
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@web/package.json`:
- Around line 43-48: The Storybook deps have mismatched minor versions; update
all Storybook packages to the same version (e.g., set
"@storybook/addon-essentials", "@storybook/addon-interactions", and
"@storybook/test" to "^8.6.18" to match "@storybook/addon-a11y",
"@storybook/react", and "@storybook/react-vite") so versions are consistent and
avoid peer dependency warnings; modify package.json dependencies for those
package names and run install to refresh lockfile.
In `@web/src/__tests__/App.test.tsx`:
- Around line 50-56: The test "redirects unauthenticated users to login" uses
the fragile query screen.getByText('Login'); replace it with a more specific
selector to avoid accidental matches: locate the login page by a unique role or
test id (e.g., getByRole('heading', { name: /login/i }) or
getByTestId('login-page') or a form-specific query) inside the same waitFor
block after render(<App />); update the assertion in the test to assert that
this specific element (heading/form/testid) is in the document.
- Around line 67-72: The test currently couples behavior to layout by asserting
exact counts from screen.getAllByText('Dashboard') and
screen.getAllByText('SynthOrg'); instead, scope assertions to semantic queries
or specific containers: replace the count checks with role-based lookups (e.g.,
getByRole/getAllByRole with accessible name 'Dashboard' for nav links or
headings) or use within(container) to target the sidebar/statusbar elements and
assert each element exists (toBeInTheDocument) rather than asserting lengths;
update the assertions around the Dashboard and SynthOrg checks in App.test.tsx
to use these semantic/scoped queries so layout changes won't break the test.
In `@web/src/__tests__/components/layout/Sidebar.test.tsx`:
- Around line 121-130: The test sets the logout spy after rendering, which can
cause flakiness because Sidebar captures logout via useAuthStore during render;
move the line that injects the spy (useAuthStore.setState({ logout: logoutSpy }
as never)) to before calling setup() so the component receives the spy when
rendered (keep logoutSpy = vi.fn() and the user.click/assert unchanged); also
consider resetting store state after the test if other tests depend on it.
In `@web/src/components/layout/AppLayout.tsx`:
- Around line 6-12: The PageLoadingFallback component should expose its loading
state to assistive tech: update PageLoadingFallback to include an ARIA live
region/role so screen readers announce progress (e.g., add role="status" and
aria-live="polite" to the container or include a visually hidden element with
the "Loading..." text) and optionally include an accessible spinner (decorative
SVG with aria-hidden="true") for sighted users; modify the PageLoadingFallback
function to wrap or replace the current div/span with these attributes and
ensure only non-redundant text is announced.
In `@web/src/components/layout/Sidebar.stories.tsx`:
- Around line 44-54: Remove the redundant play hook from the Collapsed story:
the decorator already sets localStorage.setItem('sidebar_collapsed', 'true')
before render, so delete the play property on the Collapsed export (the play: ()
=> { localStorage.setItem('sidebar_collapsed', 'true') }) and keep the decorator
that sets the same key; ensure only the decorators array remains on the
Collapsed Story definition.
- Around line 38-42: The Expanded story's play hook sets localStorage after
initial render which doesn't affect Sidebar's initial useState initializer;
either remove the play hook from export const Expanded or switch to the same
approach used by the Collapsed story (add a decorator that sets localStorage
before render so Sidebar reads the intended value on first render). Locate the
Expanded story (export const Expanded) and either delete its play function or
implement a decorator analogous to Collapsed that sets 'sidebar_collapsed' to
'false' before the component mounts.
In `@web/src/components/layout/Sidebar.tsx`:
- Around line 212-218: The logout button currently relies on title="Logout"
which isn't reliably announced by assistive tech; update the button (the element
using onClick={logout} and rendering <LogOut ... />) to include an accessible
label (e.g., add aria-label="Logout" or aria-label based on collapsed state) so
screen readers can announce the action when the sidebar is collapsed; keep the
existing title and visual icon intact but ensure aria-label is present on the
button element.
- Around line 160-169: In the Sidebar component add an explicit aria-label to
the Notifications button: update the <button> (the one rendering <Bell /> and
using the collapsed prop) to include aria-label="Notifications" so screen
readers get the label when collapsed (keep the visible
<span>Notifications</span> when !collapsed for sighted users).
In `@web/src/pages/OrgEditPage.tsx`:
- Around line 1-7: Extract a reusable PlaceholderPage component and replace the
duplicated centered-layout in OrgEditPage: create a new component (e.g.,
PlaceholderPage) that renders the common wrapper div and accepts children or a
title prop, then update the OrgEditPage function to return <PlaceholderPage
title="Edit Organization" /> (or pass the <h1> as children) instead of the
inline div; ensure the new component preserves the exact classes and typography
used in OrgEditPage so other route stubs can import and reuse it.
In `@web/src/router/guards.tsx`:
- Around line 37-43: Extract the duplicated loading markup used in SetupGuard
and SetupCompleteGuard into a single reusable component (e.g.,
FullScreenLoading) so both guards return <FullScreenLoading /> when
setupComplete === null or loading; add the function/component near the top of
this file or in a shared UI file, export if needed, and replace the duplicated
JSX in the SetupGuard and SetupCompleteGuard render paths to keep behavior and
styling identical.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 84ffa9e9-7d4c-4b82-a96c-db63898c1474
⛔ Files ignored due to path filters (1)
web/package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (45)
.github/workflows/ci.yml.gitignoreCLAUDE.mdweb/.npmrcweb/.storybook/main.tsweb/.storybook/preview.tsxweb/package.jsonweb/src/App.tsxweb/src/__tests__/App.test.tsxweb/src/__tests__/components/layout/Sidebar.test.tsxweb/src/__tests__/components/layout/SidebarNavItem.test.tsxweb/src/__tests__/router/guards.test.tsxweb/src/__tests__/stores/setup.test.tsweb/src/__tests__/test-utils.tsxweb/src/components/layout/AppLayout.tsxweb/src/components/layout/Sidebar.stories.tsxweb/src/components/layout/Sidebar.tsxweb/src/components/layout/SidebarNavItem.tsxweb/src/components/layout/StatusBar.tsxweb/src/components/ui/button.stories.tsxweb/src/pages/AgentDetailPage.tsxweb/src/pages/AgentsPage.tsxweb/src/pages/ApprovalsPage.tsxweb/src/pages/BudgetForecastPage.tsxweb/src/pages/BudgetPage.tsxweb/src/pages/DashboardPage.tsxweb/src/pages/LoginPage.tsxweb/src/pages/MeetingDetailPage.tsxweb/src/pages/MeetingsPage.tsxweb/src/pages/MessagesPage.tsxweb/src/pages/NotFoundPage.tsxweb/src/pages/OrgChartPage.tsxweb/src/pages/OrgEditPage.tsxweb/src/pages/ProviderDetailPage.tsxweb/src/pages/ProvidersPage.tsxweb/src/pages/SettingsNamespacePage.tsxweb/src/pages/SettingsPage.tsxweb/src/pages/SetupPage.tsxweb/src/pages/TaskBoardPage.tsxweb/src/pages/TaskDetailPage.tsxweb/src/router/guards.tsxweb/src/router/index.tsxweb/src/router/routes.tsweb/src/stores/auth.tsweb/src/stores/setup.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Build Sandbox
- GitHub Check: Analyze (python)
- GitHub Check: Dependency Review
🧰 Additional context used
📓 Path-based instructions (3)
web/**
📄 CodeRabbit inference engine (CLAUDE.md)
Use Node.js 22+ for the web dashboard. Dependencies in
web/package.json
Files:
web/src/pages/BudgetForecastPage.tsxweb/src/pages/AgentsPage.tsxweb/src/pages/ApprovalsPage.tsxweb/src/pages/OrgChartPage.tsxweb/src/pages/MeetingsPage.tsxweb/src/pages/AgentDetailPage.tsxweb/src/pages/DashboardPage.tsxweb/src/pages/MeetingDetailPage.tsxweb/src/pages/OrgEditPage.tsxweb/src/pages/TaskDetailPage.tsxweb/src/pages/MessagesPage.tsxweb/src/pages/NotFoundPage.tsxweb/package.jsonweb/src/pages/SetupPage.tsxweb/src/pages/ProvidersPage.tsxweb/src/pages/SettingsPage.tsxweb/src/pages/ProviderDetailPage.tsxweb/src/pages/SettingsNamespacePage.tsxweb/src/stores/auth.tsweb/src/pages/BudgetPage.tsxweb/src/pages/LoginPage.tsxweb/src/App.tsxweb/src/pages/TaskBoardPage.tsxweb/src/__tests__/components/layout/Sidebar.test.tsxweb/src/components/layout/AppLayout.tsxweb/src/components/layout/StatusBar.tsxweb/src/__tests__/components/layout/SidebarNavItem.test.tsxweb/src/components/layout/Sidebar.tsxweb/src/components/layout/Sidebar.stories.tsxweb/src/router/index.tsxweb/src/stores/setup.tsweb/src/__tests__/test-utils.tsxweb/src/components/layout/SidebarNavItem.tsxweb/src/__tests__/App.test.tsxweb/src/components/ui/button.stories.tsxweb/src/__tests__/stores/setup.test.tsweb/src/__tests__/router/guards.test.tsxweb/src/router/routes.tsweb/src/router/guards.tsx
web/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
web/src/**/*.{ts,tsx}: React 19 + shadcn/ui + Tailwind CSS 4 for the web dashboard
Use Zustand for state management in React
Use ESLint with@eslint-react/eslint-pluginandeslint-plugin-securityfor React linting
Web dashboard dependencies include Axios client, React Router, Recharts for charting, Framer Motion for animations, cmdk for command palette, Lucide React for icons,@tanstack/react-queryfor server state
Files:
web/src/pages/BudgetForecastPage.tsxweb/src/pages/AgentsPage.tsxweb/src/pages/ApprovalsPage.tsxweb/src/pages/OrgChartPage.tsxweb/src/pages/MeetingsPage.tsxweb/src/pages/AgentDetailPage.tsxweb/src/pages/DashboardPage.tsxweb/src/pages/MeetingDetailPage.tsxweb/src/pages/OrgEditPage.tsxweb/src/pages/TaskDetailPage.tsxweb/src/pages/MessagesPage.tsxweb/src/pages/NotFoundPage.tsxweb/src/pages/SetupPage.tsxweb/src/pages/ProvidersPage.tsxweb/src/pages/SettingsPage.tsxweb/src/pages/ProviderDetailPage.tsxweb/src/pages/SettingsNamespacePage.tsxweb/src/stores/auth.tsweb/src/pages/BudgetPage.tsxweb/src/pages/LoginPage.tsxweb/src/App.tsxweb/src/pages/TaskBoardPage.tsxweb/src/__tests__/components/layout/Sidebar.test.tsxweb/src/components/layout/AppLayout.tsxweb/src/components/layout/StatusBar.tsxweb/src/__tests__/components/layout/SidebarNavItem.test.tsxweb/src/components/layout/Sidebar.tsxweb/src/components/layout/Sidebar.stories.tsxweb/src/router/index.tsxweb/src/stores/setup.tsweb/src/__tests__/test-utils.tsxweb/src/components/layout/SidebarNavItem.tsxweb/src/__tests__/App.test.tsxweb/src/components/ui/button.stories.tsxweb/src/__tests__/stores/setup.test.tsweb/src/__tests__/router/guards.test.tsxweb/src/router/routes.tsweb/src/router/guards.tsx
web/src/__tests__/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
web/src/__tests__/**/*.{ts,tsx}: Use Vitest for React unit tests with@vitest/coverage-v8for coverage tracking (coverage scoped to files changed vs origin/main)
Use fast-check for property-based testing in React (fc.assert+fc.property)
Files:
web/src/__tests__/components/layout/Sidebar.test.tsxweb/src/__tests__/components/layout/SidebarNavItem.test.tsxweb/src/__tests__/test-utils.tsxweb/src/__tests__/App.test.tsxweb/src/__tests__/stores/setup.test.tsweb/src/__tests__/router/guards.test.tsx
🧠 Learnings (29)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to docker/{Dockerfile*,compose.yml} : Docker: Backend uses 3-stage build (builder → setup → distroless runtime), Chainguard Python, non-root (UID 65532), CIS-hardened. Web uses nginxinc/nginx-unprivileged, Vue 3 SPA with PrimeVue + Tailwind CSS, SPA routing, API/WebSocket proxy to backend.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T12:00:18.113Z
Learning: Commits: <type>: <description> — types: feat, fix, refactor, docs, test, chore, perf, ci. Enforced by commitizen (commit-msg hook). Signed commits: required on main via branch protection — all commits must be GPG/SSH signed.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T19:31:05.964Z
Learning: Applies to web/src/**/*.{ts,tsx} : React 19 + shadcn/ui + Tailwind CSS 4 for the web dashboard
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T19:31:05.964Z
Learning: Applies to web/src/**/*.{ts,tsx} : Web dashboard dependencies include Axios client, React Router, Recharts for charting, Framer Motion for animations, cmdk for command palette, Lucide React for icons, tanstack/react-query for server state
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to web/** : Web dashboard: Node.js 20+, dependencies in web/package.json (Vue 3, PrimeVue, Tailwind CSS, Pinia, VueFlow, ECharts, Axios, vue-draggable-plus, Vitest, fast-check, ESLint, vue-tsc).
📚 Learning: 2026-03-24T19:31:05.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T19:31:05.964Z
Learning: Applies to web/src/**/*.{ts,tsx} : React 19 + shadcn/ui + Tailwind CSS 4 for the web dashboard
Applied to files:
web/src/pages/BudgetForecastPage.tsx.gitignoreweb/src/pages/AgentsPage.tsxweb/src/pages/ApprovalsPage.tsxweb/src/pages/OrgChartPage.tsxweb/src/pages/MeetingsPage.tsxweb/src/pages/AgentDetailPage.tsxweb/.storybook/preview.tsxweb/src/pages/DashboardPage.tsxweb/src/pages/MeetingDetailPage.tsxweb/src/pages/TaskDetailPage.tsxweb/src/pages/MessagesPage.tsxweb/src/pages/NotFoundPage.tsxweb/src/pages/SetupPage.tsxweb/src/pages/ProvidersPage.tsxweb/src/pages/SettingsPage.tsxweb/src/pages/ProviderDetailPage.tsxweb/src/pages/SettingsNamespacePage.tsxweb/src/pages/BudgetPage.tsxweb/.storybook/main.tsweb/src/pages/LoginPage.tsxweb/src/App.tsxweb/src/pages/TaskBoardPage.tsxCLAUDE.mdweb/src/__tests__/components/layout/Sidebar.test.tsxweb/src/components/layout/AppLayout.tsxweb/src/components/layout/StatusBar.tsxweb/src/__tests__/components/layout/SidebarNavItem.test.tsxweb/src/components/layout/Sidebar.tsxweb/src/router/index.tsxweb/src/__tests__/test-utils.tsxweb/src/components/layout/SidebarNavItem.tsxweb/src/__tests__/App.test.tsxweb/src/router/routes.tsweb/src/router/guards.tsx
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to web/** : Web dashboard: Node.js 20+, dependencies in web/package.json (Vue 3, PrimeVue, Tailwind CSS, Pinia, VueFlow, ECharts, Axios, vue-draggable-plus, Vitest, fast-check, ESLint, vue-tsc).
Applied to files:
.gitignoreweb/src/pages/DashboardPage.tsxweb/package.jsonweb/src/App.tsxCLAUDE.md
📚 Learning: 2026-03-14T15:43:05.601Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T15:43:05.601Z
Learning: Applies to web/package.json : Web dashboard Node.js 20+; dependencies in web/package.json (Vue 3, PrimeVue, Tailwind CSS, Pinia, VueFlow, ECharts, Axios, vue-draggable-plus, Vitest, ESLint, vue-tsc)
Applied to files:
.gitignoreweb/.npmrcweb/package.jsonweb/.storybook/main.tsCLAUDE.md
📚 Learning: 2026-03-24T19:31:05.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T19:31:05.964Z
Learning: Applies to web/src/__tests__/**/*.{ts,tsx} : Use Vitest for React unit tests with `vitest/coverage-v8` for coverage tracking (coverage scoped to files changed vs origin/main)
Applied to files:
.gitignoreweb/package.jsonweb/.storybook/main.tsweb/src/__tests__/components/layout/Sidebar.test.tsxweb/src/__tests__/components/layout/SidebarNavItem.test.tsxweb/src/__tests__/test-utils.tsxweb/src/__tests__/App.test.tsxweb/src/__tests__/stores/setup.test.tsweb/src/__tests__/router/guards.test.tsx
📚 Learning: 2026-03-24T19:31:05.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T19:31:05.964Z
Learning: Applies to web/src/**/*.{ts,tsx} : Web dashboard dependencies include Axios client, React Router, Recharts for charting, Framer Motion for animations, cmdk for command palette, Lucide React for icons, tanstack/react-query for server state
Applied to files:
.gitignoreweb/src/pages/ApprovalsPage.tsxweb/src/pages/DashboardPage.tsxweb/package.jsonweb/src/App.tsxweb/src/pages/TaskBoardPage.tsxCLAUDE.mdweb/src/components/layout/AppLayout.tsxweb/src/components/layout/StatusBar.tsxweb/src/components/layout/Sidebar.tsxweb/src/router/index.tsxweb/src/__tests__/test-utils.tsxweb/src/__tests__/App.test.tsxweb/src/router/routes.tsweb/src/router/guards.tsx
📚 Learning: 2026-03-20T08:28:32.845Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T08:28:32.845Z
Learning: Applies to web/src/__tests__/**/*.{ts,js} : Dashboard testing: Vitest unit tests organized by feature under `web/src/__tests__/`. Use fast-check for property-based testing (`fc.assert` + `fc.property`).
Applied to files:
.gitignoreweb/package.jsonCLAUDE.mdweb/src/__tests__/components/layout/Sidebar.test.tsxweb/src/__tests__/components/layout/SidebarNavItem.test.tsxweb/src/__tests__/test-utils.tsxweb/src/__tests__/App.test.tsxweb/src/__tests__/stores/setup.test.tsweb/src/__tests__/router/guards.test.tsx
📚 Learning: 2026-03-24T19:31:05.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T19:31:05.964Z
Learning: Applies to web/** : Use Node.js 22+ for the web dashboard. Dependencies in `web/package.json`
Applied to files:
.gitignoreweb/.npmrc
📚 Learning: 2026-03-15T21:20:09.993Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:20:09.993Z
Learning: Applies to web/src/components/** : Vue components organized by feature (agents/, approvals/, budget/, common/, dashboard/, layout/, messages/, org-chart/, tasks/).
Applied to files:
.gitignoreCLAUDE.md
📚 Learning: 2026-03-24T19:31:05.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T19:31:05.964Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use ESLint with `eslint-react/eslint-plugin` and `eslint-plugin-security` for React linting
Applied to files:
web/package.json
📚 Learning: 2026-03-24T19:31:05.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T19:31:05.964Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use Zustand for state management in React
Applied to files:
web/src/stores/auth.tsCLAUDE.mdweb/src/router/index.tsxweb/src/stores/setup.tsweb/src/__tests__/test-utils.tsx
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to .github/workflows/**/*.yml : Path filtering: dorny/paths-filter detects Python/dashboard/docker changes; jobs only run when their domain is affected. CLI has its own workflow (cli.yml).
Applied to files:
.github/workflows/ci.ymlCLAUDE.md
📚 Learning: 2026-03-24T19:31:05.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T19:31:05.964Z
Learning: CI path filtering via `dorny/paths-filter`—jobs only run when their domain is affected. CLI has its own workflow (`cli.yml`).
Applied to files:
.github/workflows/ci.ymlCLAUDE.md
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/*.yml : Dependabot: daily updates for uv + github-actions + npm + pre-commit + docker + gomod, grouped minor/patch, no auto-merge. Use `/review-dep-pr` to review Dependabot PRs before merging.
Applied to files:
.github/workflows/ci.ymlCLAUDE.md
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/docker.yml : Docker workflow: builds backend + web + sandbox images, pushes to GHCR, signs with cosign. SLSA L3 provenance attestations via actions/attest-build-provenance. Scans: Trivy (CRITICAL = hard fail, HIGH = warn) + Grype (critical cutoff) + CIS Docker Benchmark v1.6.0 compliance (informational). CVE triage via .github/.trivyignore.yaml and .github/.grype.yaml. Images only pushed after scans pass. Triggers on push to main and version tags (v*).
Applied to files:
.github/workflows/ci.ymlCLAUDE.md
📚 Learning: 2026-03-15T12:00:18.113Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T12:00:18.113Z
Learning: Applies to .github/workflows/docker.yml : CI Docker: build → scan → push to GHCR + cosign sign + SLSA L3 provenance via attest-build-provenance (images only pushed after Trivy/Grype scans pass).
Applied to files:
.github/workflows/ci.ymlCLAUDE.md
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/cli.yml : CLI workflow: Go lint (golangci-lint + go vet) + test (-race -coverprofile) + build (cross-compile: linux/darwin/windows × amd64/arm64) + govulncheck + fuzz testing (main-only, 30s/target, continue-on-error, matrix over 4 packages). cli-pass gate includes fuzz as informational. GoReleaser release on v* tags. Cosign keyless signing of checksums.txt. SLSA L3 provenance attestations. Sigstore bundle (.sigstore.json) attached. Post-release appends checksums/verification/provenance to draft release notes.
Applied to files:
.github/workflows/ci.ymlCLAUDE.md
📚 Learning: 2026-03-19T11:19:40.044Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:19:40.044Z
Learning: CLI workflow (`.github/workflows/cli.yml`) runs Go lint (golangci-lint + go vet) + test (race, coverage) + build (cross-compile matrix) + vulnerability check (govulncheck) + fuzz testing. Cross-compiles for linux/darwin/windows × amd64/arm64. GoReleaser release on v* tags with cosign keyless signing and SLSA L3 attestations.
Applied to files:
.github/workflows/ci.ymlCLAUDE.md
📚 Learning: 2026-03-16T19:52:03.656Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T19:52:03.656Z
Learning: Applies to cli/**/*.go : Lint CLI Go code with golangci-lint and go vet; test with go test -race; check vulnerabilities with govulncheck
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-19T11:30:29.217Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:30:29.217Z
Learning: Applies to cli/**/*.go : Run Go lint via `golangci-lint run`, vet via `go vet`, tests via `go test ./...`, and fuzz via `go test -fuzz=FuzzTarget -fuzztime=30s`
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-19T11:19:40.044Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:19:40.044Z
Learning: Applies to cli/**/*.go : Lint Go code with `golangci-lint` and `go vet`. Run tests with `-race` flag to detect race conditions.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to cli/**/*.go : Go CLI (Go 1.26+) uses Cobra for commands, charmbracelet/huh for interactive CLI, charmbracelet/lipgloss for styled output. Cross-platform builds (linux/darwin/windows × amd64/arm64). GoReleaser for releases with cosign keyless signing of checksums.txt. SLSA L3 provenance attestations via actions/attest-build-provenance.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-24T19:31:05.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T19:31:05.964Z
Learning: Applies to cli/**/*.go : Use Cobra for CLI commands, charmbracelet/huh for interactive prompts, charmbracelet/lipgloss for UI styling, sigstore-go for binary verification, go-containerregistry for container image handling, go-tuf for TUF updates
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-24T19:31:05.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T19:31:05.964Z
Learning: Docker + CLI workflows: build + Trivy/Grype scan + push to GHCR + cosign sign + SLSA L3 provenance. CLI also includes govulncheck + fuzz via `testing.F`.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/**/*.py : Package structure: src/synthorg/ organized as: api/ (REST+WebSocket, Litestar), auth/ (auth subpackage), backup/ (scheduled/manual backups), budget/ (cost tracking, CFO), cli/ (superseded by Go CLI), communication/ (message bus, meetings), config/ (YAML loading), core/ (domain models, resilience config), engine/ (orchestration, task state, coordination, approval gates, stagnation detection, context budget, compaction), hr/ (hiring, performance, promotion), memory/ (pluggable backend, Mem0, retrieval, consolidation), persistence/ (operational data, SQLite, settings), observability/ (logging, correlation, sinks), providers/ (LLM abstraction, LiteLLM, auth types, presets, runtime CRUD), settings/ (runtime-editable, typed definitions, encryption, config bridge), security/ (SecOps, rule engine, output scanning, progressive trust, autonomy levels), templates/ (company templates, personalities), tools/ (registry, built-in tools, git, sandbox, code_runner, MCP...
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to docker/{Dockerfile*,compose.yml} : Docker: Backend uses 3-stage build (builder → setup → distroless runtime), Chainguard Python, non-root (UID 65532), CIS-hardened. Web uses nginxinc/nginx-unprivileged, Vue 3 SPA with PrimeVue + Tailwind CSS, SPA routing, API/WebSocket proxy to backend.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Pre-push hooks: mypy type-check + pytest unit tests + golangci-lint + go vet + go test (CLI, conditional on cli/**/*.go) (fast gate before push, skipped in pre-commit.ci — dedicated CI jobs already run these).
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-24T19:31:05.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T19:31:05.964Z
Learning: Security scanning: gitleaks (push/PR + weekly), zizmor (workflow analysis), OSSF Scorecard (weekly), Socket.dev (PR supply chain), ZAP DAST (weekly + manual, rules: `.github/zap-rules.tsv`)
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-24T19:31:05.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T19:31:05.964Z
Learning: Applies to web/src/__tests__/**/*.{ts,tsx} : Use fast-check for property-based testing in React (`fc.assert` + `fc.property`)
Applied to files:
web/src/__tests__/components/layout/Sidebar.test.tsxweb/src/__tests__/components/layout/SidebarNavItem.test.tsxweb/src/__tests__/test-utils.tsxweb/src/__tests__/App.test.tsxweb/src/__tests__/stores/setup.test.tsweb/src/__tests__/router/guards.test.tsx
🧬 Code graph analysis (13)
web/src/pages/NotFoundPage.tsx (1)
web/src/components/ui/button.stories.tsx (1)
Link(43-45)
web/src/App.tsx (1)
web/src/router/index.tsx (1)
AppRouter(115-117)
web/src/__tests__/components/layout/Sidebar.test.tsx (3)
web/src/stores/auth.ts (2)
useAuthStore(61-204)setup(150-152)web/src/__tests__/test-utils.tsx (1)
renderWithRouter(17-26)web/src/components/layout/Sidebar.tsx (1)
Sidebar(27-226)
web/src/components/layout/AppLayout.tsx (3)
web/src/components/layout/StatusBar.tsx (1)
StatusBar(3-43)web/src/components/layout/Sidebar.tsx (1)
Sidebar(27-226)scripts/export_openapi.py (1)
main(90-118)
web/src/__tests__/components/layout/SidebarNavItem.test.tsx (2)
web/src/__tests__/test-utils.tsx (1)
renderWithRouter(17-26)web/src/components/layout/SidebarNavItem.tsx (1)
SidebarNavItem(15-57)
web/src/components/layout/Sidebar.tsx (4)
web/src/hooks/useAuth.ts (1)
useAuth(10-31)web/src/stores/auth.ts (2)
logout(200-202)useAuthStore(61-204)web/src/components/layout/SidebarNavItem.tsx (1)
SidebarNavItem(15-57)web/src/router/routes.ts (1)
ROUTES(7-28)
web/src/components/layout/Sidebar.stories.tsx (2)
web/src/components/layout/Sidebar.tsx (1)
Sidebar(27-226)web/src/stores/auth.ts (1)
useAuthStore(61-204)
web/src/router/index.tsx (2)
web/src/components/layout/AppLayout.tsx (1)
AppLayout(14-28)web/src/router/guards.tsx (4)
GuestGuard(55-63)SetupCompleteGuard(69-100)AuthGuard(11-19)SetupGuard(26-50)
web/src/stores/setup.ts (1)
web/src/api/endpoints/setup.ts (1)
getSetupStatus(19-22)
web/src/__tests__/App.test.tsx (3)
web/src/stores/auth.ts (1)
useAuthStore(61-204)web/src/stores/setup.ts (1)
useSetupStore(11-27)web/src/App.tsx (1)
App(3-5)
web/src/__tests__/stores/setup.test.ts (2)
web/src/stores/setup.ts (1)
useSetupStore(11-27)web/src/api/endpoints/setup.ts (1)
getSetupStatus(19-22)
web/src/__tests__/router/guards.test.tsx (4)
web/src/stores/setup.ts (1)
useSetupStore(11-27)web/src/__tests__/test-utils.tsx (1)
renderRoutes(31-37)web/src/router/guards.tsx (4)
AuthGuard(11-19)SetupGuard(26-50)GuestGuard(55-63)SetupCompleteGuard(69-100)web/src/api/endpoints/setup.ts (1)
getSetupStatus(19-22)
web/src/router/guards.tsx (3)
web/src/stores/auth.ts (1)
useIsAuthenticated(208-208)web/src/router/routes.ts (1)
ROUTES(7-28)web/src/stores/setup.ts (2)
useSetupStore(11-27)fetchSetupStatus(15-26)
🔇 Additional comments (54)
web/src/pages/TaskBoardPage.tsx (1)
1-7: LGTM!Clean placeholder page implementation. The centered layout and custom
text-surface-500token are consistent with the other route stubs in this PR.web/src/pages/OrgChartPage.tsx (1)
1-7: LGTM — clean placeholder page stub.Structure and styling are consistent with the app-shell scaffold pattern.
web/src/pages/MeetingDetailPage.tsx (1)
1-7: LGTM — page stub is correct and consistent.web/src/pages/BudgetPage.tsx (1)
1-7: LGTM — straightforward placeholder implementation.web/src/pages/TaskDetailPage.tsx (1)
1-7: LGTM — looks good for a route placeholder page.web/src/pages/SettingsNamespacePage.tsx (1)
1-7: LGTM — implementation is consistent and correct.web/src/pages/MeetingsPage.tsx (1)
1-7: LGTM — valid and consistent page stub.web/.npmrc (1)
1-1: 🧹 Nitpick | 🔵 TrivialRemove
legacy-peer-deps=truesince strict peer resolution is now viable.Strict peer dependency resolution works without conflicts. This setting should be removed to enforce better lockfile hygiene and catch incompatibilities early.
⛔ Skipped due to learnings
Learnt from: CR Repo: Aureliolo/synthorg PR: 0 File: CLAUDE.md:0-0 Timestamp: 2026-03-24T19:31:05.964Z Learning: Applies to web/** : Use Node.js 22+ for the web dashboard. Dependencies in `web/package.json`Learnt from: CR Repo: Aureliolo/synthorg PR: 0 File: CLAUDE.md:0-0 Timestamp: 2026-03-15T18:17:43.675Z Learning: Applies to web/** : Web dashboard: Node.js 20+, dependencies in web/package.json (Vue 3, PrimeVue, Tailwind CSS, Pinia, VueFlow, ECharts, Axios, vue-draggable-plus, Vitest, fast-check, ESLint, vue-tsc).web/src/stores/auth.ts (2)
139-143: LGTM!The comment update clearly documents the intentional use of
window.location.hreffor redirects from the Zustand store. This is the correct approach since the store operates outside the React component tree where React Router's navigation hooks aren't available.
206-215: LGTM!The selector hooks follow Zustand best practices with inline selectors, preventing unnecessary re-renders. The
useMustChangePasswordfallback logic properly handles the page refresh scenario.CLAUDE.md (3)
56-57: LGTM!The Storybook commands are correctly documented with the appropriate port and build script names.
124-134: LGTM!The package structure documentation accurately reflects the new router-driven architecture with
pages/for lazy-loaded components,router/for configuration and guards, and the updatedcomponents/description including the layout directory.
237-237: LGTM!The CI jobs description correctly includes the new
storybook-buildstep in the dashboard job pipeline.web/src/stores/setup.ts (1)
11-27: LGTM!The store implementation is clean and follows Zustand patterns correctly:
- Guards against concurrent fetches with the
loadingcheck- Correctly maps the API response (
!status.needs_setup)- Intentionally leaves
setupCompleteasnullon error to allow retry on next navigationweb/src/components/layout/SidebarNavItem.tsx (1)
15-56: LGTM!Well-structured component with good practices:
- Proper use of
NavLink'sclassNamefunction for active state styling- Accessibility handled correctly (
aria-hiddenon decorative icon,titlefor collapsed tooltip)- Badge clamping logic (
99+) is appropriate for UI display- The
endprop is correctly forwarded toNavLinkfor exact route matching.gitignore (1)
54-54: LGTM!Correctly adds the Storybook build output directory to
.gitignore, preventing build artifacts from being committed.web/src/pages/SetupPage.tsx (1)
1-7: LGTM!Appropriate stub implementation for the setup wizard page. The use of
h-screen(instead ofh-fullused in app-shell pages) is correct since this page renders outside the main layout.web/src/pages/AgentDetailPage.tsx (1)
1-7: LGTM!Consistent stub implementation following the same pattern as other authenticated route pages with
h-fullfor proper layout integration within the app shell.web/src/pages/DashboardPage.tsx (1)
1-7: LGTM!Clean stub implementation with default export enabling lazy loading via
React.lazy(). Consistent styling pattern with other authenticated route pages.web/src/pages/BudgetForecastPage.tsx (1)
1-7: Looks good for a placeholder route page.Line 1-7 is clean and correct for an initial stub component.
web/src/pages/ProviderDetailPage.tsx (1)
1-7: Stub implementation is correct.Line 1-7 is valid and consistent with the app-shell page scaffold.
web/src/pages/AgentsPage.tsx (1)
1-7: No concerns on this page stub.Line 1-7 is straightforward and implementation is correct.
web/src/pages/ApprovalsPage.tsx (1)
1-7: Implementation is good.Line 1-7 is valid and appropriate for the current scaffold phase.
web/src/pages/SettingsPage.tsx (1)
1-7: LGTM for this route placeholder.Line 1-7 is correct and consistent with other stub pages.
web/src/pages/ProvidersPage.tsx (1)
1-7: No changes requested here.Line 1-7 is clean and correctly implemented.
web/src/pages/MessagesPage.tsx (1)
1-7: Looks correct as-is.Line 1-7 properly implements a simple placeholder page.
web/src/pages/LoginPage.tsx (1)
1-7: Good implementation for the public login stub.Line 1-7 is valid and aligns with the route scaffold.
web/src/pages/NotFoundPage.tsx (1)
1-14: LGTM!Clean implementation of the 404 page. The
asChildpattern withButtonwrappingLinkis the correct approach for shadcn/ui + React Router composition, and the Tailwind classes properly use the project's custom surface color tokens.web/.storybook/preview.tsx (1)
4-18: LGTM!The Storybook preview configuration correctly sets up dark theme with Tailwind integration. The decorator applying the
darkclass enables Tailwind's dark mode variants, and importing the global CSS ensures all design tokens are available in stories.web/src/App.tsx (1)
1-5: LGTM!Clean and minimal entry point that properly delegates routing to the dedicated router module. This separation of concerns makes the app structure easier to maintain and test.
web/.storybook/main.ts (1)
1-18: LGTM!The Storybook configuration correctly integrates with Vite and Tailwind CSS 4. The
viteFinalhook properly adds the Tailwind plugin while preserving existing plugins, and the addon selection (essentials, a11y, interactions) provides good development and testing capabilities..github/workflows/ci.yml (1)
309-330: LGTM!The Storybook build job follows the established patterns for dashboard CI jobs. Good choices include using
--disable-telemetryto avoid unnecessary network calls in CI and properly integrating with the path filter and CI pass gate.web/src/__tests__/components/layout/SidebarNavItem.test.tsx (1)
1-55: LGTM!Comprehensive test coverage for
SidebarNavItemincluding collapsed/expanded states, badge rendering logic, and the 99+ cap. The tests use appropriate Testing Library queries and therenderWithRouterhelper correctly handles theNavLinkrouting context.web/src/components/layout/AppLayout.tsx (1)
14-28: LGTM!Well-structured layout component with proper Suspense boundary placement for lazy-loaded routes. The flexbox layout with controlled overflow ensures the sidebar remains fixed while the main content scrolls independently.
web/src/__tests__/router/guards.test.tsx (4)
1-39: LGTM! Well-structured test setup with proper isolation.The test file has good patterns:
- API mock at module level for
getSetupStatuswindow.locationoverride to prevent side effects from auth store'sclearAuth()redirect logicresetStores()helper properly resets both Zustand stores and clears localStorage
41-82: LGTM! AuthGuard test coverage is complete.Both key scenarios are tested:
- Unauthenticated users redirect to
/login- Authenticated users see protected content
84-181: LGTM! Comprehensive SetupGuard coverage.Good async testing pattern using dynamic import with
vi.mocked()andwaitForfor the fetch trigger test.
183-336: LGTM! GuestGuard and SetupCompleteGuard tests are thorough.All guard edge cases are covered including the
SetupCompleteGuard's complex logic for unauthenticated passthrough vs authenticated+setup-complete redirect.web/src/__tests__/components/layout/Sidebar.test.tsx (1)
1-46: LGTM! Clean test setup with proper auth state initialization.Good patterns:
window.locationoverride for side-effect isolation- Separate
resetStore()andsetup()helpers for clarity- User mock object matches the auth store's user type
web/src/components/layout/StatusBar.tsx (1)
1-62: LGTM! Clean StatusBar skeleton implementation.Good patterns:
- Placeholder values (
--) for data that will be populated later- Proper use of
aria-hidden="true"on decorativeDotelements- Helper components (
Divider,Dot,StatusItem) keep the main component readable- Tailwind classes follow the project's design tokens (
surface-*,brand-*,success-*,warning-*)web/src/__tests__/stores/setup.test.ts (1)
1-105: LGTM! Comprehensive setup store test coverage.Excellent patterns:
- Tests initial state, both success paths (
needs_setup: true/false), concurrent fetch prevention, and error handling- The concurrent fetch test (Lines 65-93) uses a controlled Promise to verify the
loadingguard prevents duplicate requests- Error handling test confirms
setupCompletestaysnullon failure (allowing retry)web/src/__tests__/test-utils.tsx (2)
17-37: LGTM! Useful test utilities for router-dependent components.Two well-designed helpers:
renderWithRouter: for testing components that need router context but don't care about specific routesrenderRoutes: for testing route configurations and guard behavior with full route trees
6-9: 🧹 Nitpick | 🔵 TrivialUnused
routesproperty in interface.The
routesproperty inRenderWithRouterOptionsis defined but never used by eitherrenderWithRouterorrenderRoutes. Consider removing it or documenting its intended use.♻️ Remove unused property
interface RenderWithRouterOptions { initialEntries?: string[] - routes?: RouteObject[] }> Likely an incorrect or invalid review comment.web/src/router/index.tsx (2)
1-40: LGTM! Well-structured lazy loading with consistent fallback.Good patterns:
- All 20+ page components are lazy-loaded for optimal code splitting
SuspenseWrapperprovides a uniform loading experience- Lazy-loading
AppLayoutitself ensures the shell doesn't block initial page load
42-117: LGTM! Router configuration is well-organized.Guard composition is correct:
GuestGuardon/loginredirects authenticated users awaySetupCompleteGuardon/setuproutes prevents access after setup is doneAuthGuard→SetupGuard→AppLayoutchain ensures authenticated users with completed setup see the app shellChild routes under
AppLayoutdon't need individualSuspenseWrappersinceAppLayoutalready wraps its<Outlet />in<Suspense>(perAppLayout.tsxLines 20-22).web/src/router/routes.ts (1)
1-31: LGTM! Clean centralized route definitions.Good patterns:
as constprovides type-safe literal types for route paths- Single source of truth for URL patterns used across guards, router, and navigation
- Parameterized routes (
:taskId,:agentName, etc.) are clearly namedweb/src/components/ui/button.stories.tsx (1)
1-70: Well-structured Storybook stories with good coverage.The stories file follows CSF 3 format correctly, includes argTypes for interactive controls, and provides comprehensive coverage of Button variants and sizes. The
AllVariantsstory is a nice addition for visual comparison.web/src/components/layout/Sidebar.tsx (2)
27-40: Good implementation of persisted collapse state.The pattern of initializing state from localStorage via a lazy initializer and syncing on toggle is correct. This ensures the sidebar remembers user preference across sessions.
42-135: Clean implementation of sidebar navigation structure.The component is well-organized with clear sections (header, primary nav, workspace nav), proper conditional rendering based on collapsed state, and good use of the
cn()utility for class merging. The route constants fromROUTESensure consistency.web/src/__tests__/App.test.tsx (1)
6-48: Solid test setup with proper isolation.The test configuration correctly:
- Mocks the setup API to control guard behavior
- Patches
window.locationto prevent side effects from the auth store's hard redirect- Resets Zustand stores and clears localStorage before each test
This ensures reliable, isolated test execution.
web/src/router/guards.tsx (4)
11-19: AuthGuard implementation is clean and correct.The guard correctly checks authentication state and redirects unauthenticated users to login. Using
replaceprevents the login page from appearing in history when navigating back.
26-50: SetupGuard correctly handles async setup status check.The guard properly:
- Triggers fetch only when needed (
setupComplete === null && !loading)- Shows loading state while fetching
- Redirects to setup if incomplete
The retry-on-error behavior (leaving
setupCompleteasnull) aligns with the store's design.
55-63: GuestGuard correctly prevents authenticated users from accessing login.Simple and effective implementation that redirects logged-in users to the dashboard.
69-100: SetupCompleteGuard correctly handles the setup access control.The guard appropriately:
- Allows unauthenticated access (first-time setup flow)
- Fetches setup status only for authenticated users
- Redirects to dashboard if setup is already complete
This prevents authenticated users from re-running setup while allowing the initial admin creation flow.
8f86f70 to
4dba2f5
Compare
There was a problem hiding this comment.
Actionable comments posted: 7
♻️ Duplicate comments (1)
web/src/components/layout/Sidebar.tsx (1)
142-155:⚠️ Potential issue | 🟡 MinorAdd an accessible name to the collapse toggle.
When the sidebar is collapsed, this control is icon-only and
titleis not a reliable accessible name. Please add an explicit label here so assistive tech can still announce the action.♿ Minimal fix
<button onClick={toggleCollapse} title={collapsed ? 'Expand sidebar' : 'Collapse sidebar'} + aria-label={collapsed ? 'Expand sidebar' : 'Collapse sidebar'} + aria-expanded={!collapsed} className="flex items-center gap-3 rounded-md px-3 py-2 text-sm text-surface-500 transition-colors hover:bg-surface-100 hover:text-surface-700" >🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/components/layout/Sidebar.tsx` around lines 142 - 155, The collapse toggle button currently relies on title and becomes icon-only when collapsed, so add an explicit accessible name by adding an aria-label (or aria-labelledby) that reflects the current state using the existing collapsed variable; update the button where toggleCollapse is used to include aria-label={collapsed ? 'Expand sidebar' : 'Collapse sidebar'} (keeping the visible text when not collapsed and icons PanelLeftOpen/PanelLeftClose unchanged) so assistive tech can always announce the action.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@web/src/__tests__/App.test.tsx`:
- Around line 42-45: The test resets useSetupStore state but omits the error
flag—update the call to useSetupStore.setState used in the test (the block that
sets setupComplete and loading) to also reset the error property (e.g., set
error: null or false as appropriate) so the store is fully cleared between tests
and prevents leaking setup-guard failure state into subsequent App renders.
In `@web/src/components/layout/SidebarNavItem.tsx`:
- Around line 42-46: The JSX expression rendering the badge in SidebarNavItem
uses a single long className string for the <span> (referenced by the badge prop
check and the span that shows {badge > 99 ? '99+' : badge}), which causes the
132-character line; split the className into multiple concatenated literals or
use template/string joining across multiple lines (or place each Tailwind
utility on its own line within the JSX attribute) so the line length is <=88
characters while preserving the same classes and conditional rendering logic.
In `@web/src/components/layout/StatusBar.tsx`:
- Around line 6-8: Replace the hard-coded vendor string in the StatusBar
component: locate the span containing "SynthOrg" in StatusBar.tsx and change it
to a generic placeholder such as "example-provider" (or another approved generic
identifier like "example-vendor") so UI copy does not contain real vendor names;
update any tests or snapshots referencing the "SynthOrg" literal to the new
placeholder as well.
- Line 5: The long className string in the StatusBar component's div exceeds the
88-char limit; break the class list into multiple concatenated strings or use
the project's classnames helper (e.g., cn) when setting className on the div in
StatusBar.tsx so the line length is under 88 characters while preserving the
same classes and order.
In `@web/src/router/guards.tsx`:
- Around line 42-55: The guard currently mounts protected children as soon as
useIsAuthenticated() is truthy (restored token) while fetchUser() runs
asynchronously, causing flashes and unhandled rejections; change the guard to
track a validation state (e.g., isValidating) and only render <Outlet /> after
fetchUser() completes successfully, showing a loading UI while pending and
handling errors by calling clearAuth() or navigating to ROUTES.LOGIN; ensure the
useEffect that calls fetchUser() around useEffect, isAuthenticated, user,
fetchUser catches/awaits the returned promise to avoid unhandled rejections and
toggles isValidating appropriately so Outlet is not rendered until validation
resolves.
In `@web/src/router/routes.ts`:
- Around line 30-31: PUBLIC_ROUTES currently lists ROUTES.LOGIN and ROUTES.SETUP
but omits ROUTES.SETUP_STEP, causing multi-step setup routes to be treated as
protected; update PUBLIC_ROUTES to include ROUTES.SETUP_STEP (or replace the
static array with a pattern check that accepts the setup step path) so
authentication bypass logic treats both ROUTES.SETUP and ROUTES.SETUP_STEP
consistently; locate and modify the exported PUBLIC_ROUTES constant in routes.ts
and ensure any auth-checking code that consumes PUBLIC_ROUTES continues to work
with the added value or new pattern.
In `@web/src/stores/setup.ts`:
- Around line 24-27: The catch block currently calls set({ loading: false,
error: true }) but leaves the previous setupComplete value intact, which can
cause stale access decisions; update the error path in the fetch/refresh handler
to explicitly reset setupComplete to null (e.g., set({ loading: false, error:
true, setupComplete: null })) so the guard sees an unknown state and shows
retry/error flow; locate the catch that calls set(...) in
web/src/stores/setup.ts and add setupComplete: null to that set call.
---
Duplicate comments:
In `@web/src/components/layout/Sidebar.tsx`:
- Around line 142-155: The collapse toggle button currently relies on title and
becomes icon-only when collapsed, so add an explicit accessible name by adding
an aria-label (or aria-labelledby) that reflects the current state using the
existing collapsed variable; update the button where toggleCollapse is used to
include aria-label={collapsed ? 'Expand sidebar' : 'Collapse sidebar'} (keeping
the visible text when not collapsed and icons PanelLeftOpen/PanelLeftClose
unchanged) so assistive tech can always announce the action.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 6387875e-0f30-419c-b235-9f08e1fa0322
⛔ Files ignored due to path filters (1)
web/package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (46)
.github/workflows/ci.yml.gitignoreCLAUDE.mdweb/.npmrcweb/.storybook/main.tsweb/.storybook/preview.tsxweb/package.jsonweb/src/App.tsxweb/src/__tests__/App.test.tsxweb/src/__tests__/components/layout/Sidebar.test.tsxweb/src/__tests__/components/layout/SidebarNavItem.test.tsxweb/src/__tests__/router/guards.test.tsxweb/src/__tests__/stores/setup.test.tsweb/src/__tests__/test-utils.tsxweb/src/components/layout/AppLayout.tsxweb/src/components/layout/PlaceholderPage.tsxweb/src/components/layout/Sidebar.stories.tsxweb/src/components/layout/Sidebar.tsxweb/src/components/layout/SidebarNavItem.tsxweb/src/components/layout/StatusBar.tsxweb/src/components/ui/button.stories.tsxweb/src/pages/AgentDetailPage.tsxweb/src/pages/AgentsPage.tsxweb/src/pages/ApprovalsPage.tsxweb/src/pages/BudgetForecastPage.tsxweb/src/pages/BudgetPage.tsxweb/src/pages/DashboardPage.tsxweb/src/pages/LoginPage.tsxweb/src/pages/MeetingDetailPage.tsxweb/src/pages/MeetingsPage.tsxweb/src/pages/MessagesPage.tsxweb/src/pages/NotFoundPage.tsxweb/src/pages/OrgChartPage.tsxweb/src/pages/OrgEditPage.tsxweb/src/pages/ProviderDetailPage.tsxweb/src/pages/ProvidersPage.tsxweb/src/pages/SettingsNamespacePage.tsxweb/src/pages/SettingsPage.tsxweb/src/pages/SetupPage.tsxweb/src/pages/TaskBoardPage.tsxweb/src/pages/TaskDetailPage.tsxweb/src/router/guards.tsxweb/src/router/index.tsxweb/src/router/routes.tsweb/src/stores/auth.tsweb/src/stores/setup.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Build Backend
- GitHub Check: Dependency Review
- GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (3)
web/src/**/*.{tsx,ts}
📄 CodeRabbit inference engine (CLAUDE.md)
web/src/**/*.{tsx,ts}: React components must use TypeScript and follow shadcn/ui + Tailwind CSS conventions. Line length: 88 characters.
React code must pass ESLint (configured with@eslint-react/eslint-plugin) and TypeScript type-check
Never use real vendor names in React code, tests, or config examples. Use generic names:example-provider,example-large-001, etc.
Files:
web/src/pages/TaskDetailPage.tsxweb/src/pages/SettingsPage.tsxweb/src/pages/MeetingDetailPage.tsxweb/src/pages/ProvidersPage.tsxweb/src/components/layout/PlaceholderPage.tsxweb/src/pages/OrgEditPage.tsxweb/src/pages/BudgetForecastPage.tsxweb/src/pages/AgentDetailPage.tsxweb/src/pages/ProviderDetailPage.tsxweb/src/pages/BudgetPage.tsxweb/src/pages/DashboardPage.tsxweb/src/pages/OrgChartPage.tsxweb/src/pages/AgentsPage.tsxweb/src/pages/SetupPage.tsxweb/src/pages/ApprovalsPage.tsxweb/src/pages/LoginPage.tsxweb/src/pages/NotFoundPage.tsxweb/src/pages/SettingsNamespacePage.tsxweb/src/pages/TaskBoardPage.tsxweb/src/components/layout/AppLayout.tsxweb/src/__tests__/components/layout/SidebarNavItem.test.tsxweb/src/components/layout/Sidebar.stories.tsxweb/src/router/index.tsxweb/src/components/layout/StatusBar.tsxweb/src/stores/setup.tsweb/src/components/layout/SidebarNavItem.tsxweb/src/__tests__/test-utils.tsxweb/src/__tests__/stores/setup.test.tsweb/src/__tests__/App.test.tsxweb/src/pages/MessagesPage.tsxweb/src/__tests__/components/layout/Sidebar.test.tsxweb/src/__tests__/router/guards.test.tsxweb/src/App.tsxweb/src/router/routes.tsweb/src/components/layout/Sidebar.tsxweb/src/router/guards.tsxweb/src/pages/MeetingsPage.tsxweb/src/components/ui/button.stories.tsxweb/src/stores/auth.ts
**/*.json
📄 CodeRabbit inference engine (CLAUDE.md)
JSON files must be valid and checked by pre-commit hooks
Files:
web/package.json
web/src/__tests__/**/*.test.{tsx,ts}
📄 CodeRabbit inference engine (CLAUDE.md)
web/src/__tests__/**/*.test.{tsx,ts}: React unit tests must use Vitest with@testing-library/react. Coverage is scoped to files changed vs origin/main.
React property-based testing must use fast-check (fc.assert+fc.property)
Files:
web/src/__tests__/components/layout/SidebarNavItem.test.tsxweb/src/__tests__/stores/setup.test.tsweb/src/__tests__/App.test.tsxweb/src/__tests__/components/layout/Sidebar.test.tsxweb/src/__tests__/router/guards.test.tsx
🧠 Learnings (31)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to docker/{Dockerfile*,compose.yml} : Docker: Backend uses 3-stage build (builder → setup → distroless runtime), Chainguard Python, non-root (UID 65532), CIS-hardened. Web uses nginxinc/nginx-unprivileged, Vue 3 SPA with PrimeVue + Tailwind CSS, SPA routing, API/WebSocket proxy to backend.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to web/** : Web dashboard: Node.js 20+, dependencies in web/package.json (Vue 3, PrimeVue, Tailwind CSS, Pinia, VueFlow, ECharts, Axios, vue-draggable-plus, Vitest, fast-check, ESLint, vue-tsc).
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T15:43:05.601Z
Learning: Applies to web/package.json : Web dashboard Node.js 20+; dependencies in web/package.json (Vue 3, PrimeVue, Tailwind CSS, Pinia, VueFlow, ECharts, Axios, vue-draggable-plus, Vitest, ESLint, vue-tsc)
📚 Learning: 2026-03-14T15:43:05.601Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T15:43:05.601Z
Learning: Applies to web/package.json : Web dashboard Node.js 20+; dependencies in web/package.json (Vue 3, PrimeVue, Tailwind CSS, Pinia, VueFlow, ECharts, Axios, vue-draggable-plus, Vitest, ESLint, vue-tsc)
Applied to files:
web/.npmrc.gitignore.github/workflows/ci.ymlweb/package.jsonCLAUDE.md
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to web/** : Web dashboard: Node.js 20+, dependencies in web/package.json (Vue 3, PrimeVue, Tailwind CSS, Pinia, VueFlow, ECharts, Axios, vue-draggable-plus, Vitest, fast-check, ESLint, vue-tsc).
Applied to files:
web/.npmrc.gitignore.github/workflows/ci.ymlweb/package.jsonCLAUDE.mdweb/src/App.tsx
📚 Learning: 2026-03-20T08:28:32.845Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T08:28:32.845Z
Learning: Applies to web/src/__tests__/**/*.{ts,js} : Dashboard testing: Vitest unit tests organized by feature under `web/src/__tests__/`. Use fast-check for property-based testing (`fc.assert` + `fc.property`).
Applied to files:
.gitignoreweb/package.jsonCLAUDE.mdweb/src/__tests__/components/layout/SidebarNavItem.test.tsxweb/src/__tests__/test-utils.tsxweb/src/__tests__/stores/setup.test.tsweb/src/__tests__/App.test.tsxweb/src/__tests__/components/layout/Sidebar.test.tsxweb/src/__tests__/router/guards.test.tsx
📚 Learning: 2026-03-24T20:58:10.766Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T20:58:10.766Z
Learning: Applies to web/src/__tests__/**/*.test.{tsx,ts} : React unit tests must use Vitest with `testing-library/react`. Coverage is scoped to files changed vs origin/main.
Applied to files:
.gitignoreweb/.storybook/main.tsweb/package.jsonweb/src/__tests__/components/layout/SidebarNavItem.test.tsxweb/src/__tests__/test-utils.tsxweb/src/__tests__/stores/setup.test.tsweb/src/__tests__/App.test.tsxweb/src/__tests__/components/layout/Sidebar.test.tsxweb/src/__tests__/router/guards.test.tsx
📚 Learning: 2026-03-15T21:20:09.993Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:20:09.993Z
Learning: Applies to web/src/components/** : Vue components organized by feature (agents/, approvals/, budget/, common/, dashboard/, layout/, messages/, org-chart/, tasks/).
Applied to files:
.gitignoreCLAUDE.md
📚 Learning: 2026-03-24T20:58:10.766Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T20:58:10.766Z
Learning: Applies to web/src/**/*.{tsx,ts} : Never use real vendor names in React code, tests, or config examples. Use generic names: `example-provider`, `example-large-001`, etc.
Applied to files:
web/src/pages/ProvidersPage.tsxweb/src/components/layout/PlaceholderPage.tsxweb/src/pages/ProviderDetailPage.tsxweb/src/__tests__/test-utils.tsxweb/src/__tests__/App.test.tsx
📚 Learning: 2026-03-24T20:58:10.766Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T20:58:10.766Z
Learning: Applies to web/src/**/*.{tsx,ts} : React components must use TypeScript and follow shadcn/ui + Tailwind CSS conventions. Line length: 88 characters.
Applied to files:
web/src/pages/SetupPage.tsxweb/src/pages/ApprovalsPage.tsxweb/src/components/layout/AppLayout.tsxCLAUDE.mdweb/src/__tests__/App.test.tsxweb/src/components/layout/Sidebar.tsx
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to .github/workflows/**/*.yml : Path filtering: dorny/paths-filter detects Python/dashboard/docker changes; jobs only run when their domain is affected. CLI has its own workflow (cli.yml).
Applied to files:
.github/workflows/ci.ymlCLAUDE.md
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/*.yml : Dependabot: daily updates for uv + github-actions + npm + pre-commit + docker + gomod, grouped minor/patch, no auto-merge. Use `/review-dep-pr` to review Dependabot PRs before merging.
Applied to files:
.github/workflows/ci.ymlCLAUDE.md
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/docker.yml : Docker workflow: builds backend + web + sandbox images, pushes to GHCR, signs with cosign. SLSA L3 provenance attestations via actions/attest-build-provenance. Scans: Trivy (CRITICAL = hard fail, HIGH = warn) + Grype (critical cutoff) + CIS Docker Benchmark v1.6.0 compliance (informational). CVE triage via .github/.trivyignore.yaml and .github/.grype.yaml. Images only pushed after scans pass. Triggers on push to main and version tags (v*).
Applied to files:
.github/workflows/ci.ymlCLAUDE.md
📚 Learning: 2026-03-15T12:00:18.113Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T12:00:18.113Z
Learning: Applies to .github/workflows/docker.yml : CI Docker: build → scan → push to GHCR + cosign sign + SLSA L3 provenance via attest-build-provenance (images only pushed after Trivy/Grype scans pass).
Applied to files:
.github/workflows/ci.ymlCLAUDE.md
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/cli.yml : CLI workflow: Go lint (golangci-lint + go vet) + test (-race -coverprofile) + build (cross-compile: linux/darwin/windows × amd64/arm64) + govulncheck + fuzz testing (main-only, 30s/target, continue-on-error, matrix over 4 packages). cli-pass gate includes fuzz as informational. GoReleaser release on v* tags. Cosign keyless signing of checksums.txt. SLSA L3 provenance attestations. Sigstore bundle (.sigstore.json) attached. Post-release appends checksums/verification/provenance to draft release notes.
Applied to files:
.github/workflows/ci.ymlCLAUDE.md
📚 Learning: 2026-03-19T11:19:40.044Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:19:40.044Z
Learning: CLI workflow (`.github/workflows/cli.yml`) runs Go lint (golangci-lint + go vet) + test (race, coverage) + build (cross-compile matrix) + vulnerability check (govulncheck) + fuzz testing. Cross-compiles for linux/darwin/windows × amd64/arm64. GoReleaser release on v* tags with cosign keyless signing and SLSA L3 attestations.
Applied to files:
.github/workflows/ci.ymlCLAUDE.md
📚 Learning: 2026-03-24T20:58:10.766Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T20:58:10.766Z
Learning: Applies to web/src/**/*.{tsx,ts} : React code must pass ESLint (configured with `eslint-react/eslint-plugin`) and TypeScript type-check
Applied to files:
web/package.jsonCLAUDE.md
📚 Learning: 2026-03-16T19:52:03.656Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T19:52:03.656Z
Learning: Applies to cli/**/*.go : Lint CLI Go code with golangci-lint and go vet; test with go test -race; check vulnerabilities with govulncheck
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-19T11:30:29.217Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:30:29.217Z
Learning: Applies to cli/**/*.go : Run Go lint via `golangci-lint run`, vet via `go vet`, tests via `go test ./...`, and fuzz via `go test -fuzz=FuzzTarget -fuzztime=30s`
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-19T11:19:40.044Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:19:40.044Z
Learning: Applies to cli/**/*.go : Lint Go code with `golangci-lint` and `go vet`. Run tests with `-race` flag to detect race conditions.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to cli/**/*.go : Go CLI (Go 1.26+) uses Cobra for commands, charmbracelet/huh for interactive CLI, charmbracelet/lipgloss for styled output. Cross-platform builds (linux/darwin/windows × amd64/arm64). GoReleaser for releases with cosign keyless signing of checksums.txt. SLSA L3 provenance attestations via actions/attest-build-provenance.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-24T20:58:10.766Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T20:58:10.766Z
Learning: Applies to web/src/hooks/*.{tsx,ts} : React hooks must be in `web/src/hooks/` directory and follow React hooks conventions. Custom hooks must be prefixed with `use`.
Applied to files:
CLAUDE.mdweb/src/__tests__/test-utils.tsx
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/**/*.py : Package structure: src/synthorg/ organized as: api/ (REST+WebSocket, Litestar), auth/ (auth subpackage), backup/ (scheduled/manual backups), budget/ (cost tracking, CFO), cli/ (superseded by Go CLI), communication/ (message bus, meetings), config/ (YAML loading), core/ (domain models, resilience config), engine/ (orchestration, task state, coordination, approval gates, stagnation detection, context budget, compaction), hr/ (hiring, performance, promotion), memory/ (pluggable backend, Mem0, retrieval, consolidation), persistence/ (operational data, SQLite, settings), observability/ (logging, correlation, sinks), providers/ (LLM abstraction, LiteLLM, auth types, presets, runtime CRUD), settings/ (runtime-editable, typed definitions, encryption, config bridge), security/ (SecOps, rule engine, output scanning, progressive trust, autonomy levels), templates/ (company templates, personalities), tools/ (registry, built-in tools, git, sandbox, code_runner, MCP...
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to docker/{Dockerfile*,compose.yml} : Docker: Backend uses 3-stage build (builder → setup → distroless runtime), Chainguard Python, non-root (UID 65532), CIS-hardened. Web uses nginxinc/nginx-unprivileged, Vue 3 SPA with PrimeVue + Tailwind CSS, SPA routing, API/WebSocket proxy to backend.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Pre-push hooks: mypy type-check + pytest unit tests + golangci-lint + go vet + go test (CLI, conditional on cli/**/*.go) (fast gate before push, skipped in pre-commit.ci — dedicated CI jobs already run these).
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Pre-commit hooks: trailing-whitespace, end-of-file-fixer, check-yaml, check-toml, check-json, check-merge-conflict, check-added-large-files, no-commit-to-branch (main), ruff check+format, gitleaks, hadolint (Dockerfile linting).
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/finalize-release.yml : Finalize Release workflow: publishes draft releases created by Release Please. Triggers on workflow_run completion of Docker and CLI workflows. Verifies both workflows succeeded for the associated tag before publishing. Extracts CLI checksums, cosign verification, and container verification data from HTML comments, assembles into combined Verification section. Guards against PR-triggered runs. Handles TOCTOU races. Immutable releases enabled—once published, release assets and body cannot be modified.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to pyproject.toml : Dependencies: all versions use == in pyproject.toml. Groups: test (pytest + plugins, hypothesis), dev (includes test + ruff, mypy, pre-commit, commitizen, pip-audit). Required: mem0ai (Mem0 memory backend — the default and currently only backend). Install: uv sync installs everything (dev group is default).
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-24T20:58:10.766Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T20:58:10.766Z
Learning: Applies to pyproject.toml : Dependencies are organized in groups: `test` (pytest + plugins, hypothesis), `dev` (includes test + ruff, mypy, pre-commit, commitizen, pip-audit). Install with `uv sync`.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-19T11:19:40.044Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:19:40.044Z
Learning: Applies to go.mod : Maintain Go 1.26+ requirement. Dependencies: Cobra (CLI framework), charmbracelet/huh and charmbracelet/lipgloss (UI), sigstore-go (code signing), go-containerregistry (container image verification), go-tuf (TUF client for Sigstore).
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to cli/** : CLI: Go 1.26+, dependencies in cli/go.mod (Cobra, charmbracelet/huh).
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to cli/go.mod : Go CLI dependencies: Go 1.26+, Cobra (commands), charmbracelet/huh (interactive CLI), charmbracelet/lipgloss (styled output).
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-24T20:58:10.766Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T20:58:10.766Z
Learning: Applies to web/src/__tests__/**/*.test.{tsx,ts} : React property-based testing must use fast-check (`fc.assert` + `fc.property`)
Applied to files:
web/src/__tests__/components/layout/SidebarNavItem.test.tsxweb/src/__tests__/test-utils.tsxweb/src/__tests__/App.test.tsxweb/src/__tests__/components/layout/Sidebar.test.tsxweb/src/__tests__/router/guards.test.tsx
🧬 Code graph analysis (29)
web/src/pages/TaskDetailPage.tsx (1)
web/src/components/layout/PlaceholderPage.tsx (1)
PlaceholderPage(2-8)
web/src/pages/SettingsPage.tsx (1)
web/src/components/layout/PlaceholderPage.tsx (1)
PlaceholderPage(2-8)
web/src/pages/MeetingDetailPage.tsx (1)
web/src/components/layout/PlaceholderPage.tsx (1)
PlaceholderPage(2-8)
web/src/pages/ProvidersPage.tsx (1)
web/src/components/layout/PlaceholderPage.tsx (1)
PlaceholderPage(2-8)
web/src/pages/OrgEditPage.tsx (1)
web/src/components/layout/PlaceholderPage.tsx (1)
PlaceholderPage(2-8)
web/src/pages/BudgetForecastPage.tsx (1)
web/src/components/layout/PlaceholderPage.tsx (1)
PlaceholderPage(2-8)
web/src/pages/AgentDetailPage.tsx (1)
web/src/components/layout/PlaceholderPage.tsx (1)
PlaceholderPage(2-8)
web/src/pages/ProviderDetailPage.tsx (1)
web/src/components/layout/PlaceholderPage.tsx (1)
PlaceholderPage(2-8)
web/src/pages/BudgetPage.tsx (1)
web/src/components/layout/PlaceholderPage.tsx (1)
PlaceholderPage(2-8)
web/src/pages/DashboardPage.tsx (1)
web/src/components/layout/PlaceholderPage.tsx (1)
PlaceholderPage(2-8)
web/src/pages/OrgChartPage.tsx (1)
web/src/components/layout/PlaceholderPage.tsx (1)
PlaceholderPage(2-8)
web/src/pages/AgentsPage.tsx (1)
web/src/components/layout/PlaceholderPage.tsx (1)
PlaceholderPage(2-8)
web/src/pages/ApprovalsPage.tsx (1)
web/src/components/layout/PlaceholderPage.tsx (1)
PlaceholderPage(2-8)
web/src/pages/NotFoundPage.tsx (1)
web/src/components/ui/button.stories.tsx (1)
Link(43-45)
web/src/pages/SettingsNamespacePage.tsx (1)
web/src/components/layout/PlaceholderPage.tsx (1)
PlaceholderPage(2-8)
web/src/pages/TaskBoardPage.tsx (1)
web/src/components/layout/PlaceholderPage.tsx (1)
PlaceholderPage(2-8)
web/src/components/layout/AppLayout.tsx (2)
web/src/components/layout/StatusBar.tsx (1)
StatusBar(3-43)web/src/components/layout/Sidebar.tsx (1)
Sidebar(27-225)
web/src/__tests__/components/layout/SidebarNavItem.test.tsx (2)
web/src/__tests__/test-utils.tsx (1)
renderWithRouter(16-25)web/src/components/layout/SidebarNavItem.tsx (1)
SidebarNavItem(15-57)
web/src/components/layout/Sidebar.stories.tsx (2)
web/src/components/layout/Sidebar.tsx (1)
Sidebar(27-225)web/src/stores/auth.ts (1)
useAuthStore(61-210)
web/src/router/index.tsx (2)
web/src/components/layout/AppLayout.tsx (1)
AppLayout(14-28)web/src/router/guards.tsx (4)
GuestGuard(94-102)SetupCompleteGuard(110-144)AuthGuard(37-56)SetupGuard(64-89)
web/src/stores/setup.ts (1)
web/src/api/endpoints/setup.ts (1)
getSetupStatus(19-22)
web/src/__tests__/stores/setup.test.ts (2)
web/src/stores/setup.ts (1)
useSetupStore(13-30)web/src/api/endpoints/setup.ts (1)
getSetupStatus(19-22)
web/src/__tests__/App.test.tsx (3)
web/src/stores/auth.ts (1)
useAuthStore(61-210)web/src/stores/setup.ts (1)
useSetupStore(13-30)web/src/App.tsx (1)
App(3-5)
web/src/pages/MessagesPage.tsx (1)
web/src/components/layout/PlaceholderPage.tsx (1)
PlaceholderPage(2-8)
web/src/__tests__/components/layout/Sidebar.test.tsx (3)
web/src/stores/auth.ts (2)
useAuthStore(61-210)setup(156-158)web/src/__tests__/test-utils.tsx (1)
renderWithRouter(16-25)web/src/components/layout/Sidebar.tsx (1)
Sidebar(27-225)
web/src/__tests__/router/guards.test.tsx (5)
web/src/stores/auth.ts (1)
useAuthStore(61-210)web/src/stores/setup.ts (1)
useSetupStore(13-30)web/src/__tests__/test-utils.tsx (1)
renderRoutes(30-36)web/src/router/guards.tsx (4)
AuthGuard(37-56)SetupGuard(64-89)GuestGuard(94-102)SetupCompleteGuard(110-144)web/src/api/endpoints/setup.ts (1)
getSetupStatus(19-22)
web/src/App.tsx (1)
web/src/router/index.tsx (1)
AppRouter(115-117)
web/src/router/guards.tsx (3)
web/src/stores/auth.ts (3)
useIsAuthenticated(214-214)useAuthStore(61-210)fetchUser(160-184)web/src/router/routes.ts (1)
ROUTES(7-28)web/src/stores/setup.ts (2)
useSetupStore(13-30)fetchSetupStatus(18-29)
web/src/pages/MeetingsPage.tsx (1)
web/src/components/layout/PlaceholderPage.tsx (1)
PlaceholderPage(2-8)
🔇 Additional comments (41)
.gitignore (1)
54-54: Ignoring Storybook build output is correct.This keeps generated static artifacts out of source control and reduces noisy diffs.
web/src/components/layout/PlaceholderPage.tsx (1)
1-8: Clean reusable placeholder component.Typed props and minimal markup make this a good scaffold for unimplemented routes.
web/src/pages/TaskDetailPage.tsx (1)
1-5: Good use of shared page scaffold.This keeps page stubs consistent while routing is being built out.
web/src/pages/MeetingDetailPage.tsx (1)
1-5: Implementation looks correct.The page wrapper is simple and consistent with the placeholder routing strategy.
web/src/pages/DashboardPage.tsx (1)
1-5: LGTM.This follows the same typed placeholder-page composition used across the new routes.
web/src/pages/MessagesPage.tsx (1)
1-5: Looks good.The page stub is consistent with the rest of the route scaffolding.
web/src/pages/ApprovalsPage.tsx (1)
1-5: Approved.Consistent, typed, and straightforward placeholder page composition.
web/.npmrc (1)
1-3: Thelegacy-peer-deps=truesetting inweb/.npmrcis already properly scoped to theweb/directory only and is necessary. Storybook 8.6.18 declares peer support for React^19.0.0-betaonly, while the project uses the React 19 release (^19), which creates a genuine peer dependency conflict that npm would flag. The workaround is justified and correctly placed—no changes needed.> Likely an incorrect or invalid review comment.web/src/pages/OrgEditPage.tsx (1)
1-5: Looks good: shared placeholder component is used correctly.This resolves the earlier duplication pattern cleanly and keeps route stubs consistent.
web/src/pages/SettingsPage.tsx (1)
1-5: Clean placeholder page implementation.Consistent with the shared route-stub pattern and no issues in this segment.
web/src/pages/ProviderDetailPage.tsx (1)
1-5: LGTM for this route stub.The page is minimal, consistent, and aligned with the shared placeholder approach.
web/src/pages/AgentDetailPage.tsx (1)
1-5: Good implementation for placeholder route page.No issues found in this changed segment.
web/src/pages/OrgChartPage.tsx (1)
1-5: Consistent and correct placeholder page wiring.This change is straightforward and aligns with the app-shell stubbing pattern.
web/src/pages/ProvidersPage.tsx (1)
1-5: Looks good and aligned with conventions.No issues detected in this page stub.
web/src/pages/SettingsNamespacePage.tsx (1)
1-5: Good placeholder implementation.Consistent with the rest of the new page stubs and no issues found.
web/src/pages/AgentsPage.tsx (1)
1-5: LGTM.The component is correctly implemented and consistent with the shared page pattern.
web/src/pages/MeetingsPage.tsx (1)
1-5: Looks good and consistent with the placeholder-page routing pattern.web/src/pages/SetupPage.tsx (1)
1-7: Clean setup page scaffold; no issues found in this segment.web/src/pages/TaskBoardPage.tsx (1)
1-5: Implementation is straightforward and aligned with the other placeholder pages.web/package.json (1)
13-15: Storybook scripts and dependency additions are coherent and well-aligned with the PR objectives.Also applies to: 42-48, 57-57, 63-63
web/src/__tests__/test-utils.tsx (1)
16-25: Good test-helper abstraction; this should reduce duplication across router tests.Also applies to: 30-36
web/src/pages/BudgetPage.tsx (1)
1-5: Looks good—consistent with the other placeholder route pages.web/src/pages/BudgetForecastPage.tsx (1)
1-5: LGTM!Clean placeholder page implementation following the established pattern for lazy-loaded route scaffolding.
web/src/pages/NotFoundPage.tsx (1)
1-14: LGTM!The NotFoundPage correctly uses the
asChildpattern with Button wrapping the react-router Link, following shadcn/ui conventions. The centered layout with clear 404 messaging and navigation back to dashboard is well-implemented.web/src/App.tsx (1)
1-5: LGTM!Clean refactor delegating all routing logic to the
AppRoutercomponent. This is the appropriate pattern for a router-based application entry point.web/src/stores/auth.ts (1)
139-149: LGTM!Good security practice using
sessionStorage(same-origin only) for the return path to prevent open redirect attacks. The comment clearly explains whywindow.location.hrefis used instead of react-router navigation.web/src/pages/LoginPage.tsx (1)
1-7: LGTM!Clean placeholder for the login page skeleton. The full-viewport centered layout is appropriate for an auth page.
web/.storybook/preview.tsx (1)
1-20: LGTM!Well-structured Storybook preview configuration. The global decorator ensures consistent dark theme styling across all stories, and importing the global CSS file ensures Tailwind utilities are available.
.github/workflows/ci.yml (2)
309-330: LGTM!The Storybook build job follows the established pattern for dashboard CI jobs. Good practice using
--disable-telemetryfor CI environments.
336-357: LGTM!Correctly integrated the new Storybook build job into the
ci-passgate, ensuring Storybook build failures will block the overall CI.web/.storybook/main.ts (1)
1-18: LGTM!Clean Storybook configuration with proper Tailwind CSS v4 Vite plugin integration. The dynamic import in
viteFinalcorrectly appends the Tailwind plugin while preserving existing Vite configuration. The addon selection (essentials, a11y, interactions) aligns with the PR objectives.CLAUDE.md (1)
56-57: LGTM!Documentation updates accurately reflect the new Storybook commands, app shell structure (
layout/,pages/,router/), CI job changes, and dependency additions.Also applies to: 126-126, 129-130, 237-237, 257-257
web/src/components/layout/AppLayout.tsx (1)
1-28: LGTM!Clean app shell implementation with proper accessibility attributes on the loading fallback (
role="status",aria-live="polite"). The layout structure correctly handles overflow with a fixed StatusBar, collapsible Sidebar, and independently scrollable main content area.web/src/components/layout/Sidebar.stories.tsx (1)
1-54: LGTM!Stories correctly use decorators to set
localStoragebefore render, addressing the previous review feedback. The global decorator properly sets up auth state and router context needed for the Sidebar component.web/src/__tests__/components/layout/SidebarNavItem.test.tsx (1)
1-75: LGTM!Comprehensive test coverage for
SidebarNavItemcovering collapsed/expanded states, badge rendering with cap behavior, and dot indicator presence. Uses@testing-library/reactwith the project'srenderWithRouterhelper as per coding guidelines.web/src/__tests__/stores/setup.test.ts (1)
1-132: LGTM!Well-structured test suite for the setup store covering initial state, success paths for both
needs_setupvalues, concurrent fetch prevention, error handling, and retry behavior. The concurrent fetch test (lines 67-95) is particularly well-designed with proper async control flow.web/src/router/index.tsx (1)
1-117: LGTM!Well-structured router configuration with proper lazy-loading, guard nesting, and Suspense boundaries. The route hierarchy correctly chains guards (AuthGuard → SetupGuard) for protected routes, and AppLayout's internal Suspense handles lazy page loading for child routes.
web/src/__tests__/components/layout/Sidebar.test.tsx (2)
121-137: LGTM!The logout test now correctly sets the spy before rendering the component (lines 124-131 set state with
logoutSpy, then line 132 renders), addressing the previous review feedback about potential test flakiness.
1-138: Comprehensive Sidebar test suite.Well-structured tests covering navigation rendering, user info display, collapse/expand behavior with localStorage persistence, and logout functionality. The
window.locationmock properly prevents side effects from the auth store's redirect behavior.web/src/components/ui/button.stories.tsx (1)
4-70: Good Storybook baseline.Typed
metaplus the aggregate variants story gives a useful smoke surface for the button API.web/src/__tests__/router/guards.test.tsx (1)
161-218: Good async guard coverage.These cases lock down fetch success, loading/error, retry, and fail-closed behavior instead of only the static redirect branches.
Also applies to: 338-402
| <span className="text-[10px] uppercase tracking-widest text-surface-400"> | ||
| SynthOrg | ||
| </span> |
There was a problem hiding this comment.
Replace hard-coded vendor name with a generic placeholder string.
Line 7 uses a real vendor name in UI copy. This should use a generic placeholder identifier in this code path.
✏️ Suggested change
- <span className="text-[10px] uppercase tracking-widest text-surface-400">
- SynthOrg
- </span>
+ <span className="text-[10px] uppercase tracking-widest text-surface-400">
+ example-provider
+ </span>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <span className="text-[10px] uppercase tracking-widest text-surface-400"> | |
| SynthOrg | |
| </span> | |
| <span className="text-[10px] uppercase tracking-widest text-surface-400"> | |
| example-provider | |
| </span> |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@web/src/components/layout/StatusBar.tsx` around lines 6 - 8, Replace the
hard-coded vendor string in the StatusBar component: locate the span containing
"SynthOrg" in StatusBar.tsx and change it to a generic placeholder such as
"example-provider" (or another approved generic identifier like
"example-vendor") so UI copy does not contain real vendor names; update any
tests or snapshots referencing the "SynthOrg" literal to the new placeholder as
well.
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@web/src/components/layout/Sidebar.tsx`:
- Around line 158-170: The className string on the Notifications button in
Sidebar.tsx (the button rendering Bell with className={cn('size-5 shrink-0',
collapsed && 'mx-auto')}) exceeds the 88-char limit; refactor by extracting the
computed className into a short named constant (e.g., notificationIconClass or
iconClass) above the JSX or by wrapping the cn(...) call onto multiple
concatenated expressions so the JSX line is under 88 chars, keeping the same
logic with collapsed and reusing the Bell and button elements unchanged.
- Around line 142-156: The button JSX exceeds the 88-char line limit due to a
long className string; refactor the button to use the cn() utility to build the
className across multiple lines for readability and consistency. Locate the
button element that uses toggleCollapse and the collapsed state (which renders
PanelLeftOpen / PanelLeftClose) and replace the long className literal with a
cn(...) call split onto separate lines, keeping the same classes and leaving
title, aria-label, onClick, and the conditional children unchanged.
In `@web/src/router/guards.tsx`:
- Around line 49-71: The guard currently renders Outlet as soon as
useIsAuthenticated() is true while fetchUser() validates in background, causing
a brief render before token validation; to enforce fail-closed behavior
implement a validating state and block rendering until fetchUser() resolves: add
a validating boolean (e.g., useState) inside AuthGuard, set validating=true
before calling fetchUser() and set to false in finally, use validatedRef only to
avoid duplicate calls, and change the render to return <FullScreenLoading />
while validating is true (keep existing Navigate to ROUTES.LOGIN behavior when
!isAuthenticated), referencing AuthGuard, fetchUser, validatedRef, useAuthStore,
useIsAuthenticated and FullScreenLoading to locate where to change.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 84a8a8c1-a30f-4bee-94ff-526eaddb363c
📒 Files selected for processing (8)
docker/web/Dockerfileweb/src/__tests__/App.test.tsxweb/src/components/layout/Sidebar.tsxweb/src/components/layout/SidebarNavItem.tsxweb/src/components/layout/StatusBar.tsxweb/src/router/guards.tsxweb/src/router/routes.tsweb/src/stores/setup.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: Build Sandbox
- GitHub Check: Build Web
- GitHub Check: Build Backend
- GitHub Check: Dependency Review
- GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (3)
docker/**
📄 CodeRabbit inference engine (CLAUDE.md)
All Docker files are in
docker/(Dockerfiles, compose,.env.example). Single root.dockerignore. All images build withcontext: .
Files:
docker/web/Dockerfile
web/src/**/*.{tsx,ts}
📄 CodeRabbit inference engine (CLAUDE.md)
web/src/**/*.{tsx,ts}: React components must use TypeScript and follow shadcn/ui + Tailwind CSS conventions. Line length: 88 characters.
React code must pass ESLint (configured with@eslint-react/eslint-plugin) and TypeScript type-check
Never use real vendor names in React code, tests, or config examples. Use generic names:example-provider,example-large-001, etc.
Files:
web/src/components/layout/StatusBar.tsxweb/src/stores/setup.tsweb/src/components/layout/Sidebar.tsxweb/src/components/layout/SidebarNavItem.tsxweb/src/__tests__/App.test.tsxweb/src/router/guards.tsxweb/src/router/routes.ts
web/src/__tests__/**/*.test.{tsx,ts}
📄 CodeRabbit inference engine (CLAUDE.md)
web/src/__tests__/**/*.test.{tsx,ts}: React unit tests must use Vitest with@testing-library/react. Coverage is scoped to files changed vs origin/main.
React property-based testing must use fast-check (fc.assert+fc.property)
Files:
web/src/__tests__/App.test.tsx
🧠 Learnings (20)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to docker/{Dockerfile*,compose.yml} : Docker: Backend uses 3-stage build (builder → setup → distroless runtime), Chainguard Python, non-root (UID 65532), CIS-hardened. Web uses nginxinc/nginx-unprivileged, Vue 3 SPA with PrimeVue + Tailwind CSS, SPA routing, API/WebSocket proxy to backend.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to web/** : Web dashboard: Node.js 20+, dependencies in web/package.json (Vue 3, PrimeVue, Tailwind CSS, Pinia, VueFlow, ECharts, Axios, vue-draggable-plus, Vitest, fast-check, ESLint, vue-tsc).
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T15:43:05.601Z
Learning: Applies to web/package.json : Web dashboard Node.js 20+; dependencies in web/package.json (Vue 3, PrimeVue, Tailwind CSS, Pinia, VueFlow, ECharts, Axios, vue-draggable-plus, Vitest, ESLint, vue-tsc)
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to docker/{Dockerfile*,compose.yml} : Docker: Backend uses 3-stage build (builder → setup → distroless runtime), Chainguard Python, non-root (UID 65532), CIS-hardened. Web uses nginxinc/nginx-unprivileged, Vue 3 SPA with PrimeVue + Tailwind CSS, SPA routing, API/WebSocket proxy to backend.
Applied to files:
docker/web/Dockerfile
📚 Learning: 2026-03-19T11:33:01.580Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:33:01.580Z
Learning: Applies to docker/Dockerfile.web : `nginxinc/nginx-unprivileged` base with non-root user (UID 101), Vue 3 SPA (PrimeVue + Tailwind CSS), SPA routing, API/WebSocket proxy to backend
Applied to files:
docker/web/Dockerfile
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to docker/Dockerfile : Docker: 3-stage build (builder → setup → distroless runtime) for backend, Chainguard Python, non-root (UID 65532), CIS-hardened
Applied to files:
docker/web/Dockerfile
📚 Learning: 2026-03-24T20:58:10.766Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T20:58:10.766Z
Learning: Applies to docker/Dockerfile* : All Docker images use Chainguard distroless (backend, non-root), nginx-unprivileged (web, SPA + API proxy), or Python + Node.js (sandbox, non-root)
Applied to files:
docker/web/Dockerfile
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Dependabot: auto-updates Docker image digests and versions daily.
Applied to files:
docker/web/Dockerfile
📚 Learning: 2026-03-24T20:58:10.766Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T20:58:10.766Z
Learning: Applies to docker/** : All Docker files are in `docker/` (Dockerfiles, compose, `.env.example`). Single root `.dockerignore`. All images build with `context: .`
Applied to files:
docker/web/Dockerfile
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/docker.yml : Docker workflow: builds backend + web + sandbox images, pushes to GHCR, signs with cosign. SLSA L3 provenance attestations via actions/attest-build-provenance. Scans: Trivy (CRITICAL = hard fail, HIGH = warn) + Grype (critical cutoff) + CIS Docker Benchmark v1.6.0 compliance (informational). CVE triage via .github/.trivyignore.yaml and .github/.grype.yaml. Images only pushed after scans pass. Triggers on push to main and version tags (v*).
Applied to files:
docker/web/Dockerfile
📚 Learning: 2026-03-15T16:38:08.735Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T16:38:08.735Z
Learning: Applies to docker/** : Docker build context: single root .dockerignore (both images build with context: .). Tags: CI tags images with version from pyproject.toml ([tool.commitizen].version), semver, and SHA.
Applied to files:
docker/web/Dockerfile
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to docker/Dockerfile.sandbox : Docker sandbox: `synthorg-sandbox` — Python 3.14 + Node.js + git, non-root (UID 10001), agent code execution sandbox
Applied to files:
docker/web/Dockerfile
📚 Learning: 2026-03-15T12:00:18.113Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T12:00:18.113Z
Learning: Applies to .github/workflows/docker.yml : CI Docker: build → scan → push to GHCR + cosign sign + SLSA L3 provenance via attest-build-provenance (images only pushed after Trivy/Grype scans pass).
Applied to files:
docker/web/Dockerfile
📚 Learning: 2026-03-14T15:43:05.601Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T15:43:05.601Z
Learning: Applies to web/package.json : Web dashboard Node.js 20+; dependencies in web/package.json (Vue 3, PrimeVue, Tailwind CSS, Pinia, VueFlow, ECharts, Axios, vue-draggable-plus, Vitest, ESLint, vue-tsc)
Applied to files:
docker/web/Dockerfile
📚 Learning: 2026-03-24T20:58:10.766Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T20:58:10.766Z
Learning: Applies to web/src/**/*.{tsx,ts} : React components must use TypeScript and follow shadcn/ui + Tailwind CSS conventions. Line length: 88 characters.
Applied to files:
web/src/components/layout/StatusBar.tsxweb/src/components/layout/Sidebar.tsxweb/src/components/layout/SidebarNavItem.tsxweb/src/__tests__/App.test.tsx
📚 Learning: 2026-03-24T20:58:10.766Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T20:58:10.766Z
Learning: Applies to web/src/**/*.{tsx,ts} : Never use real vendor names in React code, tests, or config examples. Use generic names: `example-provider`, `example-large-001`, etc.
Applied to files:
web/src/components/layout/StatusBar.tsxweb/src/__tests__/App.test.tsx
📚 Learning: 2026-03-19T11:33:01.580Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:33:01.580Z
Learning: Applies to web/**/*.vue : Never use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in dashboard code — use generic names: `example-provider`, `example-large-001`, etc.
Applied to files:
web/src/components/layout/StatusBar.tsx
📚 Learning: 2026-03-15T18:28:13.207Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:28:13.207Z
Learning: Applies to {src,tests,web,cli,site}/**/*.{py,ts,tsx,go,astro} : Vendor-agnostic everywhere: NEVER use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in project-owned code, docstrings, comments, tests, or config examples. Use generic names: example-provider, example-large-001, example-medium-001, example-small-001. Vendor names may only appear in: (1) Operations design page provider list (docs/design/operations.md), (2) .claude/ skill/agent files, (3) third-party import paths/module names.
Applied to files:
web/src/components/layout/StatusBar.tsx
📚 Learning: 2026-03-24T20:58:10.766Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T20:58:10.766Z
Learning: Applies to **/{src,tests}/**/*.py : Never use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in project-owned code, docstrings, comments, tests, or config examples. Use generic names: `example-provider`, `example-large-001`, `test-provider`, etc.
Applied to files:
web/src/components/layout/StatusBar.tsx
📚 Learning: 2026-03-24T20:58:10.766Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T20:58:10.766Z
Learning: Applies to web/src/__tests__/**/*.test.{tsx,ts} : React unit tests must use Vitest with `testing-library/react`. Coverage is scoped to files changed vs origin/main.
Applied to files:
web/src/__tests__/App.test.tsx
📚 Learning: 2026-03-20T08:28:32.845Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T08:28:32.845Z
Learning: Applies to web/src/__tests__/**/*.{ts,js} : Dashboard testing: Vitest unit tests organized by feature under `web/src/__tests__/`. Use fast-check for property-based testing (`fc.assert` + `fc.property`).
Applied to files:
web/src/__tests__/App.test.tsx
📚 Learning: 2026-03-24T20:58:10.766Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T20:58:10.766Z
Learning: Applies to web/src/__tests__/**/*.test.{tsx,ts} : React property-based testing must use fast-check (`fc.assert` + `fc.property`)
Applied to files:
web/src/__tests__/App.test.tsx
🔇 Additional comments (10)
docker/web/Dockerfile (1)
12-12: Good addition for build consistency.Copying
.npmrcensures Docker builds use the same npm configuration (legacy-peer-deps=true) as CI and local dev. The file is only present in the discarded builder stage, not the final nginx runtime image.Confirmed
.npmrccontains only safe configuration with no auth tokens or secrets.web/src/components/layout/StatusBar.tsx (1)
1-69: LGTM!The component is well-structured with proper use of
cn()for className composition, good accessibility practices (aria-hiddenon decorative elements), and clean separation of helper components (Divider,Dot,StatusItem).Note: The past review flagged "SynthOrg" as a vendor name, but this is the application's own brand name, not an external vendor like Anthropic/OpenAI/Claude/GPT that the coding guidelines prohibit. The app's own branding is appropriate here.
web/src/stores/setup.ts (1)
13-30: LGTM!The Zustand store implementation is well-designed:
- Proper concurrent-call guard with
if (get().loading) return- Error handling correctly resets
setupCompletetonull(addressing the previous review concern about stale guard decisions)- Clean typed interface with clear documentation comments
web/src/router/routes.ts (1)
1-35: LGTM!The route constants module is well-organized with proper
as consttyping. ThePUBLIC_ROUTESarray now correctly includesROUTES.SETUP_STEP(addressing the previous review concern about incomplete public routes for multi-step setup).web/src/router/guards.tsx (2)
79-104: LGTM!
SetupGuardcorrectly:
- Triggers fetch when
setupComplete === nulland not loading/error- Shows error UI with retry capability
- Shows loading state while fetching
- Redirects to setup when incomplete
125-159: LGTM!
SetupCompleteGuardimplements proper fail-closed behavior for authenticated users—redirecting to dashboard on error rather than allowing setup access. The unauthenticated pass-through is correctly documented.web/src/components/layout/SidebarNavItem.tsx (1)
1-63: LGTM!Well-implemented navigation item with:
- Proper active-state styling via NavLink's
classNamecallback- Good accessibility (
aria-hiddenon decorative elements,titlefor tooltip when collapsed)- Clean badge formatting with
99+cap- Line length compliance using
cn()compositionweb/src/__tests__/App.test.tsx (1)
1-77: LGTM!The test file is well-structured:
- Proper store resets in
beforeEachincluding theerrorflag (addressing previous review)- Semantic queries with
getByRole(addressing previous fragility concerns)- Clean mock setup for the setup API
- Appropriate window.location handling for auth redirects
web/src/components/layout/Sidebar.tsx (2)
27-40: LGTM on collapse persistence logic.Clean implementation using
localStoragewith proper state sync on toggle. The functional updater pattern insetCollapsedcorrectly captures the previous state.
196-221: LGTM on user/logout section.Proper conditional rendering when
useris present, with accessibility attributes (aria-label,title) on the logout button addressing the previous review concern.
There was a problem hiding this comment.
Actionable comments posted: 4
♻️ Duplicate comments (1)
web/src/components/layout/Sidebar.tsx (1)
218-223:⚠️ Potential issue | 🟡 MinorLine length rule still violated on logout button className.
Line 222 exceeds the 88-character limit. Please split/extract it (same pattern already used with
SIDEBAR_BUTTON_CLASS).As per coding guidelines: "Line length: 88 characters."♻️ Proposed refactor
+const LOGOUT_BUTTON_CLASS = cn( + 'rounded-md p-1 text-surface-400 transition-colors', + 'hover:bg-surface-100 hover:text-surface-700', +) @@ <button onClick={logout} title="Logout" aria-label="Logout" - className="rounded-md p-1 text-surface-400 transition-colors hover:bg-surface-100 hover:text-surface-700" + className={LOGOUT_BUTTON_CLASS} >🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/components/layout/Sidebar.tsx` around lines 218 - 223, The logout button's className string in the JSX for the logout button exceeds the 88-char line limit; extract the repeated class string into a shared constant (like the existing SIDEBAR_BUTTON_CLASS) and replace the inline className on the logout button with that constant (or compose it if extra classes are needed) so the JSX line is shortened and follows the line-length rule.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@web/src/__tests__/router/guards.test.tsx`:
- Around line 229-251: Update the test to exercise the retry flow: use
vi.mocked(getSetupStatus) (mockGetSetupStatus) and make the initial failure
mockRejectedValueOnce(new Error('Network error')), call useAuthStore.setState as
before, render the routes but capture the user helper returned by renderRoutes,
then after asserting the error UI, set
mockGetSetupStatus.mockResolvedValueOnce(...) with a successful setup response,
simulate clicking the retry button via await
user.click(screen.getByRole('button', { name: /retry/i })), wait for the
expected app content (e.g. "App Content") to appear, and assert
mockGetSetupStatus was called twice to verify the retry attempted a second
fetch; keep references to getSetupStatus, SetupGuard, renderRoutes, useAuthStore
and mockGetSetupStatus to locate the changes.
- Around line 105-128: Add a test in guards.test.tsx that verifies AuthGuard
"fails open" on non-401 errors: mock the auth endpoint (getMe) to reject with a
non-401 error using vi.mocked(getMe).mockRejectedValueOnce(new Error('Network
error')), set a token via useAuthStore.setState({ token: 'test-token' }), render
the route tree with AuthGuard via renderRoutes (children render
<div>Protected</div>), assert the "Loading..." text appears, then await
waitFor(() => expect(screen.getByText('Protected')).toBeInTheDocument()) to
confirm the outlet renders despite the transient failure.
In `@web/src/components/layout/Sidebar.tsx`:
- Around line 34-36: The Sidebar component currently reads and writes
localStorage directly for STORAGE_KEY when initializing the collapsed state and
toggling it; wrap all localStorage accesses in a safe guard (check typeof window
!== 'undefined' or try/catch) so failures in restricted contexts don't throw: in
the useState initializer for collapsed (and anywhere setCollapsed triggers a
write) attempt to read localStorage.getItem(STORAGE_KEY) inside a try block and
fall back to a safe default (e.g., false) on error, and similarly wrap
localStorage.setItem calls in try/catch so errors are ignored or logged instead
of crashing the component.
- Around line 57-61: The Sidebar component currently renders vendor branding
text ("SynthOrg") and its initial ("S") using the collapsed conditional; replace
both occurrences with generic names per policy — e.g., change the expanded label
rendered by the span in Sidebar.tsx from "SynthOrg" to a generic identifier like
"example-provider" and change the collapsed initial from "S" to a matching
neutral initial like "E" (or another letter tied to your chosen generic label)
so the component (references: collapsed variable and the two span elements) no
longer contains real vendor names.
---
Duplicate comments:
In `@web/src/components/layout/Sidebar.tsx`:
- Around line 218-223: The logout button's className string in the JSX for the
logout button exceeds the 88-char line limit; extract the repeated class string
into a shared constant (like the existing SIDEBAR_BUTTON_CLASS) and replace the
inline className on the logout button with that constant (or compose it if extra
classes are needed) so the JSX line is shortened and follows the line-length
rule.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 351a332d-c38c-402f-b13a-ae77261515a4
📒 Files selected for processing (3)
web/src/__tests__/router/guards.test.tsxweb/src/components/layout/Sidebar.tsxweb/src/router/guards.tsx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: Build Web
- GitHub Check: Build Sandbox
- GitHub Check: Build Backend
- GitHub Check: Dependency Review
- GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (2)
web/src/**/*.{tsx,ts}
📄 CodeRabbit inference engine (CLAUDE.md)
web/src/**/*.{tsx,ts}: React components must use TypeScript and follow shadcn/ui + Tailwind CSS conventions. Line length: 88 characters.
React code must pass ESLint (configured with@eslint-react/eslint-plugin) and TypeScript type-check
Never use real vendor names in React code, tests, or config examples. Use generic names:example-provider,example-large-001, etc.
Files:
web/src/components/layout/Sidebar.tsxweb/src/__tests__/router/guards.test.tsxweb/src/router/guards.tsx
web/src/__tests__/**/*.test.{tsx,ts}
📄 CodeRabbit inference engine (CLAUDE.md)
web/src/__tests__/**/*.test.{tsx,ts}: React unit tests must use Vitest with@testing-library/react. Coverage is scoped to files changed vs origin/main.
React property-based testing must use fast-check (fc.assert+fc.property)
Files:
web/src/__tests__/router/guards.test.tsx
🧠 Learnings (6)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to docker/{Dockerfile*,compose.yml} : Docker: Backend uses 3-stage build (builder → setup → distroless runtime), Chainguard Python, non-root (UID 65532), CIS-hardened. Web uses nginxinc/nginx-unprivileged, Vue 3 SPA with PrimeVue + Tailwind CSS, SPA routing, API/WebSocket proxy to backend.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to web/** : Web dashboard: Node.js 20+, dependencies in web/package.json (Vue 3, PrimeVue, Tailwind CSS, Pinia, VueFlow, ECharts, Axios, vue-draggable-plus, Vitest, fast-check, ESLint, vue-tsc).
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T15:43:05.601Z
Learning: Applies to web/package.json : Web dashboard Node.js 20+; dependencies in web/package.json (Vue 3, PrimeVue, Tailwind CSS, Pinia, VueFlow, ECharts, Axios, vue-draggable-plus, Vitest, ESLint, vue-tsc)
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T08:28:32.845Z
Learning: Applies to web/src/__tests__/**/*.{ts,js} : Dashboard testing: Vitest unit tests organized by feature under `web/src/__tests__/`. Use fast-check for property-based testing (`fc.assert` + `fc.property`).
📚 Learning: 2026-03-24T20:58:10.766Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T20:58:10.766Z
Learning: Applies to web/src/**/*.{tsx,ts} : React components must use TypeScript and follow shadcn/ui + Tailwind CSS conventions. Line length: 88 characters.
Applied to files:
web/src/components/layout/Sidebar.tsx
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to **/*.{py,md} : Line length: 88 characters (ruff).
Applied to files:
web/src/components/layout/Sidebar.tsx
📚 Learning: 2026-03-24T20:58:10.766Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T20:58:10.766Z
Learning: Applies to web/src/__tests__/**/*.test.{tsx,ts} : React unit tests must use Vitest with `testing-library/react`. Coverage is scoped to files changed vs origin/main.
Applied to files:
web/src/__tests__/router/guards.test.tsx
📚 Learning: 2026-03-20T08:28:32.845Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T08:28:32.845Z
Learning: Applies to web/src/__tests__/**/*.{ts,js} : Dashboard testing: Vitest unit tests organized by feature under `web/src/__tests__/`. Use fast-check for property-based testing (`fc.assert` + `fc.property`).
Applied to files:
web/src/__tests__/router/guards.test.tsx
📚 Learning: 2026-03-24T20:58:10.766Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T20:58:10.766Z
Learning: Applies to web/src/__tests__/**/*.test.{tsx,ts} : React property-based testing must use fast-check (`fc.assert` + `fc.property`)
Applied to files:
web/src/__tests__/router/guards.test.tsx
🧬 Code graph analysis (3)
web/src/components/layout/Sidebar.tsx (4)
web/src/hooks/useAuth.ts (1)
useAuth(10-31)web/src/stores/auth.ts (2)
logout(206-208)useAuthStore(61-210)web/src/components/layout/SidebarNavItem.tsx (1)
SidebarNavItem(15-63)web/src/router/routes.ts (1)
ROUTES(7-28)
web/src/__tests__/router/guards.test.tsx (5)
web/src/stores/auth.ts (1)
useAuthStore(61-210)web/src/stores/setup.ts (1)
useSetupStore(13-30)web/src/__tests__/test-utils.tsx (1)
renderRoutes(30-36)web/src/router/guards.tsx (4)
AuthGuard(50-83)SetupGuard(91-116)GuestGuard(121-129)SetupCompleteGuard(137-171)web/src/api/endpoints/setup.ts (1)
getSetupStatus(19-22)
web/src/router/guards.tsx (3)
web/src/stores/auth.ts (2)
useIsAuthenticated(214-214)useAuthStore(61-210)web/src/router/routes.ts (1)
ROUTES(7-28)web/src/stores/setup.ts (2)
useSetupStore(13-30)fetchSetupStatus(18-29)
🔇 Additional comments (10)
web/src/components/layout/Sidebar.tsx (1)
27-31: Good cleanup on shared button classes and accessibility labels.Extracting
SIDEBAR_BUTTON_CLASSand addingaria-labelon control buttons improves consistency and a11y.Also applies to: 148-175
web/src/router/guards.tsx (5)
7-42: Good accessibility and component extraction.The shared loading and error components appropriately use ARIA attributes (
role="status",aria-live="polite",role="alert"). ExtractingFullScreenLoadingaddresses the previous review feedback about duplication.
50-83: Fail-closed token validation implemented correctly.The
validatingstate now blocks<Outlet />untilfetchUser()completes, addressing the previous review feedback. The pattern correctly handles:
- 401 responses:
clearAuth()clears token →isAuthenticatedbecomes false → redirect to login- Non-401 errors: Tolerated (retry on subsequent API calls), outlet renders after validation attempt
The
useRefprevents duplicate fetches on strict-mode double-renders, and the.catch(() => {})/.finally()pattern ensures no unhandled rejections while always clearing the validating state.
91-116: LGTM!The guard correctly prioritizes error handling over loading states, and the retry mechanism integrates cleanly with the store's
fetchSetupStatuswhich resetserror: false, loading: truebefore retrying.
121-129: LGTM!Simple and correct implementation for guest-only routes.
137-171: LGTM!The fail-closed design correctly differs from
SetupGuard: on fetch failure, authenticated users are redirected to the dashboard rather than blocked with an error screen, preventing unauthorized setup access during transient failures.web/src/__tests__/router/guards.test.tsx (4)
7-53: LGTM!The test setup correctly:
- Mocks APIs at module level for consistent behavior
- Prevents
window.locationside effects fromclearAuth()- Provides
resetStores()to ensure test isolation via Zustand'ssetStateAPI
55-129: LGTM!The AuthGuard tests comprehensively cover the three main states:
- Unauthenticated → redirect
- Authenticated with user → render immediately
- Token-only (page refresh) → loading then render after validation
The loading-state test (lines 105-128) correctly validates the fail-closed behavior by checking the intermediate loading state before the mocked
getMeresolves.
254-300: LGTM!The GuestGuard tests correctly isolate the guard's behavior by using a plain
<div>for the redirect target rather than nesting guards, avoiding unintended interactions.
302-436: LGTM!Comprehensive coverage of
SetupCompleteGuardincluding the critical fail-closed test (lines 408-435) that verifies authenticated users are redirected to the dashboard rather than granted setup access when the status check fails.
| {collapsed ? ( | ||
| <span className="mx-auto text-lg font-bold text-brand-400">S</span> | ||
| ) : ( | ||
| <span className="text-lg font-bold text-brand-400">SynthOrg</span> | ||
| )} |
There was a problem hiding this comment.
Replace hardcoded vendor branding with a generic label.
Line 60 uses SynthOrg, which violates the generic-name requirement for React code examples/UI copy in this repo policy.
♻️ Proposed fix
{collapsed ? (
- <span className="mx-auto text-lg font-bold text-brand-400">S</span>
+ <span className="mx-auto text-lg font-bold text-brand-400">E</span>
) : (
- <span className="text-lg font-bold text-brand-400">SynthOrg</span>
+ <span className="text-lg font-bold text-brand-400">Example Org</span>
)}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@web/src/components/layout/Sidebar.tsx` around lines 57 - 61, The Sidebar
component currently renders vendor branding text ("SynthOrg") and its initial
("S") using the collapsed conditional; replace both occurrences with generic
names per policy — e.g., change the expanded label rendered by the span in
Sidebar.tsx from "SynthOrg" to a generic identifier like "example-provider" and
change the collapsed initial from "S" to a matching neutral initial like "E" (or
another letter tied to your chosen generic label) so the component (references:
collapsed variable and the two span elements) no longer contains real vendor
names.
Add the dashboard navigation shell with React Router, collapsible sidebar, status bar, route guards, and Storybook infrastructure for component development. App Shell: - React Router v7 with createBrowserRouter and lazy-loaded routes - 4 route guards: AuthGuard, SetupGuard, GuestGuard, SetupCompleteGuard - Collapsible sidebar (220px/56px) with primary + workspace nav sections - Full-width status bar skeleton (matching mockup v2 layout) - 20 page stubs for all routes from page-structure.md - 404 not-found page with back-to-dashboard link - Setup store enhanced with fetchSetupStatus() for guard logic Storybook: - @storybook/react v8 + Vite builder - Tailwind CSS 4 integration via viteFinal + @tailwindcss/vite - Dark theme config (dark-mode-only dashboard) - @storybook/addon-a11y for accessibility checks - @storybook/addon-interactions for interaction testing - Initial stories: Button variants, Sidebar expanded/collapsed CI/CD: - New dashboard-storybook-build job in ci.yml - All dashboard CI jobs updated with --legacy-peer-deps for Storybook compat Testing: - renderWithRouter and renderRoutes test utilities - Route guard tests (10 test cases) - Sidebar tests (7 test cases covering nav, collapse, persistence) - Updated App.test.tsx for router-based rendering - All 203 tests pass Closes #770 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix undefined text-text-secondary/text-text-primary CSS tokens across all page stubs and guards (use valid surface-500/surface-700 tokens) - Add `end` prop to Dashboard NavLink to prevent permanent active state - Use Zustand selectors in setup store guards (consistent with auth store) - Use cn() for class merging in StatusBar Dot component - Create web/.npmrc with legacy-peer-deps=true (replaces CLI flags in CI) - Remove --legacy-peer-deps from all CI npm ci commands - Update CLAUDE.md: add router/, pages/, layout/ to Package Structure, add Storybook commands, update CI job description - Add setup store tests (concurrent fetch guard, error handling, inversion) - Add SetupGuard fetch-triggering useEffect test - Add SidebarNavItem tests (badge capping, dot, collapsed tooltip) - Add sidebar logout button test - Fix App.test.tsx: deduplicate tests, add authenticated shell test - Fix Sidebar test: reset auth store in beforeEach Pre-reviewed by 5 agents, 15 findings addressed Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Security hardening: - AuthGuard proactively validates token via fetchUser on page refresh - SetupCompleteGuard fails closed on fetch error (redirects to dashboard) - Setup store tracks error state with retry support - Save return path to sessionStorage before auth redirect Accessibility: - Sidebar nav landmark scoped to navigation links only - aria-label on Notifications and Logout buttons - role="status" + aria-live="polite" on loading fallbacks Code quality: - Extract PlaceholderPage component (DRYs 17 page stubs) - Extract FullScreenLoading/FullScreenError in guards - Fix undefined bg-bg-base CSS token in LoginPage/SetupPage - Fix Storybook stories play/decorator consistency - Remove redundant truncate class in Sidebar - Remove unused routes property from test-utils interface - Add .npmrc comment explaining Storybook 8.x workaround - Align Storybook addon versions to ^8.6.18 - Add Storybook to CLAUDE.md dependencies list Tests: - Fix logout spy timing (set before render, remove as-never cast) - Use semantic queries in App.test.tsx (role-based, not count-based) - Add SetupGuard error path test with retry button - Add SetupCompleteGuard fail-closed test - Add setup store error flag + retry tests - Add SidebarNavItem dotColor prop tests Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- AuthGuard: proactive token validation via fetchUser with useRef guard to prevent re-attempts, .catch() to avoid unhandled rejections - Setup store: explicitly reset setupComplete to null on error - SetupCompleteGuard: handle error state from setup store - App.test.tsx: reset setup store error flag in beforeEach - SidebarNavItem: split badge className to respect 88-char line limit - StatusBar: break long className with cn() helper - Sidebar: add aria-label to collapse toggle button - PUBLIC_ROUTES: include SETUP_STEP for completeness - Dockerfile.web: copy .npmrc for legacy-peer-deps (fixes CI build) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- AuthGuard: fail-closed with useState(isAuthenticated && !user) to show loading during token validation on page refresh; validatedRef prevents duplicate fetch; .catch()/.finally() avoids unhandled rejections; lint-safe (no synchronous setState in effect body) - Sidebar: extract SIDEBAR_BUTTON_CLASS constant to fix 88-char line limit on collapse toggle and notifications button classNames - New test: AuthGuard loading state when token present but user null Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…safety - SetupGuard error test: exercise retry click, verify second fetch succeeds and renders app content - AuthGuard: add test for fail-open on non-401 errors (transient network failure renders children in degraded state) - Sidebar: wrap localStorage reads/writes in try/catch for restricted contexts (quota exceeded, privacy mode) - Sidebar: extract logout button className with cn() for 88-char limit Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
acaba36 to
947fd7f
Compare
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@web/src/components/layout/Sidebar.stories.tsx`:
- Around line 38-53: Extract the repeated 'sidebar_collapsed' string into a
single shared constant (e.g., SIDEBAR_COLLAPSED_KEY) and use that constant
inside the decorators for the Expanded and Collapsed Story objects instead of
hardcoding the literal; declare the constant near the top of the file (and
export it if other modules need it), then replace
localStorage.setItem('sidebar_collapsed', ...) in the Expanded and Collapsed
decorators with localStorage.setItem(SIDEBAR_COLLAPSED_KEY, 'false') and
localStorage.setItem(SIDEBAR_COLLAPSED_KEY, 'true') respectively.
In `@web/src/components/layout/SidebarNavItem.tsx`:
- Line 11: The dotColor prop on SidebarNavItem is overly permissive (string);
constrain it to a union of known CSS class names to prevent invalid classes
being passed: update the dotColor type declaration in SidebarNavItem
(prop/interface/type for SidebarNavItem or SidebarNavItemProps) to something
like 'bg-success-500' | 'bg-warning-500' | 'bg-danger-500' | string so callers
can use the known set while retaining a fallback string; adjust any usages or
prop defaulting in the SidebarNavItem component to match the new union type.
In `@web/src/router/index.tsx`:
- Around line 88-106: The child routes list mounts lazy-loaded components (e.g.,
DashboardPage, OrgChartPage, TaskBoardPage, AgentDetailPage, etc.) without
per-route Suspense boundaries, causing errors when navigating to a
not-yet-loaded chunk; wrap each route's element with the project's
SuspenseWrapper (or equivalent) so each lazy page has its own suspense boundary
(e.g., replace element: <DashboardPage /> with element:
<SuspenseWrapper><DashboardPage /></SuspenseWrapper> for all entries) while
keeping AppLayout intact.
- Line 106: The catch-all route "{ path: '*', element: <NotFoundPage /> }" is
currently nested under the protected tree (AuthGuard/SetupGuard), so
unauthenticated users hit the login redirect instead of the 404; move the
wildcard route out of the AuthGuard/SetupGuard children to the top-level routes
array (or add an additional top-level fallback route) so NotFoundPage is matched
for unknown paths before or outside the protected wrapper, ensuring the wildcard
is not a child of the protected route tree.
In `@web/src/stores/auth.ts`:
- Around line 139-149: The duplicate checks using the same condition on
currentPath should be consolidated: compute the condition once (e.g., a boolean
like isNotAuthOrSetup based on currentPath !== '/login' && currentPath !==
'/setup') and wrap both sessionStorage.setItem('auth_return_path', currentPath)
and the hard redirect window.location.href = '/login' inside a single if block
(or use the boolean to gate both actions) in the auth store where currentPath,
sessionStorage.setItem and window.location.href are used.
- Around line 139-144: LoginPage currently doesn't consume the stored
sessionStorage key auth_return_path; update the LoginPage component (e.g., in
its successful authentication handler such as handleLogin/onAuthenticated or the
place that sets the authenticated user and does navigation) to read
sessionStorage.getItem('auth_return_path'), validate it's a same-origin path
(non-empty and starts with '/'), perform a redirect to that path (fallback to
'/' or dashboard if absent/invalid), and then remove the key
(sessionStorage.removeItem('auth_return_path')) so it won't be reused; ensure
this logic runs only after successful authentication and preserves existing
post-login flows.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 7b9a5c6a-c19c-473a-a865-9b904ad90230
⛔ Files ignored due to path filters (1)
web/package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (47)
.github/workflows/ci.yml.gitignoreCLAUDE.mddocker/web/Dockerfileweb/.npmrcweb/.storybook/main.tsweb/.storybook/preview.tsxweb/package.jsonweb/src/App.tsxweb/src/__tests__/App.test.tsxweb/src/__tests__/components/layout/Sidebar.test.tsxweb/src/__tests__/components/layout/SidebarNavItem.test.tsxweb/src/__tests__/router/guards.test.tsxweb/src/__tests__/stores/setup.test.tsweb/src/__tests__/test-utils.tsxweb/src/components/layout/AppLayout.tsxweb/src/components/layout/PlaceholderPage.tsxweb/src/components/layout/Sidebar.stories.tsxweb/src/components/layout/Sidebar.tsxweb/src/components/layout/SidebarNavItem.tsxweb/src/components/layout/StatusBar.tsxweb/src/components/ui/button.stories.tsxweb/src/pages/AgentDetailPage.tsxweb/src/pages/AgentsPage.tsxweb/src/pages/ApprovalsPage.tsxweb/src/pages/BudgetForecastPage.tsxweb/src/pages/BudgetPage.tsxweb/src/pages/DashboardPage.tsxweb/src/pages/LoginPage.tsxweb/src/pages/MeetingDetailPage.tsxweb/src/pages/MeetingsPage.tsxweb/src/pages/MessagesPage.tsxweb/src/pages/NotFoundPage.tsxweb/src/pages/OrgChartPage.tsxweb/src/pages/OrgEditPage.tsxweb/src/pages/ProviderDetailPage.tsxweb/src/pages/ProvidersPage.tsxweb/src/pages/SettingsNamespacePage.tsxweb/src/pages/SettingsPage.tsxweb/src/pages/SetupPage.tsxweb/src/pages/TaskBoardPage.tsxweb/src/pages/TaskDetailPage.tsxweb/src/router/guards.tsxweb/src/router/index.tsxweb/src/router/routes.tsweb/src/stores/auth.tsweb/src/stores/setup.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
- GitHub Check: Build Backend
- GitHub Check: Build Sandbox
- GitHub Check: Build Web
- GitHub Check: Dependency Review
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: Analyze (python)
- GitHub Check: Analyze (go)
🧰 Additional context used
📓 Path-based instructions (7)
web/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
ESLint linting is required for React/TypeScript web dashboard code via
npm --prefix web run lint.
Files:
web/src/pages/ApprovalsPage.tsxweb/src/pages/TaskDetailPage.tsxweb/src/pages/SettingsPage.tsxweb/src/pages/AgentsPage.tsxweb/src/pages/OrgEditPage.tsxweb/src/pages/MeetingDetailPage.tsxweb/src/components/layout/PlaceholderPage.tsxweb/src/pages/SettingsNamespacePage.tsxweb/src/pages/MessagesPage.tsxweb/src/pages/DashboardPage.tsxweb/src/pages/TaskBoardPage.tsxweb/src/pages/ProviderDetailPage.tsxweb/src/pages/AgentDetailPage.tsxweb/src/pages/ProvidersPage.tsxweb/src/pages/OrgChartPage.tsxweb/src/pages/SetupPage.tsxweb/src/pages/NotFoundPage.tsxweb/src/pages/BudgetPage.tsxweb/src/pages/LoginPage.tsxweb/src/pages/MeetingsPage.tsxweb/src/components/layout/AppLayout.tsxweb/src/components/layout/StatusBar.tsxweb/src/__tests__/components/layout/SidebarNavItem.test.tsxweb/src/components/layout/Sidebar.stories.tsxweb/src/__tests__/stores/setup.test.tsweb/src/__tests__/App.test.tsxweb/src/__tests__/components/layout/Sidebar.test.tsxweb/src/stores/setup.tsweb/src/components/layout/Sidebar.tsxweb/src/components/layout/SidebarNavItem.tsxweb/src/__tests__/test-utils.tsxweb/src/components/ui/button.stories.tsxweb/src/router/index.tsxweb/src/App.tsxweb/src/router/routes.tsweb/src/stores/auth.tsweb/src/__tests__/router/guards.test.tsxweb/src/pages/BudgetForecastPage.tsxweb/src/router/guards.tsx
web/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
TypeScript type checking is required for web dashboard via
npm --prefix web run type-check.
Files:
web/src/pages/ApprovalsPage.tsxweb/src/pages/TaskDetailPage.tsxweb/src/pages/SettingsPage.tsxweb/src/pages/AgentsPage.tsxweb/src/pages/OrgEditPage.tsxweb/src/pages/MeetingDetailPage.tsxweb/src/components/layout/PlaceholderPage.tsxweb/src/pages/SettingsNamespacePage.tsxweb/src/pages/MessagesPage.tsxweb/src/pages/DashboardPage.tsxweb/src/pages/TaskBoardPage.tsxweb/src/pages/ProviderDetailPage.tsxweb/src/pages/AgentDetailPage.tsxweb/src/pages/ProvidersPage.tsxweb/src/pages/OrgChartPage.tsxweb/src/pages/SetupPage.tsxweb/src/pages/NotFoundPage.tsxweb/src/pages/BudgetPage.tsxweb/src/pages/LoginPage.tsxweb/src/pages/MeetingsPage.tsxweb/src/components/layout/AppLayout.tsxweb/src/components/layout/StatusBar.tsxweb/src/__tests__/components/layout/SidebarNavItem.test.tsxweb/src/components/layout/Sidebar.stories.tsxweb/src/__tests__/stores/setup.test.tsweb/src/__tests__/App.test.tsxweb/src/__tests__/components/layout/Sidebar.test.tsxweb/src/stores/setup.tsweb/src/components/layout/Sidebar.tsxweb/src/components/layout/SidebarNavItem.tsxweb/src/__tests__/test-utils.tsxweb/src/components/ui/button.stories.tsxweb/src/router/index.tsxweb/src/App.tsxweb/src/router/routes.tsweb/src/stores/auth.tsweb/src/__tests__/router/guards.test.tsxweb/src/pages/BudgetForecastPage.tsxweb/src/router/guards.tsx
**/*.{yml,yaml,toml,json}
📄 CodeRabbit inference engine (CLAUDE.md)
YAML, TOML, JSON files must pass check-yaml, check-toml, check-json pre-commit hooks respectively.
Files:
web/package.json
web/package.json
📄 CodeRabbit inference engine (CLAUDE.md)
Web dashboard uses Node.js 22+. Key dependencies: React 19, react-router, shadcn/ui, Radix UI, Tailwind CSS 4, Zustand,
@tanstack/react-query,@xyflow/react, Recharts, Framer Motion, cmdk, Axios, Lucide React, Vitest.
Files:
web/package.json
**/Dockerfile*
📄 CodeRabbit inference engine (CLAUDE.md)
Dockerfiles must pass hadolint linting via pre-commit hooks.
Files:
docker/web/Dockerfile
docker/**
📄 CodeRabbit inference engine (CLAUDE.md)
Docker configuration: use
.env.exampleas template, all Docker files indocker/directory (Dockerfiles, compose, env). Build and verify with docker compose commands.
Files:
docker/web/Dockerfile
web/**/__tests__/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
web/**/__tests__/**/*.{ts,tsx}: Web dashboard tests use Vitest with coverage scoped to files changed vs origin/main. Run withnpm --prefix web run test.
Use fast-check for property-based testing in JavaScript/TypeScript (fc.assert+fc.property).
Files:
web/src/__tests__/components/layout/SidebarNavItem.test.tsxweb/src/__tests__/stores/setup.test.tsweb/src/__tests__/App.test.tsxweb/src/__tests__/components/layout/Sidebar.test.tsxweb/src/__tests__/test-utils.tsxweb/src/__tests__/router/guards.test.tsx
🧠 Learnings (41)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to docker/{Dockerfile*,compose.yml} : Docker: Backend uses 3-stage build (builder → setup → distroless runtime), Chainguard Python, non-root (UID 65532), CIS-hardened. Web uses nginxinc/nginx-unprivileged, Vue 3 SPA with PrimeVue + Tailwind CSS, SPA routing, API/WebSocket proxy to backend.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T22:02:25.937Z
Learning: Applies to web/package.json : Web dashboard uses Node.js 22+. Key dependencies: React 19, react-router, shadcn/ui, Radix UI, Tailwind CSS 4, Zustand, tanstack/react-query, xyflow/react, Recharts, Framer Motion, cmdk, Axios, Lucide React, Vitest.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to web/** : Web dashboard: Node.js 20+, dependencies in web/package.json (Vue 3, PrimeVue, Tailwind CSS, Pinia, VueFlow, ECharts, Axios, vue-draggable-plus, Vitest, fast-check, ESLint, vue-tsc).
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T15:43:05.601Z
Learning: Applies to web/package.json : Web dashboard Node.js 20+; dependencies in web/package.json (Vue 3, PrimeVue, Tailwind CSS, Pinia, VueFlow, ECharts, Axios, vue-draggable-plus, Vitest, ESLint, vue-tsc)
📚 Learning: 2026-03-14T15:43:05.601Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T15:43:05.601Z
Learning: Applies to web/package.json : Web dashboard Node.js 20+; dependencies in web/package.json (Vue 3, PrimeVue, Tailwind CSS, Pinia, VueFlow, ECharts, Axios, vue-draggable-plus, Vitest, ESLint, vue-tsc)
Applied to files:
web/.npmrc.gitignoreweb/package.jsondocker/web/DockerfileCLAUDE.mdweb/.storybook/main.ts
📚 Learning: 2026-03-24T22:02:25.937Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T22:02:25.937Z
Learning: Applies to web/package.json : Web dashboard uses Node.js 22+. Key dependencies: React 19, react-router, shadcn/ui, Radix UI, Tailwind CSS 4, Zustand, tanstack/react-query, xyflow/react, Recharts, Framer Motion, cmdk, Axios, Lucide React, Vitest.
Applied to files:
web/.npmrc.gitignoreweb/package.jsonCLAUDE.mdweb/src/App.tsx
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to web/** : Web dashboard: Node.js 20+, dependencies in web/package.json (Vue 3, PrimeVue, Tailwind CSS, Pinia, VueFlow, ECharts, Axios, vue-draggable-plus, Vitest, fast-check, ESLint, vue-tsc).
Applied to files:
.gitignoreweb/package.jsonCLAUDE.mdweb/src/App.tsx
📚 Learning: 2026-03-24T22:02:25.937Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T22:02:25.937Z
Learning: Applies to web/**/__tests__/**/*.{ts,tsx} : Web dashboard tests use Vitest with coverage scoped to files changed vs origin/main. Run with `npm --prefix web run test`.
Applied to files:
.gitignoreweb/package.jsonweb/src/__tests__/components/layout/SidebarNavItem.test.tsxCLAUDE.mdweb/src/__tests__/stores/setup.test.tsweb/.storybook/main.tsweb/src/__tests__/App.test.tsxweb/src/__tests__/components/layout/Sidebar.test.tsxweb/src/__tests__/test-utils.tsxweb/src/__tests__/router/guards.test.tsx
📚 Learning: 2026-03-24T22:02:25.937Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T22:02:25.937Z
Learning: Applies to web/**/*.{ts,tsx,js,jsx} : ESLint linting is required for React/TypeScript web dashboard code via `npm --prefix web run lint`.
Applied to files:
.gitignoreweb/package.jsonCLAUDE.md
📚 Learning: 2026-03-24T22:02:25.937Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T22:02:25.937Z
Learning: Applies to web/**/*.{ts,tsx} : TypeScript type checking is required for web dashboard via `npm --prefix web run type-check`.
Applied to files:
.gitignoreweb/src/pages/DashboardPage.tsxCLAUDE.mdweb/src/router/routes.ts
📚 Learning: 2026-03-20T08:28:32.845Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T08:28:32.845Z
Learning: Applies to web/src/__tests__/**/*.{ts,js} : Dashboard testing: Vitest unit tests organized by feature under `web/src/__tests__/`. Use fast-check for property-based testing (`fc.assert` + `fc.property`).
Applied to files:
.gitignoreweb/src/__tests__/components/layout/SidebarNavItem.test.tsxCLAUDE.mdweb/src/__tests__/stores/setup.test.tsweb/.storybook/main.tsweb/src/__tests__/App.test.tsxweb/src/__tests__/components/layout/Sidebar.test.tsxweb/src/__tests__/test-utils.tsxweb/src/__tests__/router/guards.test.tsx
📚 Learning: 2026-03-15T21:20:09.993Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:20:09.993Z
Learning: Applies to web/src/components/** : Vue components organized by feature (agents/, approvals/, budget/, common/, dashboard/, layout/, messages/, org-chart/, tasks/).
Applied to files:
.gitignoreCLAUDE.md
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/*.yml : Dependabot: daily updates for uv + github-actions + npm + pre-commit + docker + gomod, grouped minor/patch, no auto-merge. Use `/review-dep-pr` to review Dependabot PRs before merging.
Applied to files:
.github/workflows/ci.ymldocker/web/DockerfileCLAUDE.md
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to .github/workflows/**/*.yml : Path filtering: dorny/paths-filter detects Python/dashboard/docker changes; jobs only run when their domain is affected. CLI has its own workflow (cli.yml).
Applied to files:
.github/workflows/ci.ymlCLAUDE.md
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/docker.yml : Docker workflow: builds backend + web + sandbox images, pushes to GHCR, signs with cosign. SLSA L3 provenance attestations via actions/attest-build-provenance. Scans: Trivy (CRITICAL = hard fail, HIGH = warn) + Grype (critical cutoff) + CIS Docker Benchmark v1.6.0 compliance (informational). CVE triage via .github/.trivyignore.yaml and .github/.grype.yaml. Images only pushed after scans pass. Triggers on push to main and version tags (v*).
Applied to files:
.github/workflows/ci.ymldocker/web/DockerfileCLAUDE.md
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/cli.yml : CLI workflow: Go lint (golangci-lint + go vet) + test (-race -coverprofile) + build (cross-compile: linux/darwin/windows × amd64/arm64) + govulncheck + fuzz testing (main-only, 30s/target, continue-on-error, matrix over 4 packages). cli-pass gate includes fuzz as informational. GoReleaser release on v* tags. Cosign keyless signing of checksums.txt. SLSA L3 provenance attestations. Sigstore bundle (.sigstore.json) attached. Post-release appends checksums/verification/provenance to draft release notes.
Applied to files:
.github/workflows/ci.ymlCLAUDE.md
📚 Learning: 2026-03-15T12:00:18.113Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T12:00:18.113Z
Learning: Applies to .github/workflows/docker.yml : CI Docker: build → scan → push to GHCR + cosign sign + SLSA L3 provenance via attest-build-provenance (images only pushed after Trivy/Grype scans pass).
Applied to files:
.github/workflows/ci.ymldocker/web/DockerfileCLAUDE.md
📚 Learning: 2026-03-19T11:19:40.044Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:19:40.044Z
Learning: CLI workflow (`.github/workflows/cli.yml`) runs Go lint (golangci-lint + go vet) + test (race, coverage) + build (cross-compile matrix) + vulnerability check (govulncheck) + fuzz testing. Cross-compiles for linux/darwin/windows × amd64/arm64. GoReleaser release on v* tags with cosign keyless signing and SLSA L3 attestations.
Applied to files:
.github/workflows/ci.ymlCLAUDE.md
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to docker/{Dockerfile*,compose.yml} : Docker: Backend uses 3-stage build (builder → setup → distroless runtime), Chainguard Python, non-root (UID 65532), CIS-hardened. Web uses nginxinc/nginx-unprivileged, Vue 3 SPA with PrimeVue + Tailwind CSS, SPA routing, API/WebSocket proxy to backend.
Applied to files:
docker/web/DockerfileCLAUDE.md
📚 Learning: 2026-03-19T11:33:01.580Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:33:01.580Z
Learning: Applies to docker/Dockerfile.web : `nginxinc/nginx-unprivileged` base with non-root user (UID 101), Vue 3 SPA (PrimeVue + Tailwind CSS), SPA routing, API/WebSocket proxy to backend
Applied to files:
docker/web/Dockerfile
📚 Learning: 2026-03-24T22:02:25.937Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T22:02:25.937Z
Learning: Applies to docker/Dockerfile* : Docker images: backend (Chainguard distroless, non-root), web (nginx-unprivileged, SPA + API proxy), sandbox (Python + Node.js, non-root). All Dockerfiles in `docker/` use single root `.dockerignore` (all images build with `context: .`).
Applied to files:
docker/web/Dockerfile
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to docker/Dockerfile : Docker: 3-stage build (builder → setup → distroless runtime) for backend, Chainguard Python, non-root (UID 65532), CIS-hardened
Applied to files:
docker/web/Dockerfile
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Dependabot: auto-updates Docker image digests and versions daily.
Applied to files:
docker/web/Dockerfile
📚 Learning: 2026-03-15T16:38:08.735Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T16:38:08.735Z
Learning: Applies to docker/** : Docker build context: single root .dockerignore (both images build with context: .). Tags: CI tags images with version from pyproject.toml ([tool.commitizen].version), semver, and SHA.
Applied to files:
docker/web/Dockerfile
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to docker/Dockerfile.sandbox : Docker sandbox: `synthorg-sandbox` — Python 3.14 + Node.js + git, non-root (UID 10001), agent code execution sandbox
Applied to files:
docker/web/Dockerfile
📚 Learning: 2026-03-19T11:33:01.580Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:33:01.580Z
Learning: Applies to web/**/*.vue : Never use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in dashboard code — use generic names: `example-provider`, `example-large-001`, etc.
Applied to files:
web/src/components/layout/StatusBar.tsxweb/src/components/layout/Sidebar.tsx
📚 Learning: 2026-03-15T18:28:13.207Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:28:13.207Z
Learning: Applies to {src,tests,web,cli,site}/**/*.{py,ts,tsx,go,astro} : Vendor-agnostic everywhere: NEVER use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in project-owned code, docstrings, comments, tests, or config examples. Use generic names: example-provider, example-large-001, example-medium-001, example-small-001. Vendor names may only appear in: (1) Operations design page provider list (docs/design/operations.md), (2) .claude/ skill/agent files, (3) third-party import paths/module names.
Applied to files:
web/src/components/layout/StatusBar.tsxweb/src/components/layout/Sidebar.tsx
📚 Learning: 2026-03-24T22:02:25.937Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T22:02:25.937Z
Learning: Applies to +(src|tests)/**/*.py : NEVER use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in project-owned code, docstrings, comments, tests, or config examples. Use generic names: `example-provider`, `example-large-001`, `example-medium-001`, `example-small-001`, `large`/`medium`/`small` as aliases. Vendor names may only appear in: (1) `docs/design/operations.md` provider list, (2) `.claude/` skill/agent files, (3) third-party import paths/module names (e.g. `litellm.types.llms.openai`).
Applied to files:
web/src/components/layout/StatusBar.tsxweb/src/components/layout/Sidebar.tsx
📚 Learning: 2026-03-24T22:02:25.937Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T22:02:25.937Z
Learning: Applies to web/**/__tests__/**/*.{ts,tsx} : Use fast-check for property-based testing in JavaScript/TypeScript (`fc.assert` + `fc.property`).
Applied to files:
web/src/__tests__/components/layout/SidebarNavItem.test.tsxweb/src/__tests__/App.test.tsxweb/src/__tests__/components/layout/Sidebar.test.tsxweb/src/__tests__/test-utils.tsxweb/src/__tests__/router/guards.test.tsx
📚 Learning: 2026-03-16T19:52:03.656Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T19:52:03.656Z
Learning: Applies to cli/**/*.go : Lint CLI Go code with golangci-lint and go vet; test with go test -race; check vulnerabilities with govulncheck
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-19T11:30:29.217Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:30:29.217Z
Learning: Applies to cli/**/*.go : Run Go lint via `golangci-lint run`, vet via `go vet`, tests via `go test ./...`, and fuzz via `go test -fuzz=FuzzTarget -fuzztime=30s`
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-19T11:19:40.044Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:19:40.044Z
Learning: Applies to cli/**/*.go : Lint Go code with `golangci-lint` and `go vet`. Run tests with `-race` flag to detect race conditions.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/**/*.py : Package structure: src/synthorg/ organized as: api/ (REST+WebSocket, Litestar), auth/ (auth subpackage), backup/ (scheduled/manual backups), budget/ (cost tracking, CFO), cli/ (superseded by Go CLI), communication/ (message bus, meetings), config/ (YAML loading), core/ (domain models, resilience config), engine/ (orchestration, task state, coordination, approval gates, stagnation detection, context budget, compaction), hr/ (hiring, performance, promotion), memory/ (pluggable backend, Mem0, retrieval, consolidation), persistence/ (operational data, SQLite, settings), observability/ (logging, correlation, sinks), providers/ (LLM abstraction, LiteLLM, auth types, presets, runtime CRUD), settings/ (runtime-editable, typed definitions, encryption, config bridge), security/ (SecOps, rule engine, output scanning, progressive trust, autonomy levels), templates/ (company templates, personalities), tools/ (registry, built-in tools, git, sandbox, code_runner, MCP...
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-24T22:02:25.937Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T22:02:25.937Z
Learning: CI uses `dorny/paths-filter` for path filtering—jobs only run when their domain is affected. CLI has its own workflow (`cli.yml`).
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Pre-push hooks: mypy type-check + pytest unit tests + golangci-lint + go vet + go test (CLI, conditional on cli/**/*.go) (fast gate before push, skipped in pre-commit.ci — dedicated CI jobs already run these).
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-24T22:02:25.937Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T22:02:25.937Z
Learning: Pre-push hooks enforce: mypy type-check + pytest unit tests + golangci-lint + go vet + go test (CLI). These are fast gates before push and skipped in pre-commit.ci.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-24T22:02:25.937Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T22:02:25.937Z
Learning: Applies to .github/workflows/dev-release.yml : Dev channel releases are created for every push to `main` (except Release Please bumps) as semver dev tags (e.g. `v0.4.7-dev.3`) with draft pre-releases via `dev-release.yml`. Users opt in with `synthorg config set channel dev`. All dev releases flow through the same Docker + CLI pipelines as stable releases. All dev releases and tags are deleted when a stable release is published.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to pyproject.toml : Dependencies: all versions use == in pyproject.toml. Groups: test (pytest + plugins, hypothesis), dev (includes test + ruff, mypy, pre-commit, commitizen, pip-audit). Required: mem0ai (Mem0 memory backend — the default and currently only backend). Install: uv sync installs everything (dev group is default).
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-24T22:02:25.937Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T22:02:25.937Z
Learning: Applies to pyproject.toml : Python dependency groups: `test` (pytest + plugins, hypothesis), `dev` (includes test + ruff, mypy, pre-commit, commitizen, pip-audit). Install with `uv sync` (dev group is default).
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-24T22:02:25.937Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T22:02:25.937Z
Learning: Applies to pyproject.toml : Required Python dependencies: `mem0ai` (Mem0 memory backend), `cryptography` (Fernet encryption for sensitive settings), `faker` (multi-locale agent name generation).
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-19T11:19:40.044Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:19:40.044Z
Learning: Applies to go.mod : Maintain Go 1.26+ requirement. Dependencies: Cobra (CLI framework), charmbracelet/huh and charmbracelet/lipgloss (UI), sigstore-go (code signing), go-containerregistry (container image verification), go-tuf (TUF client for Sigstore).
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-24T22:02:25.937Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T22:02:25.937Z
Learning: Applies to cli/go.mod : CLI uses Go 1.26+. Key dependencies: Cobra, charmbracelet/huh, charmbracelet/lipgloss, sigstore-go, go-containerregistry, go-tuf.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to cli/** : CLI: Go 1.26+, dependencies in cli/go.mod (Cobra, charmbracelet/huh).
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to **/*.{py,md} : Line length: 88 characters (ruff).
Applied to files:
web/src/components/layout/Sidebar.tsx
🧬 Code graph analysis (29)
web/src/pages/ApprovalsPage.tsx (1)
web/src/components/layout/PlaceholderPage.tsx (1)
PlaceholderPage(2-8)
web/src/pages/TaskDetailPage.tsx (1)
web/src/components/layout/PlaceholderPage.tsx (1)
PlaceholderPage(2-8)
web/src/pages/SettingsPage.tsx (1)
web/src/components/layout/PlaceholderPage.tsx (1)
PlaceholderPage(2-8)
web/src/pages/AgentsPage.tsx (1)
web/src/components/layout/PlaceholderPage.tsx (1)
PlaceholderPage(2-8)
web/src/pages/OrgEditPage.tsx (1)
web/src/components/layout/PlaceholderPage.tsx (1)
PlaceholderPage(2-8)
web/src/pages/MeetingDetailPage.tsx (1)
web/src/components/layout/PlaceholderPage.tsx (1)
PlaceholderPage(2-8)
web/src/pages/SettingsNamespacePage.tsx (1)
web/src/components/layout/PlaceholderPage.tsx (1)
PlaceholderPage(2-8)
web/src/pages/MessagesPage.tsx (1)
web/src/components/layout/PlaceholderPage.tsx (1)
PlaceholderPage(2-8)
web/src/pages/DashboardPage.tsx (1)
web/src/components/layout/PlaceholderPage.tsx (1)
PlaceholderPage(2-8)
web/src/pages/TaskBoardPage.tsx (1)
web/src/components/layout/PlaceholderPage.tsx (1)
PlaceholderPage(2-8)
web/src/pages/ProviderDetailPage.tsx (1)
web/src/components/layout/PlaceholderPage.tsx (1)
PlaceholderPage(2-8)
web/src/pages/AgentDetailPage.tsx (1)
web/src/components/layout/PlaceholderPage.tsx (1)
PlaceholderPage(2-8)
web/src/pages/ProvidersPage.tsx (1)
web/src/components/layout/PlaceholderPage.tsx (1)
PlaceholderPage(2-8)
web/src/pages/OrgChartPage.tsx (1)
web/src/components/layout/PlaceholderPage.tsx (1)
PlaceholderPage(2-8)
web/src/pages/NotFoundPage.tsx (1)
web/src/components/ui/button.stories.tsx (1)
Link(43-45)
web/src/pages/BudgetPage.tsx (1)
web/src/components/layout/PlaceholderPage.tsx (1)
PlaceholderPage(2-8)
web/src/pages/MeetingsPage.tsx (1)
web/src/components/layout/PlaceholderPage.tsx (1)
PlaceholderPage(2-8)
web/src/components/layout/AppLayout.tsx (2)
web/src/components/layout/StatusBar.tsx (1)
StatusBar(3-50)web/src/components/layout/Sidebar.tsx (1)
Sidebar(49-250)
web/src/__tests__/components/layout/SidebarNavItem.test.tsx (2)
web/src/__tests__/test-utils.tsx (1)
renderWithRouter(16-25)web/src/components/layout/SidebarNavItem.tsx (1)
SidebarNavItem(15-63)
web/src/components/layout/Sidebar.stories.tsx (2)
web/src/components/layout/Sidebar.tsx (1)
Sidebar(49-250)web/src/stores/auth.ts (1)
useAuthStore(61-210)
web/src/__tests__/stores/setup.test.ts (2)
web/src/stores/setup.ts (1)
useSetupStore(13-30)web/src/api/endpoints/setup.ts (1)
getSetupStatus(19-22)
web/src/__tests__/App.test.tsx (3)
web/src/stores/auth.ts (1)
useAuthStore(61-210)web/src/stores/setup.ts (1)
useSetupStore(13-30)web/src/App.tsx (1)
App(3-5)
web/src/__tests__/components/layout/Sidebar.test.tsx (1)
web/src/components/layout/Sidebar.tsx (1)
Sidebar(49-250)
web/src/stores/setup.ts (1)
web/src/api/endpoints/setup.ts (1)
getSetupStatus(19-22)
web/src/components/layout/Sidebar.tsx (4)
web/src/hooks/useAuth.ts (1)
useAuth(10-31)web/src/stores/auth.ts (2)
logout(206-208)useAuthStore(61-210)web/src/components/layout/SidebarNavItem.tsx (1)
SidebarNavItem(15-63)web/src/router/routes.ts (1)
ROUTES(7-28)
web/src/App.tsx (1)
web/src/router/index.tsx (1)
AppRouter(115-117)
web/src/__tests__/router/guards.test.tsx (6)
web/src/stores/auth.ts (1)
useAuthStore(61-210)web/src/stores/setup.ts (1)
useSetupStore(13-30)web/src/__tests__/test-utils.tsx (1)
renderRoutes(30-36)web/src/router/guards.tsx (4)
AuthGuard(50-83)SetupGuard(91-116)GuestGuard(121-129)SetupCompleteGuard(137-171)web/src/api/endpoints/auth.ts (1)
getMe(27-30)web/src/api/endpoints/setup.ts (1)
getSetupStatus(19-22)
web/src/pages/BudgetForecastPage.tsx (1)
web/src/components/layout/PlaceholderPage.tsx (1)
PlaceholderPage(2-8)
web/src/router/guards.tsx (3)
web/src/stores/auth.ts (2)
useIsAuthenticated(214-214)useAuthStore(61-210)web/src/router/routes.ts (1)
ROUTES(7-28)web/src/stores/setup.ts (2)
useSetupStore(13-30)fetchSetupStatus(18-29)
🔇 Additional comments (62)
web/src/components/layout/PlaceholderPage.tsx (1)
1-8: Reusable placeholder component looks good.Nice extraction for page stubs; typed props and markup are clean.
web/src/pages/TaskDetailPage.tsx (1)
1-5: Task detail stub is implemented cleanly.This matches the shared placeholder pattern and keeps routing modules consistent.
web/src/pages/SettingsPage.tsx (1)
1-5: Settings stub follows the shared pattern well.No concerns here.
web/src/pages/MeetingDetailPage.tsx (1)
1-5: Meeting detail stub is good to merge.Implementation is consistent and clear.
web/src/pages/OrgEditPage.tsx (1)
1-5: Nice follow-through on shared placeholder usage.This is aligned with the extracted
PlaceholderPagepattern and removes previous duplication concerns.web/src/pages/ProviderDetailPage.tsx (1)
1-5: Provider detail stub looks correct.No issues in this segment.
web/src/pages/DashboardPage.tsx (1)
1-5: Dashboard stub is clean and consistent.Looks good.
web/.npmrc (1)
1-3: [Your rewritten review comment text here]
[Exactly ONE classification tag]web/src/pages/AgentDetailPage.tsx (1)
1-5: LGTM!Clean placeholder page following the established pattern for route components.
web/src/pages/AgentsPage.tsx (1)
1-5: LGTM!Consistent placeholder page implementation.
web/src/pages/ProvidersPage.tsx (1)
1-5: LGTM!Consistent placeholder page implementation.
web/src/pages/OrgChartPage.tsx (1)
1-5: LGTM!Consistent placeholder page implementation.
web/src/pages/TaskBoardPage.tsx (1)
1-5: LGTM!Consistent placeholder page implementation.
web/src/pages/NotFoundPage.tsx (1)
1-14: LGTM!Well-structured 404 page with proper semantic markup, accessible heading hierarchy, and correct use of the
asChildpattern for the Button-as-Link composition.docker/web/Dockerfile (1)
12-12: LGTM!Including
.npmrcin the build stage ensures consistent npm configuration (legacy-peer-deps=true) across Docker builds, CI, and local development.web/src/pages/MeetingsPage.tsx (1)
1-5: LGTM!Simple placeholder page following the established pattern used by other route modules. The import path and component usage are correct.
web/.storybook/main.ts (1)
1-18: LGTM!Storybook configuration is well-structured. The
viteFinalhook correctly integrates Tailwind CSS 4 via dynamic import, and the nullish coalescing safely handles potentially undefined plugins.web/.storybook/preview.tsx (1)
1-20: LGTM!Preview configuration correctly imports global styles and applies dark theme. The decorator ensures consistent Tailwind styling for all stories.
web/package.json (2)
13-15: LGTM!Storybook scripts are correctly configured. The dev server runs on the standard port 6006, and the build output directory matches the
.gitignoreentry.
42-63: LGTM!All Storybook packages are now consistently versioned at
^8.6.18, addressing the previous review feedback about version alignment..gitignore (1)
54-54: LGTM!Correctly ignores Storybook's static build output directory, consistent with the
storybook:buildscript's output path..github/workflows/ci.yml (2)
310-331: LGTM!The new Storybook build job follows the established pattern for dashboard CI jobs. The
--disable-telemetryflag is a good practice for CI environments, and the 15-minute timeout is appropriate.
337-358: LGTM!The
ci-passgate correctly includesdashboard-storybook-buildin both theneedsarray and theRESULTSaggregation, ensuring Storybook build failures will block the CI gate.CLAUDE.md (4)
56-57: LGTM!Storybook commands are correctly documented with accurate ports and script names matching
package.json.
126-134: LGTM!Package structure documentation accurately reflects the new
pages/androuter/directories, and the updatedcomponents/layout/description.
237-237: LGTM!CI jobs documentation correctly includes the new
storybook-buildstep.
257-257: LGTM!Dependencies list correctly includes Storybook among the web dashboard dependencies.
web/src/stores/setup.ts (1)
1-30: LGTM!Well-structured Zustand store with proper loading guards and error handling. The error path correctly resets
setupCompletetonull(addressing previous review feedback), ensuring guards see an unknown state and can show retry UI.web/src/__tests__/test-utils.tsx (1)
1-36: LGTM!Well-structured test utilities for React Router v7. The
renderWithRouterhelper with a catch-all route is ideal for component-level tests, whilerenderRoutesprovides flexibility for testing full route configurations. Exposing therouterinstance enables route state assertions in tests.web/src/components/ui/button.stories.tsx (1)
1-70: LGTM!Comprehensive Storybook stories covering all button variants and sizes. The
satisfies Meta<typeof Button>pattern ensures type safety. TheAllVariantsstory provides a useful side-by-side comparison for visual review.web/src/components/layout/SidebarNavItem.tsx (1)
15-62: LGTM!The component properly handles:
- Active state styling via NavLink's
isActivecallback- Collapsed mode with icon-only display and title tooltip for accessibility
- Badge capping at 99+ for readability
- Proper
aria-hiddenattributes on decorative elementsweb/src/pages/ApprovalsPage.tsx (1)
1-5: LGTM!Simple placeholder page following the established pattern. Default export is appropriate for lazy-loaded routes.
web/src/pages/MessagesPage.tsx (1)
1-5: LGTM!Consistent placeholder page implementation.
web/src/pages/SettingsNamespacePage.tsx (1)
1-5: LGTM!Appropriate placeholder for the dynamic settings route. When implementing the actual feature, you'll want to use
useParams()to display the actual namespace.web/src/pages/BudgetForecastPage.tsx (1)
1-5: LGTM!Consistent placeholder implementation for the budget forecast route.
web/src/pages/BudgetPage.tsx (1)
1-5: LGTM!Consistent placeholder implementation for the budget route.
web/src/pages/SetupPage.tsx (1)
1-7: Clean setup-page scaffold and styling baseline.This placeholder implementation is clear and suitable for the guarded setup flow.
web/src/App.tsx (1)
1-5: Router handoff inAppis correct and minimal.Good replacement of static content with the router entrypoint.
web/src/pages/LoginPage.tsx (1)
1-7: Login page scaffold looks good for initial guarded routing.No correctness or accessibility blockers in this segment.
web/src/components/layout/AppLayout.tsx (2)
6-12: Accessible loading fallback is implemented correctly.
role="status"plusaria-live="polite"is a solid fix for suspense loading announcements.
14-28: App shell composition is solid.The layout cleanly separates status, navigation, and routed content with proper overflow handling.
web/src/components/layout/StatusBar.tsx (1)
3-69: Status bar implementation is clean and well-factored.Good extraction of primitives (
Divider,Dot,StatusItem) and consistent styling/accessibility treatment.web/src/__tests__/components/layout/SidebarNavItem.test.tsx (1)
6-75: Strong behavioral coverage forSidebarNavItem.These test cases capture the critical collapsed/expanded, badge, and dot branches well.
web/src/__tests__/stores/setup.test.ts (1)
15-132: Setup store tests are comprehensive and high-value.Great coverage of success, failure, retry, and concurrency behavior.
web/src/router/index.tsx (1)
1-40: LGTM!The lazy-loading setup,
SuspenseWrappercomponent, and imports are well-structured. The guard composition (GuestGuardfor login,SetupCompleteGuardfor setup,AuthGuard > SetupGuardfor protected routes) correctly implements the specified access control logic.web/src/__tests__/components/layout/Sidebar.test.tsx (2)
121-137: LGTM!The logout test correctly sets up the spy before rendering, addressing the previous review feedback. The
useAuthStore.setState()call includes all required state fields plus thelogoutspy, ensuring the component captures the mocked function during render.
41-46: LGTM!Test isolation is properly implemented with
resetStore(),localStorage.clear(), andvi.clearAllMocks()inbeforeEach. This prevents state leakage between tests.web/src/__tests__/App.test.tsx (2)
35-49: LGTM!The
beforeEachproperly resets both stores includingerror: falsefor the setup store, addressing the previous review feedback. Test isolation is complete withlocalStorage.clear()andvi.clearAllMocks().
51-76: LGTM!The tests now use semantic, role-based queries (
getByRole('heading', { name: /login/i }),getByRole('navigation', { name: /main navigation/i }),getByRole('main')) instead of fragile text matching and exact counts. This addresses the previous review feedback and makes tests more resilient to UI changes.web/src/router/routes.ts (1)
1-35: LGTM!The centralized route constants provide a clean single source of truth.
PUBLIC_ROUTEScorrectly includes all unauthenticated paths (LOGIN,SETUP,SETUP_STEP), addressing the previous review feedback. Theas constassertion ensures proper literal type inference.web/src/components/layout/Sidebar.tsx (4)
33-47: LGTM!The
readCollapsedandwriteCollapsedhelpers properly guardlocalStorageaccess with try-catch blocks, preventing runtime crashes in restricted browser contexts (private browsing, quota exceeded, etc.). This addresses the previous review feedback.
162-176: LGTM!The button styling uses the extracted
SIDEBAR_BUTTON_CLASSconstant, keeping JSX clean and addressing the previous line-length feedback. The collapse toggle has propertitleandaria-labelattributes for accessibility.
232-243: LGTM!The logout button includes both
titleandaria-label="Logout"for accessibility, and the icon hasaria-hidden="true". This addresses the previous review feedback about screen reader support.
71-75: No changes needed — "SynthOrg" is the project's own product name."SynthOrg" is the defined product name for this framework (visible in
web/src/utils/constants.tsasAPP_NAME, in the README as "What is SynthOrg?", and in the package name). The vendor-agnostic naming rule applies to third-party LLM vendors (Anthropic, OpenAI, Claude, GPT) that should be abstracted, not to the project's own product branding. The current usage is appropriate.> Likely an incorrect or invalid review comment.web/src/router/guards.tsx (4)
50-83: LGTM!The
AuthGuardnow implements fail-closed behavior correctly: it tracks avalidatingstate initialized based on whether we have a token but no user (page refresh scenario), showsFullScreenLoadingwhile validation is in progress, and only renders protected content afterfetchUser()completes. This addresses the previous review feedback about flashing protected UI before token validation.
7-42: LGTM!The shared
FullScreenLoadingandFullScreenErrorcomponents reduce duplication across guards and include proper accessibility attributes (role="status",aria-live="polite",role="alert"). This addresses the previous review feedback about extracting shared components.
91-116: LGTM!
SetupGuardcorrectly handles the three states: loading (shows spinner), error (shows retry UI), and resolved (redirects to setup or renders children). The effect properly guards against redundant fetches with the!loading && !errorconditions.
137-171: LGTM!
SetupCompleteGuardimplements fail-closed security: authenticated users are redirected to dashboard on fetch errors rather than being allowed setup access. Unauthenticated users pass through (setup page handles its own auth flow). This is the correct security posture for protecting the setup wizard.web/src/__tests__/router/guards.test.tsx (4)
131-155: LGTM!The "fails open on non-401 errors" test documents the intentional design decision that transient network failures don't block authenticated users. This addresses the previous review suggestion and clarifies the guard's degraded-state behavior.
256-297: LGTM!The retry interaction test validates the full error-recovery flow: initial failure shows error UI, clicking retry triggers a second fetch, and success renders the protected content. The assertion
expect(mockGetSetupStatus).toHaveBeenCalledTimes(2)confirms the retry actually invoked the API. This addresses the previous review suggestion.
1-54: LGTM!Test setup is well-organized with proper mocks for APIs,
window.locationoverride to prevent navigation side effects, and aresetStoreshelper that fully resets both auth and setup stores including theerrorflag.
454-481: LGTM!The fail-closed test for
SetupCompleteGuardcorrectly verifies that authenticated users are redirected to dashboard when the setup status fetch fails, rather than being allowed access to the setup wizard. This is critical security behavior.
| label: string | ||
| collapsed: boolean | ||
| badge?: number | ||
| dotColor?: string |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Consider constraining dotColor to known color classes.
The dotColor prop accepts any string, which is flexible but could lead to invalid class names being passed. If there's a fixed set of status colors used in the app, consider using a union type.
dotColor?: 'bg-success-500' | 'bg-warning-500' | 'bg-danger-500' | stringThis is a minor observation—the current implementation works correctly.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@web/src/components/layout/SidebarNavItem.tsx` at line 11, The dotColor prop
on SidebarNavItem is overly permissive (string); constrain it to a union of
known CSS class names to prevent invalid classes being passed: update the
dotColor type declaration in SidebarNavItem (prop/interface/type for
SidebarNavItem or SidebarNavItemProps) to something like 'bg-success-500' |
'bg-warning-500' | 'bg-danger-500' | string so callers can use the known set
while retaining a fallback string; adjust any usages or prop defaulting in the
SidebarNavItem component to match the new union type.
| children: [ | ||
| { index: true, element: <DashboardPage /> }, | ||
| { path: 'org', element: <OrgChartPage /> }, | ||
| { path: 'org/edit', element: <OrgEditPage /> }, | ||
| { path: 'tasks', element: <TaskBoardPage /> }, | ||
| { path: 'tasks/:taskId', element: <TaskDetailPage /> }, | ||
| { path: 'budget', element: <BudgetPage /> }, | ||
| { path: 'budget/forecast', element: <BudgetForecastPage /> }, | ||
| { path: 'approvals', element: <ApprovalsPage /> }, | ||
| { path: 'agents', element: <AgentsPage /> }, | ||
| { path: 'agents/:agentName', element: <AgentDetailPage /> }, | ||
| { path: 'messages', element: <MessagesPage /> }, | ||
| { path: 'meetings', element: <MeetingsPage /> }, | ||
| { path: 'meetings/:meetingId', element: <MeetingDetailPage /> }, | ||
| { path: 'providers', element: <ProvidersPage /> }, | ||
| { path: 'providers/:providerName', element: <ProviderDetailPage /> }, | ||
| { path: 'settings', element: <SettingsPage /> }, | ||
| { path: 'settings/:namespace', element: <SettingsNamespacePage /> }, | ||
| { path: '*', element: <NotFoundPage /> }, |
There was a problem hiding this comment.
Lazy-loaded page components inside protected routes lack individual Suspense boundaries.
The page components (DashboardPage, OrgChartPage, etc.) are lazy-loaded but rendered directly without SuspenseWrapper. When navigating between routes, if the new page chunk hasn't loaded yet, React will throw because there's no Suspense boundary catching the lazy component's promise.
The AppLayout wrapper has Suspense (lines 84-86), but once it's mounted, navigating to a child route won't trigger that boundary again—the child lazy component needs its own.
🛠️ Proposed fix: wrap each lazy page in SuspenseWrapper
children: [
- { index: true, element: <DashboardPage /> },
- { path: 'org', element: <OrgChartPage /> },
- { path: 'org/edit', element: <OrgEditPage /> },
- { path: 'tasks', element: <TaskBoardPage /> },
+ { index: true, element: <SuspenseWrapper><DashboardPage /></SuspenseWrapper> },
+ { path: 'org', element: <SuspenseWrapper><OrgChartPage /></SuspenseWrapper> },
+ { path: 'org/edit', element: <SuspenseWrapper><OrgEditPage /></SuspenseWrapper> },
+ { path: 'tasks', element: <SuspenseWrapper><TaskBoardPage /></SuspenseWrapper> },
// ... apply to all lazy-loaded pages📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| children: [ | |
| { index: true, element: <DashboardPage /> }, | |
| { path: 'org', element: <OrgChartPage /> }, | |
| { path: 'org/edit', element: <OrgEditPage /> }, | |
| { path: 'tasks', element: <TaskBoardPage /> }, | |
| { path: 'tasks/:taskId', element: <TaskDetailPage /> }, | |
| { path: 'budget', element: <BudgetPage /> }, | |
| { path: 'budget/forecast', element: <BudgetForecastPage /> }, | |
| { path: 'approvals', element: <ApprovalsPage /> }, | |
| { path: 'agents', element: <AgentsPage /> }, | |
| { path: 'agents/:agentName', element: <AgentDetailPage /> }, | |
| { path: 'messages', element: <MessagesPage /> }, | |
| { path: 'meetings', element: <MeetingsPage /> }, | |
| { path: 'meetings/:meetingId', element: <MeetingDetailPage /> }, | |
| { path: 'providers', element: <ProvidersPage /> }, | |
| { path: 'providers/:providerName', element: <ProviderDetailPage /> }, | |
| { path: 'settings', element: <SettingsPage /> }, | |
| { path: 'settings/:namespace', element: <SettingsNamespacePage /> }, | |
| { path: '*', element: <NotFoundPage /> }, | |
| children: [ | |
| { index: true, element: <SuspenseWrapper><DashboardPage /></SuspenseWrapper> }, | |
| { path: 'org', element: <SuspenseWrapper><OrgChartPage /></SuspenseWrapper> }, | |
| { path: 'org/edit', element: <SuspenseWrapper><OrgEditPage /></SuspenseWrapper> }, | |
| { path: 'tasks', element: <SuspenseWrapper><TaskBoardPage /></SuspenseWrapper> }, | |
| { path: 'tasks/:taskId', element: <SuspenseWrapper><TaskDetailPage /></SuspenseWrapper> }, | |
| { path: 'budget', element: <SuspenseWrapper><BudgetPage /></SuspenseWrapper> }, | |
| { path: 'budget/forecast', element: <SuspenseWrapper><BudgetForecastPage /></SuspenseWrapper> }, | |
| { path: 'approvals', element: <SuspenseWrapper><ApprovalsPage /></SuspenseWrapper> }, | |
| { path: 'agents', element: <SuspenseWrapper><AgentsPage /></SuspenseWrapper> }, | |
| { path: 'agents/:agentName', element: <SuspenseWrapper><AgentDetailPage /></SuspenseWrapper> }, | |
| { path: 'messages', element: <SuspenseWrapper><MessagesPage /></SuspenseWrapper> }, | |
| { path: 'meetings', element: <SuspenseWrapper><MeetingsPage /></SuspenseWrapper> }, | |
| { path: 'meetings/:meetingId', element: <SuspenseWrapper><MeetingDetailPage /></SuspenseWrapper> }, | |
| { path: 'providers', element: <SuspenseWrapper><ProvidersPage /></SuspenseWrapper> }, | |
| { path: 'providers/:providerName', element: <SuspenseWrapper><ProviderDetailPage /></SuspenseWrapper> }, | |
| { path: 'settings', element: <SuspenseWrapper><SettingsPage /></SuspenseWrapper> }, | |
| { path: 'settings/:namespace', element: <SuspenseWrapper><SettingsNamespacePage /></SuspenseWrapper> }, | |
| { path: '*', element: <NotFoundPage /> }, |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@web/src/router/index.tsx` around lines 88 - 106, The child routes list mounts
lazy-loaded components (e.g., DashboardPage, OrgChartPage, TaskBoardPage,
AgentDetailPage, etc.) without per-route Suspense boundaries, causing errors
when navigating to a not-yet-loaded chunk; wrap each route's element with the
project's SuspenseWrapper (or equivalent) so each lazy page has its own suspense
boundary (e.g., replace element: <DashboardPage /> with element:
<SuspenseWrapper><DashboardPage /></SuspenseWrapper> for all entries) while
keeping AppLayout intact.
| { path: 'providers/:providerName', element: <ProviderDetailPage /> }, | ||
| { path: 'settings', element: <SettingsPage /> }, | ||
| { path: 'settings/:namespace', element: <SettingsNamespacePage /> }, | ||
| { path: '*', element: <NotFoundPage /> }, |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if there's a top-level 404 route or if this is the only one
rg -n "NotFoundPage|path:\s*['\"]?\*" web/src/router/Repository: Aureliolo/synthorg
Length of output: 238
🏁 Script executed:
head -120 web/src/router/index.tsx | tail -50Repository: Aureliolo/synthorg
Length of output: 1872
🏁 Script executed:
head -80 web/src/router/index.tsxRepository: Aureliolo/synthorg
Length of output: 2750
🏁 Script executed:
find web/src/router -name "*guard*" -o -name "*Guard*" | head -20Repository: Aureliolo/synthorg
Length of output: 87
🏁 Script executed:
cat -n web/src/router/guards.tsxRepository: Aureliolo/synthorg
Length of output: 6424
Catch-all 404 route is nested inside protected routes—unauthenticated users won't see it.
The * route is a child of the AuthGuard/SetupGuard protected tree. If an unauthenticated user visits /nonexistent, they'll be redirected to /login rather than seeing the 404 page.
If this is intentional (only show 404 after authentication), the current structure is correct. Otherwise, consider adding a top-level catch-all outside the protected tree.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@web/src/router/index.tsx` at line 106, The catch-all route "{ path: '*',
element: <NotFoundPage /> }" is currently nested under the protected tree
(AuthGuard/SetupGuard), so unauthenticated users hit the login redirect instead
of the 404; move the wildcard route out of the AuthGuard/SetupGuard children to
the top-level routes array (or add an additional top-level fallback route) so
NotFoundPage is matched for unknown paths before or outside the protected
wrapper, ensuring the wildcard is not a child of the protected route tree.
web/src/stores/auth.ts
Outdated
| // Save return path so LoginPage can redirect back after re-authentication. | ||
| // sessionStorage is same-origin only, preventing open redirect attacks. | ||
| const currentPath = window.location.pathname | ||
| if (currentPath !== '/login' && currentPath !== '/setup') { | ||
| sessionStorage.setItem('auth_return_path', currentPath) | ||
| } | ||
| // Hard redirect to login -- intentionally uses window.location (not react-router) | ||
| // because this runs in a Zustand store outside the React tree. | ||
| if (currentPath !== '/login' && currentPath !== '/setup') { | ||
| window.location.href = '/login' | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Consider consolidating the duplicate condition check.
The same condition currentPath !== '/login' && currentPath !== '/setup' is checked twice (lines 142 and 147). These can be combined into a single block.
♻️ Suggested consolidation
// Save return path so LoginPage can redirect back after re-authentication.
// sessionStorage is same-origin only, preventing open redirect attacks.
const currentPath = window.location.pathname
if (currentPath !== '/login' && currentPath !== '/setup') {
sessionStorage.setItem('auth_return_path', currentPath)
- }
- // Hard redirect to login -- intentionally uses window.location (not react-router)
- // because this runs in a Zustand store outside the React tree.
- if (currentPath !== '/login' && currentPath !== '/setup') {
+ // Hard redirect to login -- intentionally uses window.location (not react-router)
+ // because this runs in a Zustand store outside the React tree.
window.location.href = '/login'
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Save return path so LoginPage can redirect back after re-authentication. | |
| // sessionStorage is same-origin only, preventing open redirect attacks. | |
| const currentPath = window.location.pathname | |
| if (currentPath !== '/login' && currentPath !== '/setup') { | |
| sessionStorage.setItem('auth_return_path', currentPath) | |
| } | |
| // Hard redirect to login -- intentionally uses window.location (not react-router) | |
| // because this runs in a Zustand store outside the React tree. | |
| if (currentPath !== '/login' && currentPath !== '/setup') { | |
| window.location.href = '/login' | |
| } | |
| // Save return path so LoginPage can redirect back after re-authentication. | |
| // sessionStorage is same-origin only, preventing open redirect attacks. | |
| const currentPath = window.location.pathname | |
| if (currentPath !== '/login' && currentPath !== '/setup') { | |
| sessionStorage.setItem('auth_return_path', currentPath) | |
| // Hard redirect to login -- intentionally uses window.location (not react-router) | |
| // because this runs in a Zustand store outside the React tree. | |
| window.location.href = '/login' | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@web/src/stores/auth.ts` around lines 139 - 149, The duplicate checks using
the same condition on currentPath should be consolidated: compute the condition
once (e.g., a boolean like isNotAuthOrSetup based on currentPath !== '/login' &&
currentPath !== '/setup') and wrap both
sessionStorage.setItem('auth_return_path', currentPath) and the hard redirect
window.location.href = '/login' inside a single if block (or use the boolean to
gate both actions) in the auth store where currentPath, sessionStorage.setItem
and window.location.href are used.
web/src/stores/auth.ts
Outdated
| // Save return path so LoginPage can redirect back after re-authentication. | ||
| // sessionStorage is same-origin only, preventing open redirect attacks. | ||
| const currentPath = window.location.pathname | ||
| if (currentPath !== '/login' && currentPath !== '/setup') { | ||
| sessionStorage.setItem('auth_return_path', currentPath) | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Verify that LoginPage reads auth_return_path from sessionStorage
# Expected: LoginPage should contain logic to read and redirect to auth_return_path
# Search for auth_return_path usage in the codebase
rg -n 'auth_return_path' --type ts --type tsx -g '!*.test.*' -g '!*.spec.*'
# Search specifically in LoginPage if it exists
fd -e tsx -e ts 'LoginPage' --exec cat {}Repository: Aureliolo/synthorg
Length of output: 321
LoginPage must implement redirect logic using stored auth_return_path.
The code stores the return path in sessionStorage (lines 139-144) with a comment indicating "LoginPage can redirect back after re-authentication," but the LoginPage component does not read or use this value. Implement logic in LoginPage to retrieve auth_return_path from sessionStorage and redirect to it after successful authentication.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@web/src/stores/auth.ts` around lines 139 - 144, LoginPage currently doesn't
consume the stored sessionStorage key auth_return_path; update the LoginPage
component (e.g., in its successful authentication handler such as
handleLogin/onAuthenticated or the place that sets the authenticated user and
does navigation) to read sessionStorage.getItem('auth_return_path'), validate
it's a same-origin path (non-empty and starts with '/'), perform a redirect to
that path (fallback to '/' or dashboard if absent/invalid), and then remove the
key (sessionStorage.removeItem('auth_return_path')) so it won't be reused;
ensure this logic runs only after successful authentication and preserves
existing post-login flows.
- Export STORAGE_KEY from Sidebar, import in stories (DRY) - Consolidate duplicate pathname check in clearAuth into single block Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@web/src/stores/auth.ts`:
- Around line 139-147: LoginPage currently doesn't consume the saved
auth_return_path from sessionStorage; update the LoginPage component (the login
success handler, e.g., onLoginSuccess or handleSubmit in LoginPage) to read
sessionStorage.getItem('auth_return_path') after successful authentication,
clear it via sessionStorage.removeItem('auth_return_path'), then navigate to
that path (or fallback to a default route like '/') using the existing
navigation mechanism (e.g., window.location.href or react-router history/push
depending on how LoginPage handles redirects). Ensure the code only reads/clears
the key after a confirmed successful login to preserve existing behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: fe28d066-9b43-462e-9b0a-2f789add1b04
📒 Files selected for processing (3)
web/src/components/layout/Sidebar.stories.tsxweb/src/components/layout/Sidebar.tsxweb/src/stores/auth.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Build Backend
- GitHub Check: Build Sandbox
- GitHub Check: Dependency Review
- GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (2)
web/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
ESLint linting is required for React/TypeScript web dashboard code via
npm --prefix web run lint.
Files:
web/src/stores/auth.tsweb/src/components/layout/Sidebar.stories.tsxweb/src/components/layout/Sidebar.tsx
web/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
TypeScript type checking is required for web dashboard via
npm --prefix web run type-check.
Files:
web/src/stores/auth.tsweb/src/components/layout/Sidebar.stories.tsxweb/src/components/layout/Sidebar.tsx
🧠 Learnings (5)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to docker/{Dockerfile*,compose.yml} : Docker: Backend uses 3-stage build (builder → setup → distroless runtime), Chainguard Python, non-root (UID 65532), CIS-hardened. Web uses nginxinc/nginx-unprivileged, Vue 3 SPA with PrimeVue + Tailwind CSS, SPA routing, API/WebSocket proxy to backend.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T22:02:25.937Z
Learning: Applies to web/package.json : Web dashboard uses Node.js 22+. Key dependencies: React 19, react-router, shadcn/ui, Radix UI, Tailwind CSS 4, Zustand, tanstack/react-query, xyflow/react, Recharts, Framer Motion, cmdk, Axios, Lucide React, Vitest.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to web/** : Web dashboard: Node.js 20+, dependencies in web/package.json (Vue 3, PrimeVue, Tailwind CSS, Pinia, VueFlow, ECharts, Axios, vue-draggable-plus, Vitest, fast-check, ESLint, vue-tsc).
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T15:43:05.601Z
Learning: Applies to web/package.json : Web dashboard Node.js 20+; dependencies in web/package.json (Vue 3, PrimeVue, Tailwind CSS, Pinia, VueFlow, ECharts, Axios, vue-draggable-plus, Vitest, ESLint, vue-tsc)
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to **/*.{py,md} : Line length: 88 characters (ruff).
Applied to files:
web/src/components/layout/Sidebar.tsx
📚 Learning: 2026-03-19T11:33:01.580Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:33:01.580Z
Learning: Applies to web/**/*.vue : Never use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in dashboard code — use generic names: `example-provider`, `example-large-001`, etc.
Applied to files:
web/src/components/layout/Sidebar.tsx
📚 Learning: 2026-03-15T18:28:13.207Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:28:13.207Z
Learning: Applies to {src,tests,web,cli,site}/**/*.{py,ts,tsx,go,astro} : Vendor-agnostic everywhere: NEVER use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in project-owned code, docstrings, comments, tests, or config examples. Use generic names: example-provider, example-large-001, example-medium-001, example-small-001. Vendor names may only appear in: (1) Operations design page provider list (docs/design/operations.md), (2) .claude/ skill/agent files, (3) third-party import paths/module names.
Applied to files:
web/src/components/layout/Sidebar.tsx
📚 Learning: 2026-03-24T22:02:25.937Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-24T22:02:25.937Z
Learning: Applies to +(src|tests)/**/*.py : NEVER use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in project-owned code, docstrings, comments, tests, or config examples. Use generic names: `example-provider`, `example-large-001`, `example-medium-001`, `example-small-001`, `large`/`medium`/`small` as aliases. Vendor names may only appear in: (1) `docs/design/operations.md` provider list, (2) `.claude/` skill/agent files, (3) third-party import paths/module names (e.g. `litellm.types.llms.openai`).
Applied to files:
web/src/components/layout/Sidebar.tsx
🧬 Code graph analysis (2)
web/src/components/layout/Sidebar.stories.tsx (1)
web/src/components/layout/Sidebar.tsx (2)
Sidebar(49-250)STORAGE_KEY(25-25)
web/src/components/layout/Sidebar.tsx (4)
web/src/hooks/useAuth.ts (1)
useAuth(10-31)web/src/stores/auth.ts (2)
logout(204-206)useAuthStore(61-208)web/src/components/layout/SidebarNavItem.tsx (1)
SidebarNavItem(15-63)web/src/router/routes.ts (1)
ROUTES(7-28)
🔇 Additional comments (8)
web/src/components/layout/Sidebar.tsx (5)
71-75: Clarification needed on "SynthOrg" branding.A past review flagged this as a vendor name violation. However, reviewing the learnings more carefully, they prohibit third-party AI vendor names like "Anthropic, OpenAI, Claude, GPT" to keep code vendor-agnostic for LLM providers.
"SynthOrg" appears to be the product/project name itself (per the repository name
Aureliolo/synthorg), not a third-party vendor reference. If this is indeed the product's own branding, the guideline likely doesn't apply here.Please confirm whether "SynthOrg" is the intended product name or if it should be replaced with a generic placeholder per project policy.
33-47: LGTM on localStorage hardening.The
readCollapsedandwriteCollapsedhelper functions properly wrap localStorage access in try/catch blocks, preventing runtime crashes in restricted browser contexts. This addresses the concern from the previous review.
49-60: LGTM on state management.The
collapsedstate initialization andtoggleCollapsehandler are well-implemented:
- Lazy initialization via
readCollapsedfunction- Functional state update pattern ensures correct toggling
- Storage persistence happens synchronously with state update
78-156: LGTM on navigation structure.The navigation section is well-organized with:
- Proper semantic markup (
navwitharia-label)- Consistent use of
ROUTESconstants from centralized config- Conditional rendering of section headings when expanded
- Correct prop passing to
SidebarNavItemcomponents
158-248: LGTM on bottom section accessibility and styling.All accessibility concerns from previous reviews have been addressed:
- Collapse toggle, notifications, and logout buttons all have proper
aria-labelattributes- Connection status indicator has an accessible label
SIDEBAR_BUTTON_CLASSconstant consolidates shared button styles, keeping lines under the length limitweb/src/components/layout/Sidebar.stories.tsx (3)
1-5: LGTM on imports and STORAGE_KEY reuse.The import of
STORAGE_KEYfromSidebar.tsxaddresses the previous review comment about extracting the duplicated'sidebar_collapsed'string into a shared constant.
6-36: LGTM on story meta configuration.The meta configuration properly:
- Sets up mock auth state for the user display section
- Wraps stories in
MemoryRouterfor routing context (required byNavLinkinSidebarNavItem)- Uses
layout: 'fullscreen'for proper sidebar rendering
38-54: LGTM on story variants.Both
ExpandedandCollapsedstories correctly use decorators to setlocalStoragebefore the component renders. This addresses the previous review comments about:
- Using decorators instead of
playhooks for initial state- Removing redundant
playhooks- Using the shared
STORAGE_KEYconstant
| // Hard redirect to login -- intentionally uses window.location (not | ||
| // react-router) because this runs in a Zustand store outside the | ||
| // React tree. Saves return path so LoginPage can redirect back | ||
| // after re-authentication (sessionStorage is same-origin only). | ||
| const currentPath = window.location.pathname | ||
| if (currentPath !== '/login' && currentPath !== '/setup') { | ||
| sessionStorage.setItem('auth_return_path', currentPath) | ||
| window.location.href = '/login' | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify LoginPage implements redirect logic using auth_return_path
rg -n 'auth_return_path' --type ts --type tsx -g '!*.test.*' -g '!*.spec.*' || echo "No usages found"
# Check LoginPage for sessionStorage access
fd -e tsx 'LoginPage' --exec rg -n 'sessionStorage' {} || echo "LoginPage does not access sessionStorage"Repository: Aureliolo/synthorg
Length of output: 163
🏁 Script executed:
#!/bin/bash
# Broader search for auth_return_path without type restrictions
rg -n 'auth_return_path' . --type-list | head -20
echo "---"
rg -n 'auth_return_path' .
# Find and inspect LoginPage file
echo "---"
fd -type f 'LoginPage' .
fd -type f -i 'login' . | grep -i pageRepository: Aureliolo/synthorg
Length of output: 911
🏁 Script executed:
#!/bin/bash
# Find LoginPage file more broadly
find . -type f -name "*ogin*" | grep -v node_modules | grep -v ".git"
echo "---"
# Also check for any file with 'Login' in name
find . -type f \( -name "*.tsx" -o -name "*.ts" -o -name "*.jsx" -o -name "*.js" \) | xargs grep -l "LoginPage\|login.*page\|export.*Login" 2>/dev/null | head -20Repository: Aureliolo/synthorg
Length of output: 352
🏁 Script executed:
#!/bin/bash
# Inspect LoginPage implementation
wc -l ./web/src/pages/LoginPage.tsx
echo "---"
cat -n ./web/src/pages/LoginPage.tsxRepository: Aureliolo/synthorg
Length of output: 361
LoginPage implementation is incomplete—it must retrieve and use auth_return_path to redirect after authentication.
The consolidation of the currentPath check (lines 143-147) correctly fixes the duplicate condition. However, LoginPage is currently a stub that does not consume the stored auth_return_path. The feature does not work end-to-end: the return path is stored in sessionStorage but never retrieved or used for redirection.
LoginPage must be updated to:
- Retrieve
auth_return_pathfrom sessionStorage after successful authentication - Clear it from sessionStorage
- Redirect the user to that path (or a default page if not set)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@web/src/stores/auth.ts` around lines 139 - 147, LoginPage currently doesn't
consume the saved auth_return_path from sessionStorage; update the LoginPage
component (the login success handler, e.g., onLoginSuccess or handleSubmit in
LoginPage) to read sessionStorage.getItem('auth_return_path') after successful
authentication, clear it via sessionStorage.removeItem('auth_return_path'), then
navigate to that path (or fallback to a default route like '/') using the
existing navigation mechanism (e.g., window.location.href or react-router
history/push depending on how LoginPage handles redirects). Ensure the code only
reads/clears the key after a confirmed successful login to preserve existing
behavior.
🤖 I have created a release *beep* *boop* --- #MAJOR CHANGES; We got a somewhat working webui :) ## [0.5.0](v0.4.9...v0.5.0) (2026-03-30) ### Features * add analytics trends and budget forecast API endpoints ([#798](#798)) ([16b61f5](16b61f5)) * add department policies to default templates ([#852](#852)) ([7a41548](7a41548)) * add remaining activity event types (task_started, tool_used, delegation, cost_incurred) ([#832](#832)) ([4252fac](4252fac)) * agent performance, activity, and history API endpoints ([#811](#811)) ([9b75c1d](9b75c1d)) * Agent Profiles and Detail pages (biography, career, performance) ([#874](#874)) ([62d7880](62d7880)) * app shell, Storybook, and CI/CD pipeline ([#819](#819)) ([d4dde90](d4dde90)) * Approvals page with risk grouping, urgency indicators, batch actions ([#889](#889)) ([4e9673d](4e9673d)) * Budget Panel page (P&L dashboard, breakdown charts, forecast) ([#890](#890)) ([b63b0f1](b63b0f1)) * build infrastructure layer (API client, auth, WebSocket) ([#815](#815)) ([9f01d3e](9f01d3e)) * CLI global options infrastructure, UI modes, exit codes, env vars ([#891](#891)) ([fef4fc5](fef4fc5)) * CodeMirror editor and theme preferences toggle ([#905](#905), [#807](#807)) ([#909](#909)) ([41fbedc](41fbedc)) * Company page (department/agent management) ([#888](#888)) ([cfb88b0](cfb88b0)) * comprehensive hint coverage across all CLI commands ([#900](#900)) ([937974e](937974e)) * config system extensions, per-command flags for init/start/stop/status/logs ([#895](#895)) ([32f83fe](32f83fe)) * configurable currency system replacing hardcoded USD ([#854](#854)) ([b372551](b372551)) * Dashboard page (metric cards, activity feed, budget burn) ([#861](#861)) ([7d519d5](7d519d5)) * department health, provider status, and activity feed endpoints ([#818](#818)) ([6d5f196](6d5f196)) * design tokens and core UI components ([#833](#833)) ([ed887f2](ed887f2)) * extend approval, meeting, and budget API responses ([#834](#834)) ([31472bf](31472bf)) * frontend polish -- real-time UX, accessibility, responsive, performance ([#790](#790), [#792](#792), [#791](#791), [#793](#793)) ([#917](#917)) ([f04a537](f04a537)) * implement human roles and access control levels ([#856](#856)) ([d6d8a06](d6d8a06)) * implement semantic conflict detection in workspace merge ([#860](#860)) ([d97283b](d97283b)) * interaction components and animation patterns ([#853](#853)) ([82d4b01](82d4b01)) * Login page + first-run bootstrap + Company page ([#789](#789), [#888](#888)) ([#896](#896)) ([8758e8d](8758e8d)) * Meetings page with timeline viz, token bars, contribution formatting ([#788](#788)) ([#904](#904)) ([b207f46](b207f46)) * Messages page with threading, channel badges, sender indicators ([#787](#787)) ([#903](#903)) ([28293ad](28293ad)) * Org Chart force-directed view and drag-drop reassignment ([#872](#872), [#873](#873)) ([#912](#912)) ([a68a938](a68a938)) * Org Chart page (living nodes, status, CRUD, department health) ([#870](#870)) ([0acbdae](0acbdae)) * per-command flags for remaining commands, auto-behavior wiring, help/discoverability ([#897](#897)) ([3f7afa2](3f7afa2)) * Providers page with backend rework -- health, CRUD, subscription auth ([#893](#893)) ([9f8dd98](9f8dd98)) * scaffold React + Vite + TypeScript + Tailwind project ([#799](#799)) ([bd151aa](bd151aa)) * Settings page with search, dependency indicators, grouped rendering ([#784](#784)) ([#902](#902)) ([a7b9870](a7b9870)) * Setup Wizard rebuild with template comparison, cost estimator, theme customization ([#879](#879)) ([ae8b50b](ae8b50b)) * setup wizard UX -- template filters, card metadata, provider form reuse ([#910](#910)) ([7f04676](7f04676)) * setup wizard UX overhaul -- mode choice, step reorder, provider fixes ([#907](#907)) ([ee964c4](ee964c4)) * structured ModelRequirement in template agent configs ([#795](#795)) ([7433548](7433548)) * Task Board page (rich Kanban, filtering, dependency viz) ([#871](#871)) ([04a19b0](04a19b0)) ### Bug Fixes * align frontend types with backend and debounce WS refetches ([#916](#916)) ([134c11b](134c11b)) * auto-cleanup targets newly pulled images instead of old ones ([#884](#884)) ([50e6591](50e6591)) * correct wipe backup-skip flow and harden error handling ([#808](#808)) ([c05860f](c05860f)) * improve provider setup in wizard, subscription auth, dashboard bugs ([#914](#914)) ([87bf8e6](87bf8e6)) * improve update channel detection and add config get command ([#814](#814)) ([6b137f0](6b137f0)) * resolve all ESLint warnings, add zero-warnings enforcement ([#899](#899)) ([079b46a](079b46a)) * subscription auth uses api_key, base URL optional for cloud providers ([#915](#915)) ([f0098dd](f0098dd)) ### Refactoring * semantic analyzer cleanup -- shared filtering, concurrency, extraction ([#908](#908)) ([81372bf](81372bf)) ### Documentation * brand identity and UX design system from [#765](#765) exploration ([#804](#804)) ([389a9f4](389a9f4)) * page structure and information architecture for v0.5.0 dashboard ([#809](#809)) ([f8d6d4a](f8d6d4a)) * write UX design guidelines with WCAG-verified color system ([#816](#816)) ([4a4594e](4a4594e)) ### Tests * add unit tests for agent hooks and page components ([#875](#875)) ([#901](#901)) ([1d81546](1d81546)) ### CI/CD * bump actions/deploy-pages from 4.0.5 to 5.0.0 in the major group ([#831](#831)) ([01c19de](01c19de)) * bump astral-sh/setup-uv from 7.6.0 to 8.0.0 in /.github/actions/setup-python-uv in the all group ([#920](#920)) ([5f6ba54](5f6ba54)) * bump codecov/codecov-action from 5.5.3 to 6.0.0 in the major group ([#868](#868)) ([f22a181](f22a181)) * bump github/codeql-action from 4.34.1 to 4.35.0 in the all group ([#883](#883)) ([87a4890](87a4890)) * bump sigstore/cosign-installer from 4.1.0 to 4.1.1 in the minor-and-patch group ([#830](#830)) ([7a69050](7a69050)) * bump the all group with 3 updates ([#923](#923)) ([ff27c8e](ff27c8e)) * bump wrangler from 4.76.0 to 4.77.0 in /.github in the minor-and-patch group ([#822](#822)) ([07d43eb](07d43eb)) * bump wrangler from 4.77.0 to 4.78.0 in /.github in the all group ([#882](#882)) ([f84118d](f84118d)) ### Maintenance * add design system enforcement hook and component inventory ([#846](#846)) ([15abc43](15abc43)) * add dev-only auth bypass for frontend testing ([#885](#885)) ([6cdcd8a](6cdcd8a)) * add pre-push rebase check hook ([#855](#855)) ([b637a04](b637a04)) * backend hardening -- eviction/size-caps and model validation ([#911](#911)) ([81253d9](81253d9)) * bump axios from 1.13.6 to 1.14.0 in /web in the all group across 1 directory ([#922](#922)) ([b1b0232](b1b0232)) * bump brace-expansion from 5.0.4 to 5.0.5 in /web ([#862](#862)) ([ba4a565](ba4a565)) * bump eslint-plugin-react-refresh from 0.4.26 to 0.5.2 in /web ([#801](#801)) ([7574bb5](7574bb5)) * bump faker from 40.11.0 to 40.11.1 in the minor-and-patch group ([#803](#803)) ([14d322e](14d322e)) * bump https://github.com/astral-sh/ruff-pre-commit from v0.15.7 to 0.15.8 ([#864](#864)) ([f52901e](f52901e)) * bump nginxinc/nginx-unprivileged from `6582a34` to `f99cc61` in /docker/web in the all group ([#919](#919)) ([df85e4f](df85e4f)) * bump nginxinc/nginx-unprivileged from `ccbac1a` to `6582a34` in /docker/web ([#800](#800)) ([f4e9450](f4e9450)) * bump node from `44bcbf4` to `71be405` in /docker/sandbox ([#827](#827)) ([91bec67](91bec67)) * bump node from `5209bca` to `cf38e1f` in /docker/web ([#863](#863)) ([66d6043](66d6043)) * bump picomatch in /site ([#842](#842)) ([5f20bcc](5f20bcc)) * bump recharts 2->3 and @types/node 22->25 in /web ([#802](#802)) ([a908800](a908800)) * Bump requests from 2.32.5 to 2.33.0 ([#843](#843)) ([41daf69](41daf69)) * bump smol-toml from 1.6.0 to 1.6.1 in /site ([#826](#826)) ([3e5dbe4](3e5dbe4)) * bump the all group with 3 updates ([#921](#921)) ([7bace0b](7bace0b)) * bump the minor-and-patch group across 1 directory with 2 updates ([#829](#829)) ([93e611f](93e611f)) * bump the minor-and-patch group across 1 directory with 3 updates ([#841](#841)) ([7010c8e](7010c8e)) * bump the minor-and-patch group across 1 directory with 3 updates ([#869](#869)) ([548cee5](548cee5)) * bump the minor-and-patch group in /site with 2 updates ([#865](#865)) ([9558101](9558101)) * bump the minor-and-patch group with 2 updates ([#867](#867)) ([4830706](4830706)) * consolidate Dependabot groups to 1 PR per ecosystem ([06d2556](06d2556)) * consolidate Dependabot groups to 1 PR per ecosystem ([#881](#881)) ([06d2556](06d2556)) * improve worktree skill with full dep sync and status enhancements ([#906](#906)) ([772c625](772c625)) * remove Vue remnants and document framework decision ([#851](#851)) ([bf2adf6](bf2adf6)) * update web dependencies and fix brace-expansion CVE ([#880](#880)) ([a7a0ed6](a7a0ed6)) * upgrade to Storybook 10 and TypeScript 6 ([#845](#845)) ([52d95f2](52d95f2)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Summary
createBrowserRouter, lazy-loaded routes for all 20+ pages from page-structure.md, 4 route guards (AuthGuard, SetupGuard, GuestGuard, SetupCompleteGuard), collapsible sidebar (220px/56px icon rail) with primary + workspace nav sections, full-width status bar skeleton matching mockup v2 layout, 404 not-found pagedashboard-storybook-buildjob in ci.yml,web/.npmrcfor consistentlegacy-peer-depsresolution across CI/Docker/local devPre-reviewed by 5 agents, 15 findings addressed
endprop, Zustand selectors, cn() usage)Test plan
npm --prefix web run dev-- navigate to localhost:5173, verify redirect to /login/nonexistentshows 404 page with back-to-dashboard linknpm --prefix web run storybook-- serves at localhost:6006, Button + Sidebar stories rendernpm --prefix web run lint && npm --prefix web run type-check && npm --prefix web run test-- all passnpm --prefix web run build-- production build succeedsnpm --prefix web run storybook:build-- storybook static build succeedsCloses #770