From 2d7b7e5b855ebc031e10000a1114833b46d1c378 Mon Sep 17 00:00:00 2001 From: v0agent Date: Thu, 4 Jun 2026 00:39:45 +0000 Subject: [PATCH 01/11] feat: update import path for routes type from.next to .next/dev Updated Next.js type import for development environment. Co-authored-by: Cole Collins <118781133+DealPatrol@users.noreply.github.com> --- next-env.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/next-env.d.ts b/next-env.d.ts index 9edff1c..c4b7818 100644 --- a/next-env.d.ts +++ b/next-env.d.ts @@ -1,6 +1,6 @@ /// /// -import "./.next/types/routes.d.ts"; +import "./.next/dev/types/routes.d.ts"; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. From 8c6a1d93b2d9dc8c29be1403fab2963c3ed9cec0 Mon Sep 17 00:00:00 2001 From: v0agent Date: Fri, 5 Jun 2026 14:32:46 +0000 Subject: [PATCH 02/11] refactor: update Next.js route type import path Updated import path for route types to align with current Next.js structure Co-authored-by: Cole Collins <118781133+DealPatrol@users.noreply.github.com> --- next-env.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/next-env.d.ts b/next-env.d.ts index c4b7818..9edff1c 100644 --- a/next-env.d.ts +++ b/next-env.d.ts @@ -1,6 +1,6 @@ /// /// -import "./.next/dev/types/routes.d.ts"; +import "./.next/types/routes.d.ts"; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. From 1cc534935e04ce865349aad0c612d4ace6da00e9 Mon Sep 17 00:00:00 2001 From: v0agent Date: Fri, 5 Jun 2026 14:34:52 +0000 Subject: [PATCH 03/11] feat: replace dashboard header with sidebar layout Replaced DashboardHeader with DashboardSidebar for updated layout; added sidebar component Co-authored-by: Cole Collins <118781133+DealPatrol@users.noreply.github.com> --- app/dashboard/layout.tsx | 19 ++- components/dashboard-sidebar.tsx | 211 +++++++++++++++++++++++++++++++ 2 files changed, 225 insertions(+), 5 deletions(-) create mode 100644 components/dashboard-sidebar.tsx diff --git a/app/dashboard/layout.tsx b/app/dashboard/layout.tsx index c5c8818..d609863 100644 --- a/app/dashboard/layout.tsx +++ b/app/dashboard/layout.tsx @@ -1,5 +1,5 @@ import { getCurrentUser } from '@/lib/auth' -import { DashboardHeader } from '@/components/dashboard-header' +import { DashboardSidebar } from '@/components/dashboard-sidebar' export default async function DashboardLayout({ children, @@ -14,10 +14,19 @@ export default async function DashboardLayout({ } return ( -
- -
- {children} +
+ {/* Sidebar */} + + + {/* Main Content */} +
+
+ {children} +
) diff --git a/components/dashboard-sidebar.tsx b/components/dashboard-sidebar.tsx new file mode 100644 index 0000000..ad54b40 --- /dev/null +++ b/components/dashboard-sidebar.tsx @@ -0,0 +1,211 @@ +'use client' + +import Link from 'next/link' +import { usePathname } from 'next/navigation' +import { + Zap, LayoutDashboard, FolderGit2, Lightbulb, Bot, + BarChart3, Clock, GitPullRequest, Settings, Plug, + CreditCard, LogOut +} from 'lucide-react' +import { cn } from '@/lib/utils' + +interface SidebarProps { + user?: { + name?: string + email?: string + plan?: 'free' | 'pro' | 'scale' + } +} + +export function DashboardSidebar({ user }: SidebarProps) { + const pathname = usePathname() + + const isActive = (href: string) => pathname === href + + return ( + + ) +} From d2d5fe0191a1dab448fe8a5757648b604bf729a2 Mon Sep 17 00:00:00 2001 From: v0agent Date: Fri, 5 Jun 2026 18:44:44 +0000 Subject: [PATCH 04/11] feat: add authentication checks and redirects for analysis route Co-authored-by: Cole Collins <118781133+DealPatrol@users.noreply.github.com> --- app/api/analyses/[id]/run/route.ts | 34 +++++++++++++++--------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/app/api/analyses/[id]/run/route.ts b/app/api/analyses/[id]/run/route.ts index 3f2f632..8ceedba 100644 --- a/app/api/analyses/[id]/run/route.ts +++ b/app/api/analyses/[id]/run/route.ts @@ -1,4 +1,4 @@ -import { NextRequest } from 'next/server' +import { NextRequest, NextResponse } from 'next/server' import { aiConfigErrorMessage, getAnthropicClient, isAiConfigured } from '@/lib/ai-gateway' import { z } from 'zod' import { getCurrentAccessToken, getCurrentUser } from '@/lib/auth' @@ -132,10 +132,23 @@ const CODE_EXTENSIONS = new Set([ ]) export async function POST( - request: NextRequest, - { params }: { params: Promise<{ id: string }> } + req: NextRequest, + { params }: { params: { id: string } } ) { - const { id } = await params + // Check authentication first - redirect if not authenticated + const accessToken = await getCurrentAccessToken().catch(() => null) + if (!accessToken) { + const redirectUrl = new URL('/api/auth/github/login', req.url) + redirectUrl.searchParams.set('returnTo', `/dashboard/analyses/${params.id}`) + return NextResponse.redirect(redirectUrl) + } + + const user = await getCurrentUser().catch(() => null) + if (!user) { + const redirectUrl = new URL('/api/auth/github/login', req.url) + redirectUrl.searchParams.set('returnTo', `/dashboard/analyses/${params.id}`) + return NextResponse.redirect(redirectUrl) + } // Create a stream for progress updates const encoder = new TextEncoder() @@ -146,25 +159,12 @@ export async function POST( } try { - const accessToken = await getCurrentAccessToken() - if (!accessToken) { - send({ error: 'Sign in with GitHub before running an analysis.' }) - controller.close() - return - } if (!isAiConfigured()) { send({ error: aiConfigErrorMessage() }) controller.close() return } - const user = await getCurrentUser() - if (!user) { - send({ error: 'Sign in with GitHub before running an analysis.' }) - controller.close() - return - } - let sub = await getSubscriptionByGithubId(user.github_id).catch(() => null) if (!sub) { sub = await upsertSubscription({ github_id: user.github_id }).catch(() => null) From 2219333691e2872c47a1122ec88d0a18379159d3 Mon Sep 17 00:00:00 2001 From: v0agent Date: Fri, 5 Jun 2026 18:51:18 +0000 Subject: [PATCH 05/11] refactor: streamline Stripe environment variable management and error handling Co-authored-by: Cole Collins <118781133+DealPatrol@users.noreply.github.com> --- lib/stripe.ts | 55 +-------------------------------------------------- 1 file changed, 1 insertion(+), 54 deletions(-) diff --git a/lib/stripe.ts b/lib/stripe.ts index 6bf5f63..d7db3ba 100644 --- a/lib/stripe.ts +++ b/lib/stripe.ts @@ -4,45 +4,11 @@ let stripeInstance: Stripe | null = null type StripeMode = 'live' | 'test' -function normalizeMode(value?: string): StripeMode { - if (value?.toLowerCase() === 'test') return 'test' - return 'live' -} - function detectModeFromKey(key: string): StripeMode { if (key.startsWith('sk_test_') || key.startsWith('rk_test_')) return 'test' return 'live' } -function getConfiguredMode(): StripeMode { - return normalizeMode(process.env.STRIPE_MODE) -} - -function getSecretKeyForMode(mode: StripeMode): string { - if (mode === 'live') { - return process.env.STRIPE_SECRET_KEY_LIVE || process.env.STRIPE_SECRET_KEY || '' - } - return process.env.STRIPE_SECRET_KEY_TEST || process.env.STRIPE_SECRET_KEY || '' -} - -export function getWebhookSecret(): string { - const mode = getConfiguredMode() - if (mode === 'live') { - return process.env.STRIPE_WEBHOOK_SECRET_LIVE || process.env.STRIPE_WEBHOOK_SECRET || '' - } - return process.env.STRIPE_WEBHOOK_SECRET_TEST || process.env.STRIPE_WEBHOOK_SECRET || '' -} - -export function isStripeConfigured(): boolean { - return !!(getSecretKeyForMode(getConfiguredMode()) && getPriceId()) -} - -export function getStripe(): Stripe { - const mode = getConfiguredMode() - const secretKey = getSecretKeyForMode(mode) - - if (!secretKey) { - throw new Error('STRIPE_SECRET_KEY is not set') function getLiveStripeEnv(name: 'SECRET_KEY' | 'WEBHOOK_SECRET' | 'PRO_PRICE_ID' | 'SCALE_PRICE_ID'): string { return process.env[`STRIPE_LIVE_${name}`] || process.env[`STRIPE_${name}`] || '' } @@ -65,13 +31,7 @@ export function getStripe(): Stripe { console.log('[v0] Available env keys containing STRIPE:', Object.keys(process.env).filter(k => k.includes('STRIPE'))) if (!secretKey) { - throw new Error('STRIPE_LIVE_SECRET_KEY is not set') - } - const keyMode = detectModeFromKey(secretKey) - if (keyMode !== mode) { - throw new Error( - `Stripe mode mismatch: STRIPE_MODE=${mode} but key appears to be ${keyMode}. Update keys to match selected mode.`, - ) + throw new Error('STRIPE_SECRET_KEY is not set') } if (!stripeInstance) { stripeInstance = new Stripe(secretKey, { @@ -137,22 +97,9 @@ export function isPaidPlan(plan: string | null | undefined): plan is Exclude Date: Fri, 5 Jun 2026 23:04:55 +0000 Subject: [PATCH 06/11] feat: update stripe price functions and imports Co-authored-by: Cole Collins <118781133+DealPatrol@users.noreply.github.com> --- app/api/checkout/route.ts | 4 ++-- app/api/stripe/webhook/route.ts | 12 ++---------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/app/api/checkout/route.ts b/app/api/checkout/route.ts index 1dfc543..539e909 100644 --- a/app/api/checkout/route.ts +++ b/app/api/checkout/route.ts @@ -1,6 +1,6 @@ import { NextRequest, NextResponse } from 'next/server' import { getCurrentUser } from '@/lib/auth' -import { getAppUrl, getProPriceId, getStripe, isStripeConfigured } from '@/lib/stripe' +import { getAppUrl, getPriceId, getStripe, isStripeConfigured } from '@/lib/stripe' import { updateUserBilling } from '@/lib/queries' export async function GET(request: NextRequest) { @@ -40,7 +40,7 @@ export async function GET(request: NextRequest) { customer: customerId, line_items: [ { - price: getProPriceId(), + price: getPriceId(), quantity: 1, }, ], diff --git a/app/api/stripe/webhook/route.ts b/app/api/stripe/webhook/route.ts index f2bacbe..3d50dd9 100644 --- a/app/api/stripe/webhook/route.ts +++ b/app/api/stripe/webhook/route.ts @@ -1,16 +1,8 @@ import { NextRequest, NextResponse } from 'next/server' -import { getStripe, getWebhookSecret } from '@/lib/stripe' -import { upsertSubscription, getSubscriptionByStripeCustomerId, getUserByGithubId } from '@/lib/queries' +import { getWebhookSecret, getStripe, getPriceIdForPlan } from '@/lib/stripe' +import { upsertSubscription, getSubscriptionByStripeCustomerId, getUserByGithubId, updateUserBilling } from '@/lib/queries' import { grantCredits, CREDITS } from '@/lib/credits' import type Stripe from 'stripe' -import { CREDITS, grantCredits } from '@/lib/credits' -import { - getSubscriptionByStripeCustomerId, - getUserByGithubId, - updateUserBilling, - upsertSubscription, -} from '@/lib/queries' -import { getPriceIdForPlan, getStripe } from '@/lib/stripe' export const dynamic = 'force-dynamic' export const runtime = 'nodejs' From 243ffae41417e2c38fd9f2bbffcc3c04b3f0a936 Mon Sep 17 00:00:00 2001 From: v0agent Date: Sat, 6 Jun 2026 15:53:15 +0000 Subject: [PATCH 07/11] refactor: streamline Stripe webhook validation and update Next.js environment type import Co-authored-by: Cole Collins <118781133+DealPatrol@users.noreply.github.com> --- app/api/stripe/webhook/route.ts | 7 ------- next-env.d.ts | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/app/api/stripe/webhook/route.ts b/app/api/stripe/webhook/route.ts index 3d50dd9..f913e26 100644 --- a/app/api/stripe/webhook/route.ts +++ b/app/api/stripe/webhook/route.ts @@ -128,13 +128,6 @@ export async function POST(request: NextRequest) { const webhookSecret = getWebhookSecret() if (!signature || !webhookSecret) { return NextResponse.json({ error: 'Webhook not configured' }, { status: 400 }) - if (!process.env.STRIPE_WEBHOOK_SECRET || !process.env.STRIPE_SECRET_KEY) { - console.error('[stripe/webhook] Missing STRIPE_WEBHOOK_SECRET or STRIPE_SECRET_KEY in environment') - return NextResponse.json({ error: 'Webhook not configured' }, { status: 503 }) - } - - if (!signature) { - return NextResponse.json({ error: 'Missing stripe-signature header' }, { status: 400 }) } let body: string diff --git a/next-env.d.ts b/next-env.d.ts index 9edff1c..c4b7818 100644 --- a/next-env.d.ts +++ b/next-env.d.ts @@ -1,6 +1,6 @@ /// /// -import "./.next/types/routes.d.ts"; +import "./.next/dev/types/routes.d.ts"; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. From 497e22a10f7af7c74fad7de844de3ce263c5f38c Mon Sep 17 00:00:00 2001 From: v0agent Date: Sun, 7 Jun 2026 17:56:38 +0000 Subject: [PATCH 08/11] Add better error logging to repository import endpoint --- app/api/repositories/import/route.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/api/repositories/import/route.ts b/app/api/repositories/import/route.ts index 6b344d7..27c4087 100644 --- a/app/api/repositories/import/route.ts +++ b/app/api/repositories/import/route.ts @@ -60,6 +60,7 @@ export async function POST(request: NextRequest) { const imported = [] for (const repo of selectedRepositories) { + console.log('[v0] Importing repo:', repo.full_name) const saved = await createRepository({ user_id: user.id, github_id: repo.id, @@ -70,6 +71,9 @@ export async function POST(request: NextRequest) { default_branch: repo.default_branch, language: repo.language, stars: repo.stars, + }).catch(err => { + console.error('[v0] Error creating repository:', err) + throw err }) imported.push(saved) @@ -77,7 +81,8 @@ export async function POST(request: NextRequest) { return NextResponse.json({ imported, count: imported.length }) } catch (error) { - console.error('Error importing repositories:', error) - return NextResponse.json({ error: 'Failed to import repositories' }, { status: 500 }) + const errorMessage = error instanceof Error ? error.message : String(error) + console.error('[v0] Error importing repositories:', errorMessage, error) + return NextResponse.json({ error: `Failed to import repositories: ${errorMessage}` }, { status: 500 }) } } From 781059e6d004676aa3472b0832d34dd3165e00d7 Mon Sep 17 00:00:00 2001 From: v0agent Date: Sun, 7 Jun 2026 18:13:48 +0000 Subject: [PATCH 09/11] feat: update webhook secret retrieval to use new method Updated Stripe webhook secret retrieval to use new getStripeWebhookSecret function Co-authored-by: Cole Collins <118781133+DealPatrol@users.noreply.github.com> --- app/api/stripe/webhook/route.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/api/stripe/webhook/route.ts b/app/api/stripe/webhook/route.ts index f913e26..393ff39 100644 --- a/app/api/stripe/webhook/route.ts +++ b/app/api/stripe/webhook/route.ts @@ -1,5 +1,5 @@ import { NextRequest, NextResponse } from 'next/server' -import { getWebhookSecret, getStripe, getPriceIdForPlan } from '@/lib/stripe' +import { getStripeWebhookSecret, getStripe, getPriceIdForPlan } from '@/lib/stripe' import { upsertSubscription, getSubscriptionByStripeCustomerId, getUserByGithubId, updateUserBilling } from '@/lib/queries' import { grantCredits, CREDITS } from '@/lib/credits' import type Stripe from 'stripe' @@ -125,7 +125,7 @@ async function persistSubscriptionState(params: { export async function POST(request: NextRequest) { const signature = request.headers.get('stripe-signature') - const webhookSecret = getWebhookSecret() + const webhookSecret = getStripeWebhookSecret() if (!signature || !webhookSecret) { return NextResponse.json({ error: 'Webhook not configured' }, { status: 400 }) } From a0adfee0d0e4c7c65ec61e9d1a7a554aab026a9c Mon Sep 17 00:00:00 2001 From: v0agent Date: Mon, 8 Jun 2026 01:25:42 +0000 Subject: [PATCH 10/11] feat: update API route parameter handling and error logging Co-authored-by: Cole Collins <118781133+DealPatrol@users.noreply.github.com> --- app/api/analyses/[id]/run/route.ts | 9 ++++++--- app/api/repositories/import/route.ts | 9 ++------- app/api/stripe/webhook/route.ts | 4 ++-- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/app/api/analyses/[id]/run/route.ts b/app/api/analyses/[id]/run/route.ts index 8ceedba..844339d 100644 --- a/app/api/analyses/[id]/run/route.ts +++ b/app/api/analyses/[id]/run/route.ts @@ -133,20 +133,23 @@ const CODE_EXTENSIONS = new Set([ export async function POST( req: NextRequest, - { params }: { params: { id: string } } + { params }: { params: Promise<{ id: string }> } ) { + // Await params in Next.js 16 + const { id } = await params + // Check authentication first - redirect if not authenticated const accessToken = await getCurrentAccessToken().catch(() => null) if (!accessToken) { const redirectUrl = new URL('/api/auth/github/login', req.url) - redirectUrl.searchParams.set('returnTo', `/dashboard/analyses/${params.id}`) + redirectUrl.searchParams.set('returnTo', `/dashboard/analyses/${id}`) return NextResponse.redirect(redirectUrl) } const user = await getCurrentUser().catch(() => null) if (!user) { const redirectUrl = new URL('/api/auth/github/login', req.url) - redirectUrl.searchParams.set('returnTo', `/dashboard/analyses/${params.id}`) + redirectUrl.searchParams.set('returnTo', `/dashboard/analyses/${id}`) return NextResponse.redirect(redirectUrl) } diff --git a/app/api/repositories/import/route.ts b/app/api/repositories/import/route.ts index 27c4087..6b344d7 100644 --- a/app/api/repositories/import/route.ts +++ b/app/api/repositories/import/route.ts @@ -60,7 +60,6 @@ export async function POST(request: NextRequest) { const imported = [] for (const repo of selectedRepositories) { - console.log('[v0] Importing repo:', repo.full_name) const saved = await createRepository({ user_id: user.id, github_id: repo.id, @@ -71,9 +70,6 @@ export async function POST(request: NextRequest) { default_branch: repo.default_branch, language: repo.language, stars: repo.stars, - }).catch(err => { - console.error('[v0] Error creating repository:', err) - throw err }) imported.push(saved) @@ -81,8 +77,7 @@ export async function POST(request: NextRequest) { return NextResponse.json({ imported, count: imported.length }) } catch (error) { - const errorMessage = error instanceof Error ? error.message : String(error) - console.error('[v0] Error importing repositories:', errorMessage, error) - return NextResponse.json({ error: `Failed to import repositories: ${errorMessage}` }, { status: 500 }) + console.error('Error importing repositories:', error) + return NextResponse.json({ error: 'Failed to import repositories' }, { status: 500 }) } } diff --git a/app/api/stripe/webhook/route.ts b/app/api/stripe/webhook/route.ts index 393ff39..f913e26 100644 --- a/app/api/stripe/webhook/route.ts +++ b/app/api/stripe/webhook/route.ts @@ -1,5 +1,5 @@ import { NextRequest, NextResponse } from 'next/server' -import { getStripeWebhookSecret, getStripe, getPriceIdForPlan } from '@/lib/stripe' +import { getWebhookSecret, getStripe, getPriceIdForPlan } from '@/lib/stripe' import { upsertSubscription, getSubscriptionByStripeCustomerId, getUserByGithubId, updateUserBilling } from '@/lib/queries' import { grantCredits, CREDITS } from '@/lib/credits' import type Stripe from 'stripe' @@ -125,7 +125,7 @@ async function persistSubscriptionState(params: { export async function POST(request: NextRequest) { const signature = request.headers.get('stripe-signature') - const webhookSecret = getStripeWebhookSecret() + const webhookSecret = getWebhookSecret() if (!signature || !webhookSecret) { return NextResponse.json({ error: 'Webhook not configured' }, { status: 400 }) } From ae01a4e4d392dc0d5f3ccfed6a61c5a6b731c6b7 Mon Sep 17 00:00:00 2001 From: v0agent Date: Sun, 14 Jun 2026 05:06:41 +0000 Subject: [PATCH 11/11] feat: rename getWebhookSecret to getStripeWebhookSecret in stripe webhook route Renamed function for clarity and consistency in stripe secret handling Co-authored-by: Cole Collins <118781133+DealPatrol@users.noreply.github.com> --- app/api/stripe/webhook/route.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/api/stripe/webhook/route.ts b/app/api/stripe/webhook/route.ts index f913e26..f8d1aab 100644 --- a/app/api/stripe/webhook/route.ts +++ b/app/api/stripe/webhook/route.ts @@ -1,5 +1,5 @@ import { NextRequest, NextResponse } from 'next/server' -import { getWebhookSecret, getStripe, getPriceIdForPlan } from '@/lib/stripe' +import { getStripeWebhookSecret, getStripe, getPriceIdForPlan } from '@/lib/stripe' import { upsertSubscription, getSubscriptionByStripeCustomerId, getUserByGithubId, updateUserBilling } from '@/lib/queries' import { grantCredits, CREDITS } from '@/lib/credits' import type Stripe from 'stripe'