Skip to content

Inngest ,AI SDK and Pinecone setup complete#13

Open
Ansh-dhanani wants to merge 12 commits intomainfrom
working-branch
Open

Inngest ,AI SDK and Pinecone setup complete#13
Ansh-dhanani wants to merge 12 commits intomainfrom
working-branch

Conversation

@Ansh-dhanani
Copy link
Owner

@Ansh-dhanani Ansh-dhanani commented Jan 24, 2026

Summary by CodeRabbit

Release Notes

  • Documentation

    • Revamped README with improved branding, Getting Started guide, and prerequisites section.
    • Added comprehensive documentation covering architecture, tech stack, GitHub integration, and troubleshooting.
  • New Features

    • Enhanced profile form with field validation, error display, and submission feedback.
  • Improvements

    • Optimized dashboard and settings pages for improved performance and responsiveness.
    • Strengthened error handling and validation across forms and API integrations.
    • Improved GitHub webhook integration robustness.

✏️ Tip: You can customize this high-level summary in your review settings.

- Implemented a checks workflow to run linting, type-checking, tests, and build on pull requests and main branch pushes.
- Created a deploy workflow to automate deployment to Vercel on pushes to the main branch.
- Added VSCode settings for GitHub Actions schema validation.
- Introduced a CONTRIBUTING.md file with guidelines for contributing to the project.
- Consolidated project documentation into a single README.md for easier access.
- Added new logo assets for branding.
@vercel
Copy link

vercel bot commented Jan 24, 2026

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

Project Deployment Review Updated (UTC)
codeturtle Ready Ready Preview, Comment Jan 24, 2026 6:04am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 24, 2026

📝 Walkthrough

Walkthrough

This PR refactors the dashboard to use server-side async components with Suspense instead of client-side React Query, introduces form management utilities with validation, adds authentication middleware, creates reusable form UI components, enhances type safety across the codebase, and updates documentation and build configuration.

Changes

Cohort / File(s) Summary
Documentation & Configuration
.vscode/settings.json, CONTRIBUTING.md, README.md, docs/README.md, next.config.ts, package.json
VSCode YAML schema mapping for GitHub Actions workflows, new contributor guidelines and expanded README with branding and badges, comprehensive docs reference, Next.js config additions (cacheComponents, productionBrowserSourceMaps, logging, turbopack), stricter linting with max-warnings 0.
Dashboard Refactoring
src/app/(dashboard)/dashboard/page.tsx, src/app/(dashboard)/layout.tsx, src/app/(dashboard)/settings/page.tsx
Migrated from client-side React Query to server-side async components with Suspense boundaries; removed authentication gates from layout; extracted GitHub integration UI into separate component; added skeleton fallbacks for loading states.
Form Infrastructure
src/hooks/useForm.ts, src/hooks/useProfile.ts, src/lib/validation.ts
New generic useForm hook for state/error/submission management, new useProfile hook for profile data fetching and editing, validation module with field/schema validation and common schemas.
UI Components
src/components/ui/form-field.tsx, src/components/ui/submit-button.tsx, src/components/pages/profile-form.tsx
New reusable FormField and SubmitButton components, refactored ProfileForm to use hook-based approach with inline error UI and Card-based layout.
Type Safety & Error Handling
src/app/(dashboard)/repositories/page.tsx, src/module/repository/..., src/module/github/github.ts, src/app/api/webhooks/github/route.ts, src/module/repository/hooks/use-connect-repositorys.ts
Added GithubRepository and Repository types, strengthened type guards in webhook handling, improved error handling with unknown types and defensive checks, enhanced repository lookup logic.
API & Middleware
src/app/api/user/route.ts, src/app/api/user/github-account/route.ts, src/middleware.ts
Removed forced-dynamic export from API routes, suppressed error logging for expected prerender behavior, added authentication middleware with protected route enforcement and session validation.
Dashboard Actions
src/module/dashboard/actions/index.ts
Hardened error handling with try/catch blocks and default return values for prerendering scenarios, guarded against missing session/token and API fetch failures.
Minor Cleanups
src/components/navbar.tsx, src/hooks/use-signout.ts, src/components/github/repository-list.tsx
Removed unused formatSegment helper, removed ESLint suppression comments, bare catch for URL parsing errors.

Sequence Diagram(s)

sequenceDiagram
    participant Browser
    participant Middleware
    participant Server
    participant Suspense
    participant Component
    participant Database

    Browser->>Middleware: Request /dashboard
    Middleware->>Server: Session validation via getSession
    alt Session exists
        Server-->>Middleware: Session confirmed
        Middleware-->>Browser: Allow request
        Browser->>Server: Render Page component
        Server->>Suspense: Render DashboardStats (pending)
        Suspense->>Browser: Show DashboardStatsSkeleton
        Component->>Database: Fetch user stats (Octokit)
        Database-->>Component: Stats data
        Component-->>Suspense: Resolve with StatCards
        Suspense->>Browser: Replace skeleton with stats
    else No session
        Server-->>Middleware: No session
        Middleware-->>Browser: Redirect to /login
    end
Loading
sequenceDiagram
    participant User
    participant ProfileForm
    participant useProfile Hook
    participant useForm Hook
    participant API
    participant Toast

    User->>ProfileForm: Render profile settings
    ProfileForm->>useProfile: Initialize hook
    useProfile->>API: Fetch user profile (TanStack Query)
    API-->>useProfile: Profile data
    useProfile->>useForm: Initialize form with profile data
    User->>ProfileForm: Edit name field
    ProfileForm->>useForm: setValue('name', newValue)
    useForm-->>useForm: Clear error for name field
    User->>ProfileForm: Submit form
    ProfileForm->>useForm: handleSubmit(e)
    useForm->>useForm: Validate data via validation schema
    alt Validation passes
        useForm->>API: Call updateUserProfile
        API-->>useForm: Success
        useForm->>Toast: Show success message
    else Validation fails
        useForm-->>ProfileForm: Display field errors
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~55 minutes

Possibly related PRs

Poem

🐰 Hopping through dashboards with grace so fine,
Server-side suspense, a querying design,
Forms with validation now neatly arranged,
Types made safer, middleware exchanged,
CodeRabbit celebrates this thoughtful refrain!

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Title check ⚠️ Warning The PR title claims to add Inngest, AI SDK, and Pinecone setup, but the changeset contains no implementation of these features. Instead, it includes documentation updates, configuration changes, dashboard refactoring, form handling improvements, and middleware additions. Update the title to accurately reflect the main changes, such as 'Refactor dashboard with server components and add contributor documentation' or 'Add authentication middleware and improve form handling'
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing touches
  • 📝 Generate docstrings

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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
README.md (1)

119-128: Version inconsistency: README states Next.js 15, but project uses Next.js 16.

The Tech Stack section mentions "Next.js 15 with App Router" but the project appears to be using Next.js 16.0.10 based on the library context. Update to reflect the actual version.

📝 Proposed fix
 ## Tech Stack
 
-- **Framework:** Next.js 15 with App Router
+- **Framework:** Next.js 16 with App Router
 - **Language:** TypeScript
src/components/github/repository-list.tsx (1)

43-55: Toast message should reflect "Disconnect All" action.

Line 49 shows "Repository disconnected successfully" but this is the disconnectAllMutation handler. The message should indicate multiple repositories were disconnected.

📝 Proposed fix
         onSuccess: (result) => {
             if(result?.success){
                 queryClient.invalidateQueries({ queryKey: ['connected-repositories'] });
                 queryClient.invalidateQueries({ queryKey: ['repository-stats'] });
-                toast.success("Repository disconnected successfully");
+                toast.success("All repositories disconnected successfully");
                 setDisconnectAllOpen(false);
             } else {
-                toast.error("Failed to disconnect repository");
+                toast.error("Failed to disconnect repositories");
             }
         }
🤖 Fix all issues with AI agents
In `@CONTRIBUTING.md`:
- Around line 1-53: The CONTRIBUTING.md references missing files
CODE_OF_CONDUCT.md and .env.example (also mentioned via README.md); fix by
either adding those files to the repo or updating CONTRIBUTING.md/README.md to
remove or replace those references with existing resources (e.g., link to actual
code of conduct file or a different env example), ensuring the text "Read and
follow `CODE_OF_CONDUCT.md`" and "Follow `.env.example` instructions in
`README.md`" are corrected to point to real files or guidance.

In `@docs/README.md`:
- Around line 42-51: The README's Project Structure incorrectly lists "api/" as
a top-level sibling to "app/"; update the section so API routes are shown under
the App Router (e.g., reflect "src/app/api/" rather than "src/api/") and ensure
the example tree matches actual routes used in the repo (for example, the
existing route file src/app/api/user/github-account/route.ts); modify the bullet
for api to indicate it's within app (or remove the standalone api/ entry) and
keep other folder names unchanged.

In `@src/app/`(dashboard)/dashboard/page.tsx:
- Around line 95-112: The ContributionGraphServer component currently only
renders summary text and a legend but never uses contributionData.contributions;
update ContributionGraphServer to iterate over contributionData.contributions
and render the actual contribution grid (e.g., map rows/weeks and cells/days),
using unique keys and appropriate classes/aria attributes so each cell reflects
its contribution count and intensity (class or style) based on
contribution.count; ensure you reference contributionData.contributions, produce
a consistent grid structure (rows/columns) and include tooltip/aria-label
showing the date and count for each cell.

In `@src/app/api/user/github-account/route.ts`:
- Around line 24-25: The catch block currently swallows all exceptions which can
hide real failures; change the anonymous catch to catch (err) in the route
handler and conditionally suppress only expected PPR-related errors (e.g., by
implementing or using a helper like isPprExpectedError(err) or checking known
error codes/messages), otherwise call your logger (e.g., console.error or
requestLogger.error) with the full error and context; update the catch in
src/app/api/user/github-account/route.ts around the GitHub account handling to
perform this selective logging.

In `@src/hooks/useForm.ts`:
- Around line 12-53: The hook freezes initialFormData at mount which breaks
isDirty and reset after async hydration; change initialFormData from a const to
a React state pair (e.g., [initialFormData, setInitialFormData]) and update the
UseFormReturn type so reset accepts an optional newBaseline (reset:
(newBaseline?: Partial<T>) => void). Implement reset to, when newBaseline is
provided, call setInitialFormData(newBaseline as T) and setFormData(newBaseline
as T), otherwise revert to the current initialFormData; ensure isDirty continues
to compare formData to the state-backed initialFormData and update any
dependencies (e.g., setValue/setData callbacks) to reference the state variable
where needed.

In `@src/lib/validation.ts`:
- Around line 32-34: The custom validator is being called with the wrong second
argument ({ fieldName }) in validateField; change validateField to accept the
full data object (e.g., add a parameter data: Record<string, unknown> |
undefined) and call rules.custom(value, data) so rules.custom receives the
complete form data; also update validateData to forward the data when it calls
validateField so cross-field validators can inspect other fields via the second
argument.

In `@src/module/dashboard/actions/index.ts`:
- Around line 107-108: Replace the hardcoded const totalRepos = 30 with real
retrieval or an explicit placeholder: call your repository/count API or model
(e.g., RepositoryModel.countDocuments or RepoService.getConnectedRepoCount) and
assign its awaited result to totalRepos, or set totalRepos = null and document
that the UI should handle a null placeholder; update any surrounding function
(the dashboard action in this file where totalRepos is defined) to await the
count and handle errors (fallback to null and log) so the value is accurate
instead of hardcoded.
🧹 Nitpick comments (12)
src/middleware.ts (2)

21-23: Prefix matching with startsWith may be overly broad.

Routes like /dashboard-admin or /pricing-table would incorrectly match /dashboard and /pricing. Consider using exact matching or more precise route patterns.

♻️ Suggested fix with stricter matching
-  const isProtectedRoute = protectedRoutes.some(route =>
-    pathname.startsWith(route)
-  )
+  const isProtectedRoute = protectedRoutes.some(route =>
+    pathname === route || pathname.startsWith(`${route}/`)
+  )

34-36: Consider avoiding logging potentially sensitive error details.

Logging the full error object may expose sensitive information in server logs. Consider logging only the error message or a sanitized version.

♻️ Suggested fix
     } catch (error) {
-      console.error('Auth middleware error:', error)
+      console.error('Auth middleware error:', error instanceof Error ? error.message : 'Unknown error')
       return NextResponse.redirect(new URL('/login', request.url))
     }
src/module/dashboard/actions/index.ts (3)

71-77: Silent error swallowing hides genuine failures.

Catching all errors and returning defaults makes debugging difficult. Consider logging the error in development or distinguishing between expected (prerender) and unexpected errors.

♻️ Suggested improvement
-  } catch {
+  } catch (error) {
     // During prerendering, return default values (expected PPR behavior)
+    if (process.env.NODE_ENV === 'development') {
+      console.warn('getContributionGraph error:', error);
+    }
     return {
       contributions: [],
       totalContributions: 0,
     };

150-158: Inconsistent error handling compared to other functions.

getContributionGraph and getDashboardStats return early with defaults when session is missing, but getMonthlyActivity throws and relies on the outer catch. For consistency and clarity, consider using the same pattern.

♻️ Suggested fix for consistency
   try {
     const session = await auth.api.getSession({ headers: await headers() });
     if (!session) {
-      throw new Error("Unauthorized");
+      // During prerendering, return default values
+      return getDefaultMonthlyData();
     }
     const token = await getGithubToken();
     if (!token) {
-      throw new Error("No GitHub token found");
+      return getDefaultMonthlyData();
     }

Then extract the default data generation to a helper function to avoid duplication:

function getDefaultMonthlyData() {
  const monthsNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
  const now = new Date();
  const defaultData = [];
  for (let i = 5; i >= 0; i--) {
    const date = new Date(now.getFullYear(), now.getMonth() - i, 1);
    defaultData.push({
      name: `${monthsNames[date.getMonth()]} ${date.getFullYear()}`,
      commits: 0,
      prs: 0,
      reviews: 0,
    });
  }
  return defaultData;
}

145-148: Outdated JSDoc - function no longer throws or returns null.

The docstring states @throws {Error} and Returns null if an error occurs, but the function now returns default data on error and doesn't propagate exceptions.

📝 Suggested doc update
  * `@returns` A promise that resolves to an array of objects, each containing the month name
- * (e.g., "Jan 2023"), and the counts for commits, PRs, and reviews. Returns null if an error occurs.
- * `@throws` {Error} If the user is unauthorized or no GitHub token is found.
+ * (e.g., "Jan 2023"), and the counts for commits, PRs, and reviews. Returns default zero-value data
+ * during prerendering or if an error occurs.
  */
src/app/(dashboard)/settings/page.tsx (1)

64-81: Suspense fallback duplicates Card structure - consider extracting a skeleton component.

The fallback Card mirrors the GithubStatus Card structure. Extracting a GithubStatusSkeleton component would improve maintainability and ensure consistency when the Card design changes.

♻️ Suggested refactor
function GithubStatusSkeleton() {
  return (
    <Card>
      <CardHeader>
        <CardTitle className="flex items-center gap-2">
          <Github className="h-5 w-5" />
          GitHub Integration
        </CardTitle>
        <CardDescription>
          Connect your GitHub account to view contribution data and statistics.
        </CardDescription>
      </CardHeader>
      <CardContent>
        <div className="animate-pulse">Loading...</div>
      </CardContent>
    </Card>
  );
}

// Usage
<Suspense fallback={<GithubStatusSkeleton />}>
  <GithubStatus />
</Suspense>
src/app/(dashboard)/dashboard/page.tsx (2)

88-89: The isLoading={false} prop is redundant in server component context.

Since Suspense handles the loading state, passing isLoading={false} is unnecessary. Consider removing this prop or updating MonthlyActivityChart to not require it when used in server components.

♻️ Suggested fix
-        <MonthlyActivityChart data={monthlyActivity} isLoading={false} />
+        <MonthlyActivityChart data={monthlyActivity} />

147-185: Consider adding an error boundary for resilience.

If any async component fails after hydration, the error could propagate and break the entire page. Wrapping sections in error boundaries would improve resilience.

♻️ Example error boundary usage
import { ErrorBoundary } from 'react-error-boundary'

function ErrorFallback({ error, resetErrorBoundary }) {
  return (
    <Card>
      <CardContent className="py-8 text-center">
        <p className="text-muted-foreground">Failed to load data</p>
        <Button variant="outline" onClick={resetErrorBoundary}>Retry</Button>
      </CardContent>
    </Card>
  )
}

// Usage
<ErrorBoundary FallbackComponent={ErrorFallback}>
  <Suspense fallback={<DashboardStatsSkeleton />}>
    <DashboardStats />
  </Suspense>
</ErrorBoundary>
src/app/api/webhooks/github/route.ts (2)

48-56: Inconsistent query: missing select clause on second lookup.

Line 49-52 uses select: { hookSecret: true } for efficiency, but line 55 fetches the entire repository record. For consistency and to minimize data transfer, add the same select clause.

♻️ Proposed fix
     if (!repoRecord && parsedBody?.repository && typeof parsedBody.repository === 'object' && 'full_name' in parsedBody.repository) {
-      repoRecord = await prisma.repository.findFirst({ where: { fullName: (parsedBody.repository as { full_name: string }).full_name } });
+      repoRecord = await prisma.repository.findFirst({ 
+        where: { fullName: (parsedBody.repository as { full_name: string }).full_name },
+        select: { hookSecret: true }
+      });
     }

84-94: TODO: PR processing is not yet implemented.

The pull_request event handler logs the event but doesn't process it further. Consider implementing the enqueue/processing logic or tracking this as a follow-up task.

Would you like me to help design the PR processing flow or open an issue to track this implementation?

src/module/github/github.ts (1)

140-148: Consider extracting duplicated 404 error handling.

The same error handling pattern for 404 status appears in both listWebhooks and createWebhook catch blocks. A helper function would reduce duplication.

♻️ Proposed helper
function throwIfPermissionError(error: unknown): never | void {
  if (error && typeof error === 'object' && 'status' in error) {
    const err = error as { status: number };
    if (err.status === 404) {
      throw new Error("You don't have permission to create webhooks on this repository. Make sure you have admin access to the repository.");
    }
  }
}

Then use in catch blocks:

   } catch (error: unknown) {
-    if (error && typeof error === 'object' && 'status' in error) {
-      const err = error as { status: number };
-      if (err.status === 404) {
-        throw new Error("You don't have permission to create webhooks on this repository. Make sure you have admin access to the repository.");
-      }
-    }
+    throwIfPermissionError(error);
     throw error;
   }

Also applies to: 168-176

src/app/(dashboard)/repositories/page.tsx (1)

24-39: Centralize repository types to avoid drift.

These types are now defined here and in src/module/repository/actions/index.ts, which risks divergence. Consider extracting them into a shared repository-types.ts (or similar) and importing via import type in both server and client modules.

Comment on lines +1 to +53
# Contributing to CodeTurtle

Thank you for considering contributing — we welcome and appreciate your help!

Please read these guidelines before opening issues or PRs to make the process fast and friendly for everyone.

## Code of Conduct
Read and follow `CODE_OF_CONDUCT.md`. Be respectful and constructive.

## How to Contribute
- For bugs: open an issue with a reproducible example, environment, and expected vs actual behavior.
- For feature ideas: open an issue describing the problem, the proposed solution, and any alternatives.
- For quick fixes and docs: open a PR directly against `main` from a feature branch.

## Development Workflow
1. Fork the repo and create a branch: `feature/<short-desc>` or `fix/<short-desc>`.
2. Keep changes small and focused.
3. Add tests when fixing bugs or adding features.
4. Run linting and tests locally before opening a PR:

```bash
bun install
bun run lint --if-present
bun run test --if-present
```

5. Open a PR and include:
- Summary of changes
- Testing steps
- Related issues

## Pull Request Checklist
- [ ] Branch off `main` and keep PR small
- [ ] Updated/added tests where applicable
- [ ] Linting passes locally
- [ ] Descriptive PR title and body
- [ ] Linked to an issue when appropriate

## Commit Messages
Use short, present-tense messages. Prefer conventional commits (e.g., `feat:`, `fix:`, `chore:`).

## Review & Merging
- At least one approving review required for changes to `main`.
- Maintainers may squash or rebase when merging.

## Local Environment & Secrets
Follow `.env.example` instructions in `README.md`. Do not commit credentials or tokens.

## Reporting Security Issues
If you find a security vulnerability, please report it privately via GitHub Security Advisories or by contacting the maintainer directly. Please do not open a public issue.

---
Thanks again — we look forward to your contribution! No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check for all referenced files
echo "=== Checking for CODE_OF_CONDUCT.md ==="
fd -t f "CODE_OF_CONDUCT.md" --max-depth 1

echo "=== Checking for README.md ==="
fd -t f "README.md" --max-depth 1

echo "=== Checking for .env.example ==="
fd -t f ".env.example" --max-depth 1

echo "=== List root directory files ==="
ls -la | head -20

Repository: Ansh-dhanani/codeturtle

Length of output: 1448


Add missing referenced files or update references.

The CONTRIBUTING.md references two files that do not exist in the repository:

  • CODE_OF_CONDUCT.md (referenced in "Read and follow CODE_OF_CONDUCT.md")
  • .env.example (referenced in "Follow .env.example instructions in README.md")

Either create these files or update the documentation to remove the references to avoid confusing contributors.

🤖 Prompt for AI Agents
In `@CONTRIBUTING.md` around lines 1 - 53, The CONTRIBUTING.md references missing
files CODE_OF_CONDUCT.md and .env.example (also mentioned via README.md); fix by
either adding those files to the repo or updating CONTRIBUTING.md/README.md to
remove or replace those references with existing resources (e.g., link to actual
code of conduct file or a different env example), ensuring the text "Read and
follow `CODE_OF_CONDUCT.md`" and "Follow `.env.example` instructions in
`README.md`" are corrected to point to real files or guidance.

Comment on lines +42 to +51
## Project Structure
```text
src/
├── app/ # Next.js App Router
├── api/ # API routes (auth, webhooks)
├── lib/ # Auth, prisma client, utilities
├── components/ # Shared UI components
├── prisma/ # Prisma schema and migrations
└── styles/ # Global styles
```
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Project structure appears inconsistent with Next.js App Router conventions.

The structure shows api/ as a sibling directory to app/, but based on Next.js App Router conventions and the files in this PR (e.g., src/app/api/user/github-account/route.ts), API routes are located inside src/app/api/.

Suggested fix
 src/
 ├── app/                # Next.js App Router
-├── api/                # API routes (auth, webhooks)
+│   └── api/            # API routes (auth, webhooks)
 ├── lib/                # Auth, prisma client, utilities
 ├── components/         # Shared UI components
-├── prisma/             # Prisma schema and migrations
 └── styles/             # Global styles
+prisma/                 # Prisma schema and migrations (at root)
📝 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.

Suggested change
## Project Structure
```text
src/
├── app/ # Next.js App Router
├── api/ # API routes (auth, webhooks)
├── lib/ # Auth, prisma client, utilities
├── components/ # Shared UI components
├── prisma/ # Prisma schema and migrations
└── styles/ # Global styles
```
src/
├── app/ # Next.js App Router
│ └── api/ # API routes (auth, webhooks)
├── lib/ # Auth, prisma client, utilities
├── components/ # Shared UI components
└── styles/ # Global styles
prisma/ # Prisma schema and migrations (at root)
🤖 Prompt for AI Agents
In `@docs/README.md` around lines 42 - 51, The README's Project Structure
incorrectly lists "api/" as a top-level sibling to "app/"; update the section so
API routes are shown under the App Router (e.g., reflect "src/app/api/" rather
than "src/api/") and ensure the example tree matches actual routes used in the
repo (for example, the existing route file
src/app/api/user/github-account/route.ts); modify the bullet for api to indicate
it's within app (or remove the standalone api/ entry) and keep other folder
names unchanged.

Comment on lines +95 to +112
async function ContributionGraphServer() {
const contributionData = await getContributionGraph()

const {
data: stats,
isLoading: isStatsLoading,
} = useQuery({
queryKey: ['dashboard-stats'],
queryFn: async () => await getDashboardStats(),
refetchOnWindowFocus: false,
})
return (
<div className="w-full">
<div className="text-sm text-muted-foreground mb-2">
{contributionData.totalContributions} contributions in the last year
</div>
<div className="text-xs text-muted-foreground">
Less <span className="inline-block w-2 h-2 bg-muted rounded-sm mx-1"></span>
<span className="inline-block w-2 h-2 bg-blue-200 rounded-sm mx-1"></span>
<span className="inline-block w-2 h-2 bg-blue-300 rounded-sm mx-1"></span>
<span className="inline-block w-2 h-2 bg-blue-400 rounded-sm mx-1"></span>
<span className="inline-block w-2 h-2 bg-blue-500 rounded-sm mx-1"></span> More
</div>
</div>
)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

ContributionGraphServer only renders summary text, not the actual contribution graph.

The component shows total contributions and a legend but doesn't render the contributions array data. The actual contribution grid visualization appears to be missing.

Do you want me to help implement the contribution graph grid visualization using the contributionData.contributions array?

🤖 Prompt for AI Agents
In `@src/app/`(dashboard)/dashboard/page.tsx around lines 95 - 112, The
ContributionGraphServer component currently only renders summary text and a
legend but never uses contributionData.contributions; update
ContributionGraphServer to iterate over contributionData.contributions and
render the actual contribution grid (e.g., map rows/weeks and cells/days), using
unique keys and appropriate classes/aria attributes so each cell reflects its
contribution count and intensity (class or style) based on contribution.count;
ensure you reference contributionData.contributions, produce a consistent grid
structure (rows/columns) and include tooltip/aria-label showing the date and
count for each cell.

Comment on lines +24 to +25
} catch {
// Suppress logging for expected PPR behavior
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Silencing all errors may mask real issues.

While suppressing logs for expected PPR behavior is reasonable, this catch block now silences all errors indiscriminately, including database failures, network issues, or auth errors. Consider logging unexpected errors while filtering out known PPR-related ones.

Suggested approach
-  } catch {
-    // Suppress logging for expected PPR behavior
+  } catch (error) {
+    // Only suppress logging for expected PPR/prerender behavior
+    if (process.env.NODE_ENV === 'development') {
+      console.error("Error checking GitHub account:", error);
+    }

Alternatively, if specific error types are expected during PPR, check for those specifically before suppressing.

📝 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.

Suggested change
} catch {
// Suppress logging for expected PPR behavior
} catch (error) {
// Only suppress logging for expected PPR/prerender behavior
if (process.env.NODE_ENV === 'development') {
console.error("Error checking GitHub account:", error);
}
}
🤖 Prompt for AI Agents
In `@src/app/api/user/github-account/route.ts` around lines 24 - 25, The catch
block currently swallows all exceptions which can hide real failures; change the
anonymous catch to catch (err) in the route handler and conditionally suppress
only expected PPR-related errors (e.g., by implementing or using a helper like
isPprExpectedError(err) or checking known error codes/messages), otherwise call
your logger (e.g., console.error or requestLogger.error) with the full error and
context; update the catch in src/app/api/user/github-account/route.ts around the
GitHub account handling to perform this selective logging.

Comment on lines +12 to +53
interface UseFormReturn<T extends Record<string, unknown>> {
data: T
errors: Record<string, string>
isSubmitting: boolean
isDirty: boolean
setValue: <K extends keyof T>(key: K, value: T[K]) => void
setData: (data: Partial<T>) => void
handleSubmit: (e: React.FormEvent) => void
reset: () => void
}

export function useForm<T extends Record<string, unknown>>({
initialData = {} as Partial<T>,
validate,
onSubmit,
onSuccess,
onError,
}: UseFormOptions<T>): UseFormReturn<T> {
const [formData, setFormData] = React.useState<T>(initialData as T)
const [initialFormData] = React.useState<T>(initialData as T)
const [errors, setErrors] = React.useState<Record<string, string>>({})

const isDirty = useMemo(() => {
return JSON.stringify(formData) !== JSON.stringify(initialFormData)
}, [formData, initialFormData])

const setValue = useCallback(<K extends keyof T>(key: K, value: T[K]) => {
setFormData(prev => ({ ...prev, [key]: value }))
// Clear error when user starts typing
if (errors[key as string]) {
setErrors(prev => ({ ...prev, [key as string]: '' }))
}
}, [errors])

const setData = useCallback((data: Partial<T>) => {
setFormData(prev => ({ ...prev, ...data }))
}, [])

const reset = useCallback(() => {
setFormData(initialFormData)
setErrors({})
}, [initialFormData])
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

find . -type f -name "useForm.ts" -o -name "useForm.js"

Repository: Ansh-dhanani/codeturtle

Length of output: 89


🏁 Script executed:

cat -n ./src/hooks/useForm.ts

Repository: Ansh-dhanani/codeturtle

Length of output: 3141


🏁 Script executed:

find . -type f \( -name "*.test.ts*" -o -name "*.spec.ts*" \) | grep -i form

Repository: Ansh-dhanani/codeturtle

Length of output: 49


🏁 Script executed:

find . -type f \( -name "*.test.ts*" -o -name "*.spec.ts*" \) | head -10

Repository: Ansh-dhanani/codeturtle

Length of output: 49


🏁 Script executed:

rg "useForm" --type ts --type tsx -l

Repository: Ansh-dhanani/codeturtle

Length of output: 94


🏁 Script executed:

rg "useForm" --type ts -B 2 -A 5

Repository: Ansh-dhanani/codeturtle

Length of output: 4746


🏁 Script executed:

cat -n ./src/hooks/useProfile.ts

Repository: Ansh-dhanani/codeturtle

Length of output: 2193


Update baseline after async data loads to keep isDirty accurate.

initialFormData is frozen at mount (line 31), so when callers hydrate data asynchronously (e.g., useProfile fetches user data), isDirty flips true and reset() returns to the old empty defaults instead of the loaded baseline. Allow reset to accept an optional new baseline and update initialFormData accordingly.

🛠️ Suggested fix
 interface UseFormReturn<T extends Record<string, unknown>> {
   data: T
   errors: Record<string, string>
   isSubmitting: boolean
   isDirty: boolean
   setValue: <K extends keyof T>(key: K, value: T[K]) => void
   setData: (data: Partial<T>) => void
   handleSubmit: (e: React.FormEvent) => void
-  reset: () => void
+  reset: (nextInitialData?: T) => void
 }
 
 export function useForm<T extends Record<string, unknown>>({
   initialData = {} as Partial<T>,
   validate,
   onSubmit,
   onSuccess,
   onError,
 }: UseFormOptions<T>): UseFormReturn<T> {
   const [formData, setFormData] = React.useState<T>(initialData as T)
-  const [initialFormData] = React.useState<T>(initialData as T)
+  const [initialFormData, setInitialFormData] = React.useState<T>(initialData as T)
   const [errors, setErrors] = React.useState<Record<string, string>>({})
 
   const reset = useCallback((nextInitialData?: T) => {
+    const next = (nextInitialData ?? initialFormData) as T
+    setInitialFormData(next)
-    setFormData(initialFormData)
+    setFormData(next)
     setErrors({})
-  }, [initialFormData])
+  }, [initialFormData])

Callers can then do form.reset(loadedData) after async loads to keep isDirty accurate and ensure resets work correctly.

📝 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.

Suggested change
interface UseFormReturn<T extends Record<string, unknown>> {
data: T
errors: Record<string, string>
isSubmitting: boolean
isDirty: boolean
setValue: <K extends keyof T>(key: K, value: T[K]) => void
setData: (data: Partial<T>) => void
handleSubmit: (e: React.FormEvent) => void
reset: () => void
}
export function useForm<T extends Record<string, unknown>>({
initialData = {} as Partial<T>,
validate,
onSubmit,
onSuccess,
onError,
}: UseFormOptions<T>): UseFormReturn<T> {
const [formData, setFormData] = React.useState<T>(initialData as T)
const [initialFormData] = React.useState<T>(initialData as T)
const [errors, setErrors] = React.useState<Record<string, string>>({})
const isDirty = useMemo(() => {
return JSON.stringify(formData) !== JSON.stringify(initialFormData)
}, [formData, initialFormData])
const setValue = useCallback(<K extends keyof T>(key: K, value: T[K]) => {
setFormData(prev => ({ ...prev, [key]: value }))
// Clear error when user starts typing
if (errors[key as string]) {
setErrors(prev => ({ ...prev, [key as string]: '' }))
}
}, [errors])
const setData = useCallback((data: Partial<T>) => {
setFormData(prev => ({ ...prev, ...data }))
}, [])
const reset = useCallback(() => {
setFormData(initialFormData)
setErrors({})
}, [initialFormData])
interface UseFormReturn<T extends Record<string, unknown>> {
data: T
errors: Record<string, string>
isSubmitting: boolean
isDirty: boolean
setValue: <K extends keyof T>(key: K, value: T[K]) => void
setData: (data: Partial<T>) => void
handleSubmit: (e: React.FormEvent) => void
reset: (nextInitialData?: T) => void
}
export function useForm<T extends Record<string, unknown>>({
initialData = {} as Partial<T>,
validate,
onSubmit,
onSuccess,
onError,
}: UseFormOptions<T>): UseFormReturn<T> {
const [formData, setFormData] = React.useState<T>(initialData as T)
const [initialFormData, setInitialFormData] = React.useState<T>(initialData as T)
const [errors, setErrors] = React.useState<Record<string, string>>({})
const isDirty = useMemo(() => {
return JSON.stringify(formData) !== JSON.stringify(initialFormData)
}, [formData, initialFormData])
const setValue = useCallback(<K extends keyof T>(key: K, value: T[K]) => {
setFormData(prev => ({ ...prev, [key]: value }))
// Clear error when user starts typing
if (errors[key as string]) {
setErrors(prev => ({ ...prev, [key as string]: '' }))
}
}, [errors])
const setData = useCallback((data: Partial<T>) => {
setFormData(prev => ({ ...prev, ...data }))
}, [])
const reset = useCallback((nextInitialData?: T) => {
const next = (nextInitialData ?? initialFormData) as T
setInitialFormData(next)
setFormData(next)
setErrors({})
}, [initialFormData])
🤖 Prompt for AI Agents
In `@src/hooks/useForm.ts` around lines 12 - 53, The hook freezes initialFormData
at mount which breaks isDirty and reset after async hydration; change
initialFormData from a const to a React state pair (e.g., [initialFormData,
setInitialFormData]) and update the UseFormReturn type so reset accepts an
optional newBaseline (reset: (newBaseline?: Partial<T>) => void). Implement
reset to, when newBaseline is provided, call setInitialFormData(newBaseline as
T) and setFormData(newBaseline as T), otherwise revert to the current
initialFormData; ensure isDirty continues to compare formData to the
state-backed initialFormData and update any dependencies (e.g., setValue/setData
callbacks) to reference the state variable where needed.

Comment on lines +32 to +34
if (rules.custom) {
return rules.custom(value, { fieldName })
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Bug: custom validator receives wrong second argument.

The custom validator signature expects data?: Record<string, unknown> (the form data), but line 33 passes { fieldName } instead. This breaks cross-field validation use cases.

🐛 Proposed fix

Update validateField to accept the full data object:

-export function validateField(value: unknown, rules: ValidationRule, fieldName: string): string | null {
+export function validateField(value: unknown, rules: ValidationRule, fieldName: string, data?: Record<string, unknown>): string | null {
   if (rules.required && (!value || (typeof value === 'string' && value.trim() === ''))) {
     return `${fieldName} is required`
   }
   // ... existing code ...

   if (rules.custom) {
-    return rules.custom(value, { fieldName })
+    return rules.custom(value, data)
   }

   return null
 }

And update validateData to pass the data:

   for (const [field, rules] of Object.entries(schema)) {
-    const error = validateField(data[field], rules, field.charAt(0).toUpperCase() + field.slice(1))
+    const error = validateField(data[field], rules, field.charAt(0).toUpperCase() + field.slice(1), data)
     if (error) {
🤖 Prompt for AI Agents
In `@src/lib/validation.ts` around lines 32 - 34, The custom validator is being
called with the wrong second argument ({ fieldName }) in validateField; change
validateField to accept the full data object (e.g., add a parameter data:
Record<string, unknown> | undefined) and call rules.custom(value, data) so
rules.custom receives the complete form data; also update validateData to
forward the data when it calls validateField so cross-field validators can
inspect other fields via the second argument.

Comment on lines +107 to +108
//todo to fetch total connected repos
const totalRepos = 30;
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Hardcoded totalRepos = 30 should be addressed.

This placeholder value could mislead users. Consider fetching actual connected repository count from the database or returning a clearly marked placeholder (e.g., null with UI handling).

Do you want me to help implement fetching the actual connected repository count?

🤖 Prompt for AI Agents
In `@src/module/dashboard/actions/index.ts` around lines 107 - 108, Replace the
hardcoded const totalRepos = 30 with real retrieval or an explicit placeholder:
call your repository/count API or model (e.g., RepositoryModel.countDocuments or
RepoService.getConnectedRepoCount) and assign its awaited result to totalRepos,
or set totalRepos = null and document that the UI should handle a null
placeholder; update any surrounding function (the dashboard action in this file
where totalRepos is defined) to await the count and handle errors (fallback to
null and log) so the value is accurate instead of hardcoded.

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