Skip to content

fix: error boundary, NavLink remount, env var standardization, useQuery refactor#247

Merged
DevanshuNEU merged 6 commits into
OpenCodeIntel:mainfrom
DevanshuNEU:fix/p0-and-p1-sprint
Feb 20, 2026
Merged

fix: error boundary, NavLink remount, env var standardization, useQuery refactor#247
DevanshuNEU merged 6 commits into
OpenCodeIntel:mainfrom
DevanshuNEU:fix/p0-and-p1-sprint

Conversation

@DevanshuNEU

@DevanshuNEU DevanshuNEU commented Feb 18, 2026

Copy link
Copy Markdown
Collaborator

What

Focused bug fix and infrastructure sprint. Four distinct fixes, each its own commit.

Changes

1. React Error Boundary (OPE-15)

  • New ErrorBoundary.tsx component wrapping AppRoutes
  • Shows recovery UI instead of white screen on unhandled errors
  • "Try again" resets error state, "Go home" navigates to /

2. NavLink remount fix (OPE-28)

  • Moved NavLink from inside Sidebar body to module scope
  • Was creating new component type every render, breaking React reconciliation
  • Now receives active/showLabels/onClick as props

3. Docker env var standardization (OPE-12)

  • docker-compose.yml now passes SUPABASE_ANON_KEY (was SUPABASE_KEY)
  • Added SUPABASE_JWT_SECRET to backend container
  • auth.py reads SUPABASE_ANON_KEY which was never set in Docker
  • Root .env.example updated with SUPABASE_SERVICE_ROLE_KEY and VOYAGE_API_KEY

4. Supabase env var alignment

  • supabase_service.py fallback now checks SUPABASE_ANON_KEY instead of SUPABASE_KEY

5. Replace fetch-in-useEffect with useQuery (OPE-30)

  • New useRepos hook in useCachedQuery.ts using React Query
  • 30s polling via refetchInterval (replaces manual setInterval)
  • DashboardHome.tsx reduced by ~20 lines of manual data fetching

Files changed: 7

Lines: +350 / -90

Linear

Closes OPE-15, OPE-28, OPE-12, OPE-30
Verified: OPE-8 (already fixed), OPE-13 (already exists), OPE-29 (already done)

Summary by CodeRabbit

  • New Features

    • Error boundary with a friendly fallback UI ("Try again" and "Go home").
    • Repository list now uses automatic refresh and caching for smoother updates.
  • Tests

    • Test runner, setup, and multiple component/hook tests added to improve reliability.
  • Chores

    • Updated environment and deployment settings (new API key entries and env vars).
    • Startup now validates environment on launch.
    • Backend key handling adjusted; sidebar/nav internals refined for more consistent UI behavior.

Wraps AppRoutes in ErrorBoundary so any unhandled component error
shows a recovery UI instead of a blank white screen. Displays the
error message, a 'Try again' button (resets error state) and a
'Go home' button (navigates to /).

Class component because React doesn't support error boundaries
with hooks yet.

Closes OPE-15
NavLink (OPE-28):
- Moved NavLink from inside Sidebar body to module scope
- Was creating a new component type every render, destroying state
- Now receives active/showLabels/onClick as props instead of closures

Docker env vars (OPE-12):
- docker-compose.yml now uses SUPABASE_ANON_KEY (not SUPABASE_KEY)
- Added SUPABASE_JWT_SECRET to backend container env
- auth.py reads SUPABASE_ANON_KEY which was never passed in Docker
- Frontend build args already used SUPABASE_ANON_KEY via different name

Root .env.example (OPE-21):
- Added SUPABASE_SERVICE_ROLE_KEY
- Added VOYAGE_API_KEY (was in backend .env.example but not root)
supabase_service.py was falling back to SUPABASE_KEY which we just
removed from docker-compose. Updated to fall back to SUPABASE_ANON_KEY
which is now the standardized name across all config.

Closes OPE-13 (startup validation already existed, just needed alignment)
Added useRepos hook to useCachedQuery.ts:
- Uses React Query with refetchInterval: 30s (replaces setInterval)
- Request deduplication, caching, loading/error states for free
- Returns invalidate() function for manual refresh after mutations

DashboardHome.tsx:
- Removed manual useState for repos and reposLoading
- Removed fetchRepos function and its useEffect + setInterval
- Replaced all fetchRepos() calls with refreshRepos() (invalidate)
- Reduced component by ~20 lines of manual data fetching code

Closes OPE-30
@vercel

vercel Bot commented Feb 18, 2026

Copy link
Copy Markdown

@DevanshuNEU is attempting to deploy a commit to the Dev's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Feb 18, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds startup environment validation and new env vars (SUPABASE_SERVICE_ROLE_KEY, VOYAGE_API_KEY), switches Supabase anon key usage, integrates validation into backend startup, adds frontend ErrorBoundary, refactors repo fetching to a React Query hook, and introduces Vitest-based test infra and tests.

Changes

Cohort / File(s) Summary
Environment configuration
.env.example, docker-compose.yml, backend/services/supabase_service.py
Added SUPABASE_SERVICE_ROLE_KEY and VOYAGE_API_KEY; replaced references to SUPABASE_KEY with SUPABASE_ANON_KEY; updated Docker env and Supabase fallback/key selection and comments.
Backend startup validation
backend/config/startup_checks.py, backend/main.py
New validate_environment() with REQUIRED_VARS / OPTIONAL_VARS; invoked during app lifespan startup to fast-fail on missing required envs and warn on optional ones.
Frontend error handling
frontend/src/components/ErrorBoundary.tsx, frontend/src/App.tsx
Added class ErrorBoundary (getDerivedStateFromError, componentDidCatch) and wrapped app routes to render a fallback UI with "Try again" and "Go home" actions.
Repo fetching / caching
frontend/src/hooks/useCachedQuery.ts, frontend/src/components/dashboard/DashboardHome.tsx
New useRepos(apiKey) React Query hook (auto-refetch, staleTime, invalidate) and refactored DashboardHome to use it instead of local state/polling; calls invalidate to refresh after mutations.
Sidebar nav refactor
frontend/src/components/dashboard/Sidebar.tsx
Extracted module-level NavLink helper, improved external-link rendering and label/collapse/mobile logic; internal refactor preserving exported API.
Testing infra & tests
frontend/package.json, frontend/vitest.config.ts, frontend/src/test/setup.ts, frontend/src/test/*.test.tsx
Added Vitest and testing-library dev deps and scripts; added vitest.config.ts, test setup file, and new tests for ErrorBoundary, useGraphData, and useDirectoryMatrix.

Sequence Diagram(s)

sequenceDiagram
    participant App as App Startup
    participant Lifespan as Lifespan Manager
    participant Validator as validate_environment()
    participant Logger as Logger Service
    participant Process as Process

    App->>Lifespan: Start application
    Lifespan->>Validator: Call validate_environment()
    Validator->>Validator: Check REQUIRED_VARS
    alt Missing Required Variables
        Validator->>Logger: Log error(s)
        Validator->>Process: Exit(1)
    else All Required Variables Set
        Validator->>Validator: Check OPTIONAL_VARS
        Validator->>Logger: Log warnings for missing optional vars
        Validator->>Logger: Log validation success
        Logger-->>Lifespan: Validation complete
    end
Loading
sequenceDiagram
    participant User as User
    participant Child as Child Component
    participant ErrorBoundary as ErrorBoundary
    participant ErrorUI as Error Fallback UI

    User->>Child: Interact / render
    Child->>Child: Error thrown during render
    Child-->>ErrorBoundary: Error propagates
    ErrorBoundary->>ErrorBoundary: getDerivedStateFromError()
    ErrorBoundary->>ErrorBoundary: componentDidCatch() (log)
    ErrorBoundary->>ErrorUI: Render fallback UI with actions
    ErrorUI-->>User: Show error + "Try again" / "Go home"
    User->>ErrorUI: Click "Try again"
    ErrorUI->>ErrorBoundary: Reset error state
    ErrorBoundary->>Child: Re-render children
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Poem

🐰
I hopped through env and start-up light,
Caught crashes in a gentle night,
Hooks fetch repos with steady pace,
Tests now hum and guards embrace—
A rabbit cheers: the build takes flight! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 36.36% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes all four main fixes across the PR: error boundary implementation, NavLink component remount issue, environment variable standardization, and useQuery hook refactoring.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@DevanshuNEU

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Feb 18, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (2)
frontend/src/components/dashboard/DashboardHome.tsx (1)

33-33: Unused import: useInvalidateRepoCache.

useInvalidateRepoCache is imported but never used in this component. Remove it to avoid confusion.

Proposed fix
-import { useRepos, useInvalidateRepoCache } from '../../hooks/useCachedQuery'
+import { useRepos } from '../../hooks/useCachedQuery'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/dashboard/DashboardHome.tsx` at line 33, Remove the
unused import useInvalidateRepoCache from the import statement in the
DashboardHome component so only useRepos is imported; update the import line
that currently reads "import { useRepos, useInvalidateRepoCache } ..." to remove
useInvalidateRepoCache and run lint/tests to verify no other references to
useInvalidateRepoCache remain in DashboardHome.
frontend/src/hooks/useCachedQuery.ts (1)

196-198: Consider memoizing invalidate to provide a stable reference.

invalidate creates a new closure on every render. If a consumer ever passes it as a prop or uses it in a dependency array, it would trigger unnecessary re-renders or effects. Wrapping it in useCallback is cheap insurance.

Proposed fix
-  const invalidate = () => queryClient.invalidateQueries({ queryKey: ['repos'] })
+  const invalidate = useCallback(
+    () => queryClient.invalidateQueries({ queryKey: ['repos'] }),
+    [queryClient]
+  )

(Add useCallback to the import from @tanstack/react-query or import from react.)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/hooks/useCachedQuery.ts` around lines 196 - 198, The invalidate
closure returned from useCachedQuery is recreated each render; wrap it in
React's useCallback to memoize it (e.g., const invalidate = useCallback(() =>
queryClient.invalidateQueries({ queryKey: ['repos'] }), [queryClient])) and
update the return to provide this memoized invalidate so consumers get a stable
reference; add useCallback to the imports from 'react'.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.env.example:
- Around line 22-23: The .env example uses inline comments on unquoted values
which python-dotenv will parse literally for SUPABASE_JWT_SECRET and
SUPABASE_SERVICE_ROLE_KEY; update the file by removing inline comments after the
values and instead place explanatory comments on the preceding line (or quote
the values) so the assigned values remain clean raw tokens (e.g., move "From
Project Settings -> API -> JWT Secret" and "From Project Settings -> API ->
service_role key" to their own comment lines above the SUPABASE_JWT_SECRET and
SUPABASE_SERVICE_ROLE_KEY entries).

In `@backend/config/startup_checks.py`:
- Line 12: The inline comment above REQUIRED_VARS is outdated; update it to
reflect the actual tuple shape used by REQUIRED_VARS (List[Tuple[str, str]]) —
i.e., two elements: env_var_name and description. Modify the comment near
REQUIRED_VARS in startup_checks.py to remove the ", required" part or replace
the whole comment with a correct description like "# (env_var_name,
description)". Ensure the comment text exactly matches the tuple structure used
by REQUIRED_VARS.

In `@frontend/package.json`:
- Around line 53-65: Add `@testing-library/dom` to devDependencies so
`@testing-library/react` no longer has an unmet peer; update frontend package.json
devDependencies to include "@testing-library/dom" with a version compatible with
"@testing-library/react@^16.3.2" (for example "^8.0.0") and then run the package
manager to install/update (this change relates to the entries
"@testing-library/react", "vitest", and "jsdom" in package.json).

In `@frontend/src/components/ErrorBoundary.tsx`:
- Line 35: The message "An unexpected error occurred. This has been logged." in
ErrorBoundary is misleading because componentDidCatch currently only calls
console.error; update componentDidCatch in the ErrorBoundary class to, when
SENTRY_DSN (or the app's front-end Sentry flag) is present, call
Sentry.captureException(error, { contexts: { react: { componentStack:
info.componentStack } } }) (import Sentry from '@sentry/browser' or the app's
Sentry wrapper and guard with process.env.SENTRY_DSN or the app config),
otherwise change the UI copy to remove "This has been logged." (e.g., "An
unexpected error occurred.") so it doesn't imply server-side logging.
- Around line 13-14: Replace the class-based ErrorBoundary with a functional
wrapper using the react-error-boundary package: create a functional
ErrorBoundary component that uses react-error-boundary's ErrorBoundary (or
useErrorBoundary) and accepts a FallbackComponent prop, moving the current
render fallback UI into that FallbackComponent; remove the class ErrorBoundary
and its lifecycle method componentDidCatch, and instead forward error/ info to
an actual error tracking call inside the onError handler you pass to
react-error-boundary. Also fix the user-facing text currently reading "This has
been logged" to accurately reflect whether errors are being sent (e.g., change
it to "An error occurred" if you don't integrate a tracking service) or
implement a real tracking call in the onError handler before leaving the message
as-is.

In `@frontend/src/hooks/useCachedQuery.ts`:
- Around line 176-194: Replace the inline repository type in the useQuery call
inside useCachedQuery (the const query = useQuery({...}) block) with the shared
Repository interface from frontend/src/types.ts to ensure fields like git_url
match DashboardHome usage; import Repository at the top of useCachedQuery.ts,
change the queryFn return typing to use Array<Repository>, and if additional API
fields (language, created_at, file_count, status) are required, extend the
Repository interface in types.ts rather than keeping a mismatched inline type.

---

Nitpick comments:
In `@frontend/src/components/dashboard/DashboardHome.tsx`:
- Line 33: Remove the unused import useInvalidateRepoCache from the import
statement in the DashboardHome component so only useRepos is imported; update
the import line that currently reads "import { useRepos, useInvalidateRepoCache
} ..." to remove useInvalidateRepoCache and run lint/tests to verify no other
references to useInvalidateRepoCache remain in DashboardHome.

In `@frontend/src/hooks/useCachedQuery.ts`:
- Around line 196-198: The invalidate closure returned from useCachedQuery is
recreated each render; wrap it in React's useCallback to memoize it (e.g., const
invalidate = useCallback(() => queryClient.invalidateQueries({ queryKey:
['repos'] }), [queryClient])) and update the return to provide this memoized
invalidate so consumers get a stable reference; add useCallback to the imports
from 'react'.

Comment thread .env.example Outdated
Comment thread backend/config/startup_checks.py Outdated
Comment thread frontend/package.json
Comment thread frontend/src/components/ErrorBoundary.tsx
Comment thread frontend/src/components/ErrorBoundary.tsx Outdated
Comment thread frontend/src/hooks/useCachedQuery.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (7)
frontend/src/components/dashboard/Sidebar.tsx (6)

33-85: Rename NavLink to avoid shadowing react-router-dom's own export, and consider leveraging its built-in active state.

react-router-dom v7 exports its own NavLink that accepts a className callback ({ isActive, isPending }) => ... for exactly this active-state styling use case. The locally defined function NavLink at line 34 silently shadows that export — not a runtime bug today since NavLink isn't imported from rr-dom here, but it's a naming hazard: any future import { NavLink } from 'react-router-dom' in this file would require aliasing, and readers may conflate the two.

Recommended approach: rename the local helper (e.g. SidebarNavLink) and, optionally, replace the internal <Link> branch with rr-dom's NavLink using the className callback — which would also let you remove the manual isActive() function and the active prop threaded through every call site.

♻️ Proposed rename + native active-state approach
+import { Link, NavLink, useLocation } from 'react-router-dom'
-import { Link, useLocation } from 'react-router-dom'
-// defined at module scope so React can reconcile it across renders
-function NavLink({
+// defined at module scope so React can reconcile it across renders
+function SidebarNavLink({
   item,
-  active,
   showLabels,
   onClick,
 }: {
   item: NavItem
-  active: boolean
   showLabels: boolean
   onClick?: () => void
 }) {
-  const baseClasses = `
-    flex items-center gap-3 px-3 py-2.5 rounded-lg transition-all group
-    ${active 
-      ? 'bg-primary/10 text-primary' 
-      : 'text-muted-foreground hover:text-foreground hover:bg-muted'
-    }
-  `
+  const getClasses = (active: boolean) =>
+    cn(
+      'flex items-center gap-3 px-3 py-2.5 rounded-lg transition-all group',
+      active
+        ? 'bg-primary/10 text-primary'
+        : 'text-muted-foreground hover:text-foreground hover:bg-muted'
+    )
 
   if (item.external) {
     return (
       <a
         href={item.href}
         target="_blank"
         rel="noopener noreferrer"
-        className={baseClasses}
+        className={getClasses(false)}
         onClick={onClick}
       >
         ...
       </a>
     )
   }
 
   return (
-    <Link to={item.href} className={baseClasses} onClick={onClick}>
+    <NavLink
+      to={item.href}
+      className={({ isActive }) => getClasses(isActive)}
+      onClick={onClick}
+    >
       ...
-    </Link>
+    </NavLink>
   )
 }

Then remove the isActive helper from Sidebar and drop the active={isActive(item.href)} prop from every SidebarNavLink call site.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/dashboard/Sidebar.tsx` around lines 33 - 85, Rename
the local helper function NavLink to avoid shadowing react-router-dom's NavLink
(e.g., SidebarNavLink) and update all call sites; optionally replace the
internal <Link> branch with react-router-dom's NavLink using its className
callback to compute active styling so you can remove the isActive helper and
stop passing active={isActive(...)} from Sidebar—adjust imports/usages
accordingly (use NavLink from 'react-router-dom' for route-aware className
callback and keep the external-anchor branch unchanged).

45-51: Prefer cn() over a raw multi-line template literal for baseClasses.

The backtick string starts with \n and ends with \n , producing a className value with leading/trailing whitespace. Browsers ignore it, but using the shadcn cn() utility (typically @/lib/utils) is the idiomatic pattern in this stack for conditional Tailwind composition and avoids the artefact entirely.

♻️ Proposed refactor using `cn()`
+import { cn } from '@/lib/utils'
 ...
-  const baseClasses = `
-    flex items-center gap-3 px-3 py-2.5 rounded-lg transition-all group
-    ${active 
-      ? 'bg-primary/10 text-primary' 
-      : 'text-muted-foreground hover:text-foreground hover:bg-muted'
-    }
-  `
+  const baseClasses = cn(
+    'flex items-center gap-3 px-3 py-2.5 rounded-lg transition-all group',
+    active
+      ? 'bg-primary/10 text-primary'
+      : 'text-muted-foreground hover:text-foreground hover:bg-muted'
+  )

As per coding guidelines, "Use shadcn/ui components over custom UI" — the cn utility is shadcn's canonical class-merging helper.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/dashboard/Sidebar.tsx` around lines 45 - 51, Replace
the multi-line template literal assigned to baseClasses with a call to the
shadcn cn() utility (import from '@/lib/utils') to compose classes without
leading/trailing whitespace and to handle the conditional active classes; locate
the baseClasses declaration in Sidebar.tsx and rewrite it to pass the static
classes and the active ? 'bg-primary/10 text-primary' : 'text-muted-foreground
hover:text-foreground hover:bg-muted' expression into cn() so class merging
follows project conventions.

99-103: Redundant first branch in getWidthClass — both mobileOpen and the default return the same string.

Line 100 is effectively dead; removing it simplifies the function with no behavior change.

♻️ Proposed simplification
  const getWidthClass = () => {
-   if (mobileOpen) return 'w-[var(--sidebar-width)]'
    if (collapsed) return 'w-[var(--sidebar-width-collapsed)]'
    return 'w-[var(--sidebar-width)]'
  }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/dashboard/Sidebar.tsx` around lines 99 - 103, The
getWidthClass function contains a redundant branch: the mobileOpen check returns
the same string as the default case; remove that branch and simplify
getWidthClass to only check collapsed (return
'w-[var(--sidebar-width-collapsed)]' when collapsed) and otherwise return the
default 'w-[var(--sidebar-width)]' using the existing symbols mobileOpen,
collapsed and function getWidthClass to locate and update the code.

99-103: Redundant first branch in getWidthClassmobileOpen and the default path return the same string.

Line 100 is dead code: removing it produces identical runtime behavior and makes the intent (collapsed → narrow, otherwise → full width) immediately legible.

♻️ Proposed simplification
  const getWidthClass = () => {
-   if (mobileOpen) return 'w-[var(--sidebar-width)]'
    if (collapsed) return 'w-[var(--sidebar-width-collapsed)]'
    return 'w-[var(--sidebar-width)]'
  }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/dashboard/Sidebar.tsx` around lines 99 - 103, The
first branch in getWidthClass is redundant because mobileOpen and the default
return the same width; simplify getWidthClass by removing the mobileOpen branch
and returning 'w-[var(--sidebar-width-collapsed)]' when collapsed is true,
otherwise return 'w-[var(--sidebar-width)]' so the function clearly expresses
"collapsed → narrow, otherwise → full width" (update the getWidthClass function
and any related references to rely on collapsed/mobileOpen where needed).

45-51: Prefer cn() over a raw multi-line template literal for baseClasses.

The backtick string starts with a newline and ends with trailing spaces. While browsers silently ignore extra whitespace in className, shadcn's cn utility (typically available in lib/utils) is the idiomatic way to compose conditional Tailwind classes in this stack and avoids the whitespace artifact.

♻️ Proposed refactor using `cn()`
+import { cn } from '@/lib/utils'
 ...
-  const baseClasses = `
-    flex items-center gap-3 px-3 py-2.5 rounded-lg transition-all group
-    ${active 
-      ? 'bg-primary/10 text-primary' 
-      : 'text-muted-foreground hover:text-foreground hover:bg-muted'
-    }
-  `
+  const baseClasses = cn(
+    'flex items-center gap-3 px-3 py-2.5 rounded-lg transition-all group',
+    active
+      ? 'bg-primary/10 text-primary'
+      : 'text-muted-foreground hover:text-foreground hover:bg-muted'
+  )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/dashboard/Sidebar.tsx` around lines 45 - 51, Replace
the multi-line template literal assigned to baseClasses with the project's cn
utility: import cn from "lib/utils" (or existing utils export) and build
baseClasses via cn('flex items-center gap-3 px-3 py-2.5 rounded-lg
transition-all group', active ? 'bg-primary/10 text-primary' :
'text-muted-foreground hover:text-foreground hover:bg-muted') to avoid the
leading newline/trailing-space artifact and use the idiomatic class composition;
update any references to baseClasses in Sidebar (component/JSX) accordingly.

33-85: Rename NavLink to avoid shadowing react-router-dom's own NavLink export.

react-router-dom v7 exports its own NavLink component. The local function at line 34 uses the same name, creating a naming hazard — any future import of import { NavLink } from 'react-router-dom' would require aliasing to avoid collision. Rename to SidebarNavLink for clarity.

⚠️ Regarding the refactor to use react-router-dom's NavLink: react-router-dom v7's NavLink does support a className callback accepting { isActive }. However, the current code includes custom routing logic in the isActive helper (line 90–97) that checks for /dashboard pathname AND /dashboard/repo/* prefixes. React Router's default NavLink matching won't replicate this custom logic. If adopting react-router-dom's NavLink, ensure the routing rules still apply — either by adjusting the route config or retaining the custom matcher.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/dashboard/Sidebar.tsx` around lines 33 - 85, Rename
the locally defined NavLink function to SidebarNavLink (update the function
declaration and all internal references/usages) to avoid shadowing
react-router-dom's NavLink export; ensure any existing imports or future imports
of NavLink from 'react-router-dom' remain unambiguous. While renaming, preserve
the existing custom isActive routing logic (the helper around lines 90–97) so
the same dashboard and /dashboard/repo/* matching behavior continues; if you
later switch to react-router-dom's NavLink, re-implement that matcher via its
className/isActive callback or keep the custom matcher to maintain identical
behavior.
frontend/src/hooks/useCachedQuery.ts (1)

196-198: Memoize invalidate with useCallback to stabilize the reference.

invalidate is recreated on every render. While queryClient is stable, callers that put refreshRepos in useEffect deps will trigger spurious effects.

♻️ Proposed refactor
+import { useQuery, useQueryClient, useCallback } from '@tanstack/react-query'
 
-  const invalidate = () => queryClient.invalidateQueries({ queryKey: ['repos'] })
+  const invalidate = useCallback(
+    () => queryClient.invalidateQueries({ queryKey: ['repos'] }),
+    [queryClient]
+  )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/hooks/useCachedQuery.ts` around lines 196 - 198, The invalidate
function is recreated every render; wrap it in React's useCallback to stabilize
its reference (e.g., const invalidate = useCallback(() =>
queryClient.invalidateQueries({ queryKey: ['repos'] }), [queryClient])) and
return that memoized invalidate from the same place that currently returns {
...query, invalidate } so callers can safely use it in effect deps.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docker-compose.yml`:
- Around line 35-37: The docker-compose backend service environment block is
missing the VOYAGE_API_KEY mapping so the container won't receive the .env
value; add a line like - VOYAGE_API_KEY=${VOYAGE_API_KEY} to the backend
service's environment list in docker-compose.yml (matching how COHERE_API_KEY
and SENTRY_DSN are handled) so startup_checks.py's OPTIONAL_VARS and
.env.example actually get propagated into the container.

In `@frontend/src/components/dashboard/DashboardHome.tsx`:
- Line 33: The import useInvalidateRepoCache in DashboardHome.tsx is unused;
remove it from the import statement (keep useRepos) or, if intended, wire it
into the component where cache invalidation is needed (e.g., call
useInvalidateRepoCache() after repo mutations). Locate the import line
referencing useInvalidateRepoCache and either delete that identifier from the
import list or add the appropriate invocation inside the DashboardHome component
(e.g., call the hook and use its invalidate function after repo changes).

---

Duplicate comments:
In @.env.example:
- Around line 22-23: The .env.example lines for SUPABASE_JWT_SECRET and
SUPABASE_SERVICE_ROLE_KEY trigger dotenv-linter's ValueWithoutQuotes rule;
update the example to wrap the values in quotes (e.g., change
SUPABASE_JWT_SECRET=your-jwt-secret to SUPABASE_JWT_SECRET="your-jwt-secret" and
SUPABASE_SERVICE_ROLE_KEY=eyJ... to SUPABASE_SERVICE_ROLE_KEY="eyJ...") so both
SUPABASE_JWT_SECRET and SUPABASE_SERVICE_ROLE_KEY are quoted.

In `@backend/config/startup_checks.py`:
- Line 12: The inline comment "# (env_var_name, description, required)" is
inconsistent with the actual variable shape used in startup_checks.py:
REQUIRED_VARS is declared as List[Tuple[str, str]]; either update the comment to
reflect the two-tuple shape (e.g. "# (env_var_name, description)") or change
REQUIRED_VARS and its usages to a three-tuple/typed structure (e.g.
List[Tuple[str, str, bool]] or a dataclass) if a "required" flag is intended;
adjust any references to REQUIRED_VARS (and functions that iterate it)
accordingly so the comment and type/signature match.

In `@frontend/package.json`:
- Around line 53-65: Add the missing peer dependency `@testing-library/dom` to
frontend package.json devDependencies so tests using `@testing-library/react`
(v16) can resolve its peer; update the devDependencies block to include
"@testing-library/dom" with a compatible version (match the
`@testing-library/react` major, e.g. latest v8/compatible), then run bun install
to install the new dependency.

In `@frontend/src/components/ErrorBoundary.tsx`:
- Line 35: The error message "An unexpected error occurred. This has been
logged." in the ErrorBoundary component is misleading because componentDidCatch
currently only calls console.error; either integrate a real reporter (e.g., call
Sentry.captureException(error, {extra: info}) inside componentDidCatch of
ErrorBoundary) or change the rendered string in ErrorBoundary's render (or
fallback UI) to a truthful message such as "An unexpected error occurred."
Update the code in the ErrorBoundary class: modify componentDidCatch to call the
chosen reporting API if you wire one up, or edit the JSX/text returned by render
to remove the "This has been logged" claim.
- Around line 13-14: Replace the class-based ErrorBoundary component with the
functional wrapper provided by react-error-boundary: remove the class export
ErrorBoundary (and its Props/State usage) and instead import { ErrorBoundary as
ReactErrorBoundary } from 'react-error-boundary', then export a functional
component named ErrorBoundary that accepts the same props, renders
<ReactErrorBoundary FallbackComponent={FallbackComponent}
onError={onError}>{children}</ReactErrorBoundary>, and implement any previously
in-class behavior (like logging or reset logic) via the onError prop or a small
functional FallbackComponent; reference the original ErrorBoundary class name
and any custom Fallback/handler functions so the replacement preserves existing
behavior.

In `@frontend/src/hooks/useCachedQuery.ts`:
- Around line 180-189: The inline cast returning repositories uses a mismatched
shape (url:string) causing selectedRepoData.git_url to be undefined; update the
return type in useCachedQuery's repository extraction to use the shared
Repository type (import Repository from the types module) and return
data.repositories as Repository[] so callers like DashboardHome.tsx
(selectedRepoData.git_url) get the correct git_url field.

---

Nitpick comments:
In `@frontend/src/components/dashboard/Sidebar.tsx`:
- Around line 33-85: Rename the local helper function NavLink to avoid shadowing
react-router-dom's NavLink (e.g., SidebarNavLink) and update all call sites;
optionally replace the internal <Link> branch with react-router-dom's NavLink
using its className callback to compute active styling so you can remove the
isActive helper and stop passing active={isActive(...)} from Sidebar—adjust
imports/usages accordingly (use NavLink from 'react-router-dom' for route-aware
className callback and keep the external-anchor branch unchanged).
- Around line 45-51: Replace the multi-line template literal assigned to
baseClasses with a call to the shadcn cn() utility (import from '@/lib/utils')
to compose classes without leading/trailing whitespace and to handle the
conditional active classes; locate the baseClasses declaration in Sidebar.tsx
and rewrite it to pass the static classes and the active ? 'bg-primary/10
text-primary' : 'text-muted-foreground hover:text-foreground hover:bg-muted'
expression into cn() so class merging follows project conventions.
- Around line 99-103: The getWidthClass function contains a redundant branch:
the mobileOpen check returns the same string as the default case; remove that
branch and simplify getWidthClass to only check collapsed (return
'w-[var(--sidebar-width-collapsed)]' when collapsed) and otherwise return the
default 'w-[var(--sidebar-width)]' using the existing symbols mobileOpen,
collapsed and function getWidthClass to locate and update the code.
- Around line 99-103: The first branch in getWidthClass is redundant because
mobileOpen and the default return the same width; simplify getWidthClass by
removing the mobileOpen branch and returning
'w-[var(--sidebar-width-collapsed)]' when collapsed is true, otherwise return
'w-[var(--sidebar-width)]' so the function clearly expresses "collapsed →
narrow, otherwise → full width" (update the getWidthClass function and any
related references to rely on collapsed/mobileOpen where needed).
- Around line 45-51: Replace the multi-line template literal assigned to
baseClasses with the project's cn utility: import cn from "lib/utils" (or
existing utils export) and build baseClasses via cn('flex items-center gap-3
px-3 py-2.5 rounded-lg transition-all group', active ? 'bg-primary/10
text-primary' : 'text-muted-foreground hover:text-foreground hover:bg-muted') to
avoid the leading newline/trailing-space artifact and use the idiomatic class
composition; update any references to baseClasses in Sidebar (component/JSX)
accordingly.
- Around line 33-85: Rename the locally defined NavLink function to
SidebarNavLink (update the function declaration and all internal
references/usages) to avoid shadowing react-router-dom's NavLink export; ensure
any existing imports or future imports of NavLink from 'react-router-dom' remain
unambiguous. While renaming, preserve the existing custom isActive routing logic
(the helper around lines 90–97) so the same dashboard and /dashboard/repo/*
matching behavior continues; if you later switch to react-router-dom's NavLink,
re-implement that matcher via its className/isActive callback or keep the custom
matcher to maintain identical behavior.

In `@frontend/src/hooks/useCachedQuery.ts`:
- Around line 196-198: The invalidate function is recreated every render; wrap
it in React's useCallback to stabilize its reference (e.g., const invalidate =
useCallback(() => queryClient.invalidateQueries({ queryKey: ['repos'] }),
[queryClient])) and return that memoized invalidate from the same place that
currently returns { ...query, invalidate } so callers can safely use it in
effect deps.

Comment thread docker-compose.yml
Comment thread frontend/src/components/dashboard/DashboardHome.tsx Outdated
@vercel

vercel Bot commented Feb 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
opencodeintel Ready Ready Preview, Comment Feb 20, 2026 7:12pm

1. docker-compose: add VOYAGE_API_KEY, COHERE_API_KEY, SENTRY_DSN
   to backend env (were in .env.example but never passed to container)
2. DashboardHome: remove unused useInvalidateRepoCache import
3. ErrorBoundary: remove misleading 'This has been logged' claim
   (we only console.error, no Sentry integration yet)
4. startup_checks.py: fix stale comment -- says 3-tuple, actual is
   2-tuple (env_var_name, description)
5. package.json: add @testing-library/dom peer dep required by RTL v16
6. useCachedQuery: use shared Repository type instead of inline cast
   missing git_url field -- fixes undefined git_url in DashboardHome

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (5)
docker-compose.yml (1)

35-43: SUPABASE_KEY → SUPABASE_ANON_KEY rename is a breaking change for existing deployments; add a migration note.

The rename is semantically correct and aligns the compose file with auth.py and supabase_service.py, and the three previously-missing optional vars (COHERE_API_KEY, VOYAGE_API_KEY, SENTRY_DSN) are now wired in — resolving the past review concern.

However, any operator upgrading from a prior version who still has SUPABASE_KEY in their .env will find authentication silently broken (or loudly rejected at startup by startup_checks.py). A short inline comment, or a note in the project README/migration guide, would prevent confusion:

📝 Suggested inline comment
      - SUPABASE_URL=${SUPABASE_URL}
+     # Renamed from SUPABASE_KEY — update your .env accordingly
      - SUPABASE_ANON_KEY=${SUPABASE_ANON_KEY}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docker-compose.yml` around lines 35 - 43, The docker-compose change renames
SUPABASE_KEY → SUPABASE_ANON_KEY which breaks upgrades for operators who still
use SUPABASE_KEY; add a brief inline comment next to the environment block in
docker-compose.yml explaining the rename and instructing operators to update
their .env, and add a note to the README/migration guide; optionally, to be
extra safe, implement a fallback in startup_checks.py (or where envs are read in
auth.py/supabase_service.py) to accept SUPABASE_KEY if SUPABASE_ANON_KEY is
missing and log a deprecation warning so existing deployments don’t fail
silently.
frontend/src/components/dashboard/DashboardHome.tsx (1)

76-76: Consider disabling "Add" buttons during initial repo-list load.

repos defaults to [] while reposLoading is true, so repos.length >= MAX_FREE_REPOS evaluates to false during the initial fetch. A user who is already at the limit could briefly see the buttons as enabled and attempt an add before the actual count is known.

🔧 Suggested fix
- disabled={loading || repos.length >= MAX_FREE_REPOS}
+ disabled={loading || reposLoading || repos.length >= MAX_FREE_REPOS}

Apply the same change to both the "Import from GitHub" button (line 319) and the "Add Repository" button (line 327).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/dashboard/DashboardHome.tsx` at line 76, The "Add"
and "Import from GitHub" buttons can be enabled while repos are still loading
because repos defaults to [], so update their disabled logic to also check the
loading state: change the disabled condition to (reposLoading || repos.length >=
MAX_FREE_REPOS) for both buttons referenced in DashboardHome (look for the
"Import from GitHub" and "Add Repository" button elements) so they remain
disabled during the initial fetch until the real repo count is known.
frontend/src/test/ErrorBoundary.test.tsx (2)

1-1: Smoke-test comment claims "recovers on retry" but no such test exists.

Line 1 declares the intent to test recovery ("recovers on retry"), yet there is no test case that clicks the Try again button and verifies the error state is cleared and children are rendered again. The three existing tests only cover rendering children, showing the fallback, and button presence — not the reset path.

Consider adding a test like:

it('recovers when Try again is clicked', async () => {
  const { rerender } = render(
    <ErrorBoundary>
      <ThrowingChild shouldThrow={true} />
    </ErrorBoundary>
  )
  expect(screen.getByText('Something went wrong')).toBeInTheDocument()

  fireEvent.click(screen.getByText('Try again'))

  rerender(
    <ErrorBoundary>
      <ThrowingChild shouldThrow={false} />
    </ErrorBoundary>
  )
  expect(screen.getByText('child rendered')).toBeInTheDocument()
})

This would also justify the fireEvent import.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/test/ErrorBoundary.test.tsx` at line 1, The test suite declares
"recovers on retry" but lacks a test for the reset path; add a new test that
renders <ErrorBoundary> with <ThrowingChild shouldThrow={true} />, asserts the
fallback ("Something went wrong") is shown, clicks the "Try again" button (use
fireEvent.click on the button), then rerenders <ErrorBoundary> with
<ThrowingChild shouldThrow={false} /> and asserts the child content ("child
rendered") is displayed; this verifies ErrorBoundary.reset logic and justifies
the fireEvent import.

3-3: fireEvent is imported but never used.

fireEvent is imported from @testing-library/react but not referenced in any of the three test cases. Remove it to keep the import surface clean.

♻️ Proposed fix
-import { render, screen, fireEvent } from '@testing-library/react'
+import { render, screen } from '@testing-library/react'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/test/ErrorBoundary.test.tsx` at line 3, Remove the unused import
"fireEvent" from the import statement in ErrorBoundary.test.tsx (currently
imported from '@testing-library/react'); edit the import line that reads "import
{ render, screen, fireEvent } from '@testing-library/react'" to only include the
used symbols (render, screen), then run the linter/tests to confirm no
unused-import warnings remain.
frontend/src/test/useGraphData.test.ts (1)

29-71: Consider sharing a single renderHook result across the last four tests.

Each of the four connected-graph tests independently calls renderHook(() => useGraphData(mockApiData)), which re-runs the ForceAtlas2 layout algorithm every time. Extracting to a beforeAll/module-scoped variable eliminates 3 redundant layout computations.

♻️ Suggested refactor
+import { beforeAll } from 'vitest'
+
+let graph: ReturnType<typeof useGraphData>
+
+beforeAll(() => {
+  const { result } = renderHook(() => useGraphData(mockApiData))
+  graph = result.current
+})
+
 describe('useGraphData', () => {
   it('returns null for empty data', () => {
     const { result } = renderHook(() => useGraphData(undefined))
     expect(result.current).toBeNull()
   })

   it('builds a graph with connected nodes, filters orphans', () => {
-    const { result } = renderHook(() => useGraphData(mockApiData))
-    const graph = result.current!
+    expect(graph).not.toBeNull()

     // orphan.ts has 0 connections, should be filtered
-    expect(graph.order).toBe(3)
+    expect(graph!.order).toBe(3)
     // ...
   })
   // same pattern for remaining tests
 })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/test/useGraphData.test.ts` around lines 29 - 71, The four tests
repeatedly call renderHook(() => useGraphData(mockApiData)) causing redundant
ForceAtlas2 runs; refactor by calling renderHook once in a beforeAll (or
module-scoped) block, store result.current (graph) in a shared variable, and
have each test read from that shared graph; update references to graph, attrs,
etc., so tests use the shared graph instead of invoking renderHook in each it()
(symbols: renderHook, useGraphData, mockApiData, graph, attrs).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@frontend/src/test/ErrorBoundary.test.tsx`:
- Line 2: Remove the unused fireEvent import from the top import list in
ErrorBoundary.test.tsx and either use userEvent (preferred) or fireEvent if you
add interactive assertions; then add a test case named or matching "recovers on
retry" that mounts the ErrorBoundary (the same setup used in existing tests),
triggers the error state, finds and clicks the "Try again" button (the retry
control rendered by ErrorBoundary), and asserts the error is cleared and the
child content renders again to verify recovery behavior. Ensure you reference
the same ErrorBoundary test helpers and JSX used in the existing tests so the
new test reuses the current setup.

In `@frontend/src/test/useGraphData.test.ts`:
- Around line 30-37: Add an explicit null-check assertion before using the
non-null assertion on result.current in the useGraphData tests: call
expect(result.current).not.toBeNull() (or .toBeDefined()) immediately before the
line that reads result.current! and then access result.current. Do this in all
four connected-graph tests where result.current! is used so the test fails with
a clear Vitest assertion if useGraphData returns null.

In `@frontend/src/test/useMatrixData.test.ts`:
- Around line 42-49: Update the test "counts cross-directory deps only in
totalDeps" in frontend/src/test/useMatrixData.test.ts: correct the misleading
comment about edge counts (edge 3 is intra-directory under frontend/src so
cross-directory edges are 3, not 4) and tighten the assertion on
result.current.totalDeps from toBeGreaterThan(0) to an exact check (e.g.,
expect(data.totalDeps).toBe(3)) so the test verifies the deterministic
mockApiData output; reference the useDirectoryMatrix hook and mockApiData used
to produce result.current.
- Around line 19-20: Update the misleading comment before the edge { source:
'backend/routes/auth.py', target: 'backend/main.py' } to describe it as a
backend-internal back-edge that creates an intra-backend cycle (not a
cross-project dependency); explicitly note that this edge (Edge 4) forms a
bidirectional cycle with the existing backend → backend/routes edge (Edge 2) so
the cycle-detection test behaves as expected and any test data description
referring to "cross-project" should be replaced with "intra-backend back-edge"
or equivalent.

---

Duplicate comments:
In `@frontend/src/components/dashboard/DashboardHome.tsx`:
- Line 33: Remove the now-unused import symbol useInvalidateRepoCache from the
import list in DashboardHome.tsx and ensure only useRepos is imported; verify
that any references to useInvalidateRepoCache have been deleted or replaced so
there are no lingering usages or TypeScript errors related to that symbol.

---

Nitpick comments:
In `@docker-compose.yml`:
- Around line 35-43: The docker-compose change renames SUPABASE_KEY →
SUPABASE_ANON_KEY which breaks upgrades for operators who still use
SUPABASE_KEY; add a brief inline comment next to the environment block in
docker-compose.yml explaining the rename and instructing operators to update
their .env, and add a note to the README/migration guide; optionally, to be
extra safe, implement a fallback in startup_checks.py (or where envs are read in
auth.py/supabase_service.py) to accept SUPABASE_KEY if SUPABASE_ANON_KEY is
missing and log a deprecation warning so existing deployments don’t fail
silently.

In `@frontend/src/components/dashboard/DashboardHome.tsx`:
- Line 76: The "Add" and "Import from GitHub" buttons can be enabled while repos
are still loading because repos defaults to [], so update their disabled logic
to also check the loading state: change the disabled condition to (reposLoading
|| repos.length >= MAX_FREE_REPOS) for both buttons referenced in DashboardHome
(look for the "Import from GitHub" and "Add Repository" button elements) so they
remain disabled during the initial fetch until the real repo count is known.

In `@frontend/src/test/ErrorBoundary.test.tsx`:
- Line 1: The test suite declares "recovers on retry" but lacks a test for the
reset path; add a new test that renders <ErrorBoundary> with <ThrowingChild
shouldThrow={true} />, asserts the fallback ("Something went wrong") is shown,
clicks the "Try again" button (use fireEvent.click on the button), then
rerenders <ErrorBoundary> with <ThrowingChild shouldThrow={false} /> and asserts
the child content ("child rendered") is displayed; this verifies
ErrorBoundary.reset logic and justifies the fireEvent import.
- Line 3: Remove the unused import "fireEvent" from the import statement in
ErrorBoundary.test.tsx (currently imported from '@testing-library/react'); edit
the import line that reads "import { render, screen, fireEvent } from
'@testing-library/react'" to only include the used symbols (render, screen),
then run the linter/tests to confirm no unused-import warnings remain.

In `@frontend/src/test/useGraphData.test.ts`:
- Around line 29-71: The four tests repeatedly call renderHook(() =>
useGraphData(mockApiData)) causing redundant ForceAtlas2 runs; refactor by
calling renderHook once in a beforeAll (or module-scoped) block, store
result.current (graph) in a shared variable, and have each test read from that
shared graph; update references to graph, attrs, etc., so tests use the shared
graph instead of invoking renderHook in each it() (symbols: renderHook,
useGraphData, mockApiData, graph, attrs).

Comment thread frontend/src/test/ErrorBoundary.test.tsx
Comment thread frontend/src/test/useGraphData.test.ts
Comment thread frontend/src/test/useMatrixData.test.ts
Comment thread frontend/src/test/useMatrixData.test.ts
…eEvent import

- Moved inline comments on SUPABASE_JWT_SECRET and SUPABASE_SERVICE_ROLE_KEY
  to their own lines above the values. python-dotenv parses everything after
  the = sign including inline comments when values are unquoted.
- Removed unused fireEvent import from ErrorBoundary.test.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
.env.example (1)

23-25: Consider reordering Supabase keys to satisfy dotenv-linter.

dotenv-linter warns that SUPABASE_JWT_SECRET and SUPABASE_SERVICE_ROLE_KEY should precede SUPABASE_URL (alphabetical order: _A…_J…_S…_U…). Functional impact is zero, but keeping the file linter-clean avoids noise in CI.

♻️ Proposed reorder
 # Supabase (Required)
 # Get from: https://app.supabase.com/project/_/settings/api
-SUPABASE_URL=https://your-project.supabase.co
 SUPABASE_ANON_KEY=eyJ...
 # From Project Settings -> API -> JWT Secret
 SUPABASE_JWT_SECRET=your-jwt-secret
 # From Project Settings -> API -> service_role key
 SUPABASE_SERVICE_ROLE_KEY=eyJ...
+SUPABASE_URL=https://your-project.supabase.co
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.env.example around lines 23 - 25, Move the Supabase secret lines so they
appear before SUPABASE_URL to satisfy dotenv-linter's alphabetical ordering:
place SUPABASE_JWT_SECRET and SUPABASE_SERVICE_ROLE_KEY above the SUPABASE_URL
entry (keep their values unchanged), ensuring the .env.example variables are
ordered alphabetically by name to remove the linter warning.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In @.env.example:
- Around line 23-25: Move the Supabase secret lines so they appear before
SUPABASE_URL to satisfy dotenv-linter's alphabetical ordering: place
SUPABASE_JWT_SECRET and SUPABASE_SERVICE_ROLE_KEY above the SUPABASE_URL entry
(keep their values unchanged), ensuring the .env.example variables are ordered
alphabetically by name to remove the linter warning.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant