-
Notifications
You must be signed in to change notification settings - Fork 155
Feat/sponsor #239
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Feat/sponsor #239
Conversation
…d renderer and styling.
|
@huamanraj is attempting to deploy a commit to the AJEET PRATAP SINGH's projects Team on Vercel. A member of the Team first needs to authorize it. |
WalkthroughAdds a Sponsor system: new Prisma Sponsor model and User relation, Cloudinary image uploads and upload endpoint, Razorpay order/subscription/payment flows with webhook handling, a TRPC sponsor router, and frontend sponsor pages/components for purchase, asset submission, and display. Changes
Sequence Diagram(s)sequenceDiagram
participant User as User (Browser)
participant Frontend as Frontend (Next.js)
participant Backend as Backend (TRPC/Express)
participant Razorpay as Razorpay
participant Cloudinary as Cloudinary
participant DB as Database (Prisma)
rect rgb(200,220,255)
note over User,Frontend: Purchase flow
User->>Frontend: Click "Become a Sponsor"
Frontend->>Backend: trpc.createSubscription()
Backend->>Razorpay: Create order/subscription
Razorpay-->>Backend: Order/Subscription details
Backend-->>Frontend: orderId, amount, currency, key
Frontend->>Razorpay: Open checkout & complete payment
Razorpay->>Backend: Webhook (payment.captured)
Backend->>DB: Upsert Payment
Backend->>DB: Create Sponsor (plan_status=pending_submission)
end
rect rgb(220,255,220)
note over User,Cloudinary: Asset submission
Frontend->>User: Redirect to /sponsor/submit?paymentId=...
User->>Frontend: Upload image + submit form
Frontend->>Backend: trpc.uploadImage(base64)
Backend->>Cloudinary: Upload image
Cloudinary-->>Backend: Image URL
Backend-->>Frontend: { url }
Frontend->>Backend: trpc.submitAssets(..., imageUrl, paymentId)
Backend->>DB: Update Sponsor (details + plan_status=active)
Backend-->>Frontend: Success
end
rect rgb(255,240,200)
note over Razorpay,Backend: Subscription lifecycle
Razorpay->>Backend: Webhook (subscription.charged / cancelled / pending / failed)
Backend->>DB: Update Sponsor.plan_status by razorpay_sub_id
DB-->>Backend: Acknowledged
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Note
Due to the large number of review comments, Critical severity comments were prioritized as inline comments.
🟠 Major comments (29)
apps/web/src/app/(main)/sponsor/layout.tsx-1-2 (1)
1-2: Fix import order to follow coding guidelines.Imports should be ordered: React → third-party → local components → utils → types.
As per coding guidelines.
Apply this diff to fix the import order:
-import Navbar from "@/components/landing-sections/navbar"; import React from "react"; +import Navbar from "@/components/landing-sections/navbar";apps/api/prisma/schema.prisma-106-116 (1)
106-116: Fix naming convention inconsistency.The Sponsor model uses
snake_casefor field names (company_name,image_url,razorpay_payment_id, etc.) while all other models in the schema usecamelCase(firstName,createdAt,razorpayPaymentId, etc.). Maintain consistent naming conventions across the schema.Apply this diff:
model Sponsor { id String @id @default(cuid()) - company_name String + companyName String description String website String - image_url String - razorpay_payment_id String? - razorpay_sub_id String? - plan_status String // active, cancelled, pending_payment, pending_submission, failed - created_at DateTime @default(now()) + imageUrl String + razorpayPaymentId String? + razorpaySubId String? + planStatus String // active, cancelled, pending_payment, pending_submission, failed + createdAt DateTime @default(now()) }apps/web/src/components/dashboard/DashboardSponsorList.tsx-26-26 (1)
26-26: Replace hardcoded color with design token.Use semantic color names from the design token system instead of hardcoded values like
text-white.As per coding guidelines.
Apply this diff:
- <h2 className="text-xl font-semibold text-white">Featured Sponsors</h2> + <h2 className="text-xl font-semibold text-text-primary">Featured Sponsors</h2>apps/web/src/components/dashboard/DashboardSponsorReminder.tsx-18-37 (1)
18-37: Replace hardcoded colors with design system tokens.Multiple hardcoded color values (
yellow-500,yellow-400,neutral-400,text-white,text-black) violate the design system guidelines. Use semantic color names from the design token system for warnings and alerts.As per coding guidelines.
Consider using semantic warning/alert colors from the design system. For example:
- <div className="w-full mb-6 bg-yellow-500/10 border border-yellow-500/20 rounded-xl p-4 flex items-center justify-between"> + <div className="w-full mb-6 bg-warning-surface border border-warning-border rounded-xl p-4 flex items-center justify-between"> <div className="flex items-center gap-3"> - <div className="p-2 bg-yellow-500/20 rounded-lg"> - <AlertTriangle className="w-5 h-5 text-yellow-500" /> + <div className="p-2 bg-warning-surface-hover rounded-lg"> + <AlertTriangle className="w-5 h-5 text-warning-text" /> </div> <div> - <h3 className="text-white font-medium">Complete your sponsorship</h3> - <p className="text-neutral-400 text-sm"> + <h3 className="text-text-primary font-medium">Complete your sponsorship</h3> + <p className="text-text-secondary text-sm"> You have a pending sponsorship payment. Upload your assets to go live. </p> </div> </div> <Link href={`/sponsor/submit?paymentId=${pendingSponsorship.paymentId}`} - className="px-4 py-2 bg-yellow-500 text-black font-medium rounded-lg text-sm hover:bg-yellow-400 transition-colors" + className="px-4 py-2 bg-warning-accent text-warning-accent-text font-medium rounded-lg text-sm hover:bg-warning-accent-hover transition-colors" > Complete Setup </Link>Note: Verify the exact warning/alert color tokens available in your design system at
apps/web/src/lib/design-tokens.ts.Committable suggestion skipped: line range outside the PR's diff.
apps/web/src/components/dashboard/DashboardSponsorList.tsx-29-29 (1)
29-29: Replace hardcoded green colors with design system colors.Use semantic color names from the design token system instead of hardcoded values like
text-green-400andtext-green-300. Consider usingtext-brand-purpleor another semantic color from the design system.As per coding guidelines.
Apply this diff:
- className="text-sm text-green-400 hover:text-green-300" + className="text-sm text-brand-purple hover:text-brand-purple/80"apps/web/src/components/dashboard/DashboardSponsorReminder.tsx-9-11 (1)
9-11: Removeanytype assertion for type safety.The type assertion
(as any)bypasses TypeScript's type checking. The TRPC query should be properly typed.As per coding guidelines.
Apply this diff:
- const { data: pendingSponsorship, isLoading } = ( - trpc.sponsor.getPendingSponsorship as any - ).useQuery(); + const { data: pendingSponsorship, isLoading } = + trpc.sponsor.getPendingSponsorship.useQuery();apps/web/src/components/dashboard/DashboardSponsorList.tsx-42-53 (1)
42-53: Replace hardcoded neutral colors with design system tokens.Multiple hardcoded color values (
border-neutral-800,bg-neutral-900/20,bg-neutral-800,text-neutral-500,text-neutral-400) violate the design system guidelines. Use semantic color names from the design token system.As per coding guidelines.
Apply this diff:
<Link href="/sponsor" className="group block h-full"> - <div className="aspect-[16/10] w-full h-full rounded-2xl border border-dashed border-neutral-800 bg-neutral-900/20 hover:bg-neutral-900/40 hover:border-neutral-700 transition-all duration-300 flex flex-col items-center justify-center gap-3 p-6"> - <div className="w-12 h-12 rounded-full bg-neutral-800 flex items-center justify-center group-hover:scale-110 transition-transform duration-300"> - <span className="text-xl text-neutral-500">+</span> + <div className="aspect-[16/10] w-full h-full rounded-2xl border border-dashed border-dash-border bg-surface-secondary/20 hover:bg-surface-secondary/40 hover:border-dash-border/70 transition-all duration-300 flex flex-col items-center justify-center gap-3 p-6"> + <div className="w-12 h-12 rounded-full bg-surface-secondary flex items-center justify-center group-hover:scale-110 transition-transform duration-300"> + <span className="text-xl text-text-muted">+</span> </div> <div className="text-center"> - <h3 className="text-neutral-400 font-medium text-sm group-hover:text-white transition-colors"> + <h3 className="text-text-muted font-medium text-sm group-hover:text-text-primary transition-colors"> Your Ad Here </h3> </div>apps/api/src/routers/sponsor.ts-30-43 (1)
30-43: Persist order information to database.The created Razorpay order is not saved to the database, which could make it difficult to track payment flow or debug issues.
Consider saving the order to a database table before returning it to the client:
const order = await paymentService.createOrder({...}); if ("error" in order) { throw new Error(order.error.description); } // Save order to DB await prisma.order.create({ data: { razorpay_order_id: order.id, user_id: user.id, amount: order.amount, currency: order.currency, status: 'created', }, }); return {...};apps/web/src/components/sponsor/SponsorForm.tsx-55-82 (1)
55-82: Remove extensive TODO/implementation comments.These comments indicate uncertainty and incomplete implementation, making the code harder to maintain.
Remove or consolidate the speculative comments. If the upload implementation is working as intended, clean up the commentary. If issues remain, create a GitHub issue to track them.
apps/web/src/app/(main)/sponsor/page.tsx-28-29 (1)
28-29: Replace alert() with proper toast notifications.Using
alert()provides poor user experience and blocks the UI.Consider using a toast notification library or custom toast component for better UX.
onFailure: (error) => { console.error("Payment failed:", error); - alert("Payment failed: " + error.message); + // TODO: Show toast notification instead setLoading(false); },onError: (error: any) => { console.error("Subscription creation failed:", error); - alert("Failed to initiate payment. Please try again."); + // TODO: Show toast notification instead setLoading(false); },Also applies to: 59-60
apps/api/src/webhooks.ts-66-94 (1)
66-94: Replaceanytypes with proper TypeScript interfaces.Using
anyfor payload types bypasses type safety.As per coding guidelines, avoid
anytype; use proper interfaces for Razorpay webhook payloads.Define interfaces:
interface RazorpayPaymentEntity { id: string; amount: number; currency: string; description?: string; // add other fields as needed } interface RazorpaySubscriptionEntity { id: string; status: string; // add other fields as needed } interface RazorpayWebhookPayload { payment?: { entity: RazorpayPaymentEntity }; subscription?: { entity: RazorpaySubscriptionEntity }; } async function handleSubscriptionCharged(payload: RazorpayWebhookPayload) { // implementation }apps/api/src/routers/sponsor.ts-16-16 (1)
16-16: Replaceanytypes with proper TypeScript types.Multiple instances of
anytype bypass TypeScript's type safety.As per coding guidelines, avoid
anytype. Define proper interfaces for ctx and input parameters.Example for
createSubscription:interface CreateSubscriptionInput { planId: string; } interface ProtectedContext { user: { id: string; email: string; // other user fields }; } .mutation(async ({ ctx, input }: { ctx: ProtectedContext, input: CreateSubscriptionInput }) => {Apply similar typing for all procedures.
Also applies to: 40-40, 58-58, 65-65, 111-111
apps/web/src/components/sponsor/SponsorForm.tsx-109-112 (1)
109-112: Replace alert() with proper form validation feedback.Using
alert()provides poor UX.Use form error state instead:
const onSubmit = (values: z.infer<typeof formSchema>) => { if (!imageUrl) { - alert("Please upload an image"); + form.setError("root", { + type: "manual", + message: "Please upload a company logo", + }); return; }Then display the error in the JSX:
{form.formState.errors.root && ( <p className="text-xs text-red-500 mt-1"> {form.formState.errors.root.message} </p> )}apps/web/src/components/landing-sections/SponsorSection.tsx-22-22 (1)
22-22: Replace hardcoded hex values with design system tokens.The code uses hardcoded hex values
#252525and#0A0A0Adirectly, which violates the design system guidelines.As per coding guidelines, always use Tailwind classes from the design token system instead of hardcoded hex values. Replace with semantic color names like
border-neutral-800andbg-surface-primary.Apply this diff:
- <section className="w-full py-20 px-4 md:px-8 border-b border-[#252525] bg-[#0A0A0A]"> + <section className="w-full py-20 px-4 md:px-8 border-b border-neutral-800 bg-neutral-950">apps/web/src/components/sponsor/SponsorForm.tsx-101-102 (1)
101-102: Provide user feedback for upload errors.Upload errors are only logged to console without user notification.
Show user-friendly error messages:
} catch (error) { console.error("Upload failed", error); + form.setError("root", { + type: "manual", + message: "Failed to upload image. Please try again.", + }); } finally {apps/web/src/components/sponsor/SponsorForm.tsx-52-52 (1)
52-52: Use environment variable for upload preset.Hardcoding the upload preset is a security risk and lacks flexibility.
- formData.append("upload_preset", "opensox_sponsor"); // Make sure this preset exists or use signed upload + const uploadPreset = process.env.NEXT_PUBLIC_CLOUDINARY_UPLOAD_PRESET; + if (!uploadPreset) { + throw new Error("Cloudinary upload preset not configured"); + } + formData.append("upload_preset", uploadPreset);Note: The preset is already used on line 85, so remove the hardcoded one on line 52.
apps/web/src/app/(main)/sponsor/page.tsx-76-348 (1)
76-348: Multiple hardcoded hex values violate design system.The component contains numerous hardcoded hex colors throughout (e.g.,
#0A0A0A,#252525,#555).As per coding guidelines, all colors should use Tailwind classes from the design token system. Review lines 121, 165, 171, 207, 220, 233, 246, 296 and replace all hex values with appropriate design tokens like
bg-neutral-950,border-neutral-800, etc.apps/api/src/routers/sponsor.ts-65-108 (1)
65-108: Use database transaction for atomic operations.The
submitAssetsprocedure performs multiple database operations (read, upsert) without transaction guarantees, risking data inconsistency.Wrap the database operations in a transaction:
.mutation(async ({ ctx, input }: { ctx: any, input: any }) => { return await prisma.$transaction(async (tx) => { // Verify payment const payment = await tx.payment.findUnique({ where: { razorpayPaymentId: input.razorpayPaymentId }, }); if (!payment || payment.status !== "captured") { throw new Error("Valid payment not found"); } if (payment.userId !== ctx.user.id) { throw new Error("Unauthorized"); } // Upsert sponsor const existingSponsor = await tx.sponsor.findFirst({ where: { razorpay_payment_id: input.razorpayPaymentId }, }); if (existingSponsor) { return await tx.sponsor.update({...}); } else { return await tx.sponsor.create({...}); } }); }),apps/api/src/webhooks.ts-60-62 (1)
60-62: Add structured error logging with context.The error logging lacks context like endpoint, timestamp, and event type.
As per coding guidelines for API code, log errors with context (userId, endpoint, timestamp) for debugging.
Apply this diff:
} catch (error: any) { - console.error("Webhook error:", error); + console.error("Webhook processing failed:", { + error: error.message, + endpoint: "/api/razorpay/webhook", + timestamp: new Date().toISOString(), + eventType: req.body?.event + }); return res.status(500).json({ error: "Internal server error" }); }apps/web/src/app/(main)/sponsor/submit/page.tsx-15-18 (1)
15-18: Remove commented-out code.The redirect logic is commented out. Either implement it or remove it to keep the code clean.
As per coding guidelines, remove unused code.
Apply this diff:
useEffect(() => { setMounted(true); - if (!paymentId) { - // If no payment ID, redirect back to sponsor page - // router.push("/sponsor"); - } }, [paymentId, router]);apps/api/src/routers/sponsor.ts-111-138 (1)
111-138: Optimize database queries to avoid N+1 problem.The nested loop performs a database query for each payment, which is inefficient.
Refactor to fetch all relevant data in a single query:
getPendingSponsorship: protectedProcedure.query(async ({ ctx }: { ctx: any }) => { const pendingPayment = await prisma.payment.findFirst({ where: { userId: ctx.user.id, status: "captured", subscriptionId: { not: null }, sponsor: null, // assumes relation exists }, orderBy: { createdAt: "desc" }, include: { sponsor: true, }, }); if (pendingPayment && !pendingPayment.sponsor) { return { paymentId: pendingPayment.razorpayPaymentId, amount: pendingPayment.amount, date: pendingPayment.createdAt, }; } return null; }),Note: This assumes a relation between Payment and Sponsor models.
apps/web/src/components/landing-sections/SponsorSection.tsx-44-58 (1)
44-58: Add aria-label to the sponsor Link for accessibility.The Link element lacks an aria-label, which is important for screen readers.
As per coding guidelines, include proper aria labels for accessibility.
Apply this diff:
- {(!hasSponsors || sponsors.length < 3) && ( - <Link href="/sponsor" className="group block h-full"> + {(!hasSponsors || sponsors.length < 3) && ( + <Link + href="/sponsor" + className="group block h-full" + aria-label="Become a sponsor of OpenSox" + >Committable suggestion skipped: line range outside the PR's diff.
apps/web/src/app/(main)/sponsor/page.tsx-52-52 (1)
52-52: Replace hardcoded hex value with design system token.As per coding guidelines, never use hardcoded hex values directly.
theme: { - color: "#4dd0a4", + color: "rgb(77, 208, 164)", // reference from design tokens },Note: Razorpay requires hex/rgb format, so you may need to extract the actual color value from your design tokens.
Committable suggestion skipped: line range outside the PR's diff.
apps/web/src/app/(main)/(landing)/page.tsx-17-19 (1)
17-19: Replace hardcoded hex values with design system tokens.The code uses hardcoded hex values
#101010and#252525, which violates the design system guidelines.As per coding guidelines, always use Tailwind classes from the design token system.
Apply this diff:
- <main className="min-h-screen w-full bg-[#101010] text-white font-sans overflow-hidden relative"> + <main className="min-h-screen w-full bg-neutral-950 text-white font-sans overflow-hidden relative"> <Navbar /> - <div className="min-h-screen w-full max-w-[2000px] mx-auto border-x border-[#252525] overflow-hidden"> + <div className="min-h-screen w-full max-w-[2000px] mx-auto border-x border-neutral-800 overflow-hidden">apps/web/src/components/sponsor/SponsorForm.tsx-29-29 (1)
29-29: Remove unsafeas anytype cast.As per coding guidelines, avoid
anytype.- const submitAssetsMutation = (trpc.sponsor.submitAssets as any).useMutation({ + const submitAssetsMutation = trpc.sponsor.submitAssets.useMutation({apps/web/src/app/(main)/sponsor/submit/page.tsx-32-32 (1)
32-32: Replace hardcoded hex value with design system token.The code uses
#4dd0a4directly, which violates the design system guidelines.As per coding guidelines, use Tailwind classes from the design token system.
Apply this diff:
- className="bg-[#4dd0a4] text-black font-bold py-2 px-6 rounded-lg" + className="bg-brand-green text-black font-bold py-2 px-6 rounded-lg"apps/web/src/components/sponsor/SponsorForm.tsx-209-210 (1)
209-210: Replace hardcoded hex values with design system tokens.As per coding guidelines, use Tailwind classes from the design token system.
- className="w-full bg-[#4dd0a4] text-black font-bold py-3 rounded-xl hover:bg-[#3db08a] transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center" + className="w-full bg-brand-green text-black font-bold py-3 rounded-xl hover:bg-brand-green-dark transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center"apps/web/src/components/sponsor/SponsorForm.tsx-162-166 (1)
162-166: Add aria-label to input fields.Form inputs lack proper accessibility labels.
As per coding guidelines, include proper aria labels for accessibility. While you have visual
<label>elements, ensure they're properly associated:<input + id="companyName" {...form.register("companyName")} className="w-full bg-neutral-800 border border-neutral-700 rounded-lg px-4 py-2 text-white focus:ring-2 focus:ring-green-500 outline-none" placeholder="Acme Corp" + aria-describedby="companyName-error" />And update the label:
- <label className="block text-sm font-medium text-neutral-400 mb-2"> + <label htmlFor="companyName" className="block text-sm font-medium text-neutral-400 mb-2"> Company Name </label>Apply similar changes to other input fields.
Committable suggestion skipped: line range outside the PR's diff.
apps/web/src/app/(main)/sponsor/page.tsx-37-39 (1)
37-39: Remove unsafeas anytype cast.Using
as anybypasses TypeScript's type safety and should be avoided.As per coding guidelines, avoid
anytype. Use proper TypeScript types.Apply this diff:
- const createSubscriptionMutation = ( - trpc.sponsor.createSubscription as any - ).useMutation({ + const createSubscriptionMutation = trpc.sponsor.createSubscription.useMutation({
🟡 Minor comments (1)
apps/web/src/app/(main)/sponsor/page.tsx-28-29 (1)
28-29: Avoid exposing error details to users.Displaying raw error messages in alerts can expose sensitive implementation details.
Consider showing a generic user-friendly message instead of
error.message.- alert("Payment failed: " + error.message); + // Show generic message: "Payment failed. Please try again."Committable suggestion skipped: line range outside the PR's diff.
🧹 Nitpick comments (15)
apps/web/src/components/ui/custom-button.tsx (2)
3-5: Reorder imports to follow the project conventions.The imports should be organized in the order: React → third-party → local components → utils → types. Currently, the local utils import appears before the third-party import.
Apply this diff to fix the import order:
"use client"; -import { cn } from "@/lib/utils"; import { motion } from "framer-motion"; import type React from "react"; +import { cn } from "@/lib/utils";As per coding guidelines, imports should follow the order: React → third-party → local components → utils → types.
7-19: Define a separate type for component props.The props should be defined as a separate type or interface rather than inline with the destructuring. This improves maintainability and follows the project's TypeScript conventions.
Apply this diff to extract the props type:
+type PrimaryButtonProps = { + children: React.ReactNode; + animate?: boolean; + classname?: string; + onClick?: () => void; + disabled?: boolean; +}; + -const PrimaryButton = ({ - children, - animate = true, - classname, - onClick, - disabled, -}: { - children: React.ReactNode; - animate?: boolean; - classname?: string; - onClick?: () => void; - disabled?: boolean; -}) => { +const PrimaryButton = ({ + children, + animate = true, + classname, + onClick, + disabled, +}: PrimaryButtonProps) => {As per coding guidelines, const functions should have defined types.
apps/web/src/components/ui/accordion.tsx (1)
23-41: align header text color with design tokens instead oftext-white
accordionprimitive.headernow usesclassName="flex text-white". design rules prefer semantic, design-token-based color classes (for exampletext-text-primaryor other tokenized variants) instead of raw tailwind palette names liketext-white. please consider switching this to the appropriate semantic text token (or reverting to the project’s token you were using before, if that was intentional) so the accordion trigger header stays aligned with the design system.apps/api/prisma/schema.prisma (2)
114-114: Consider using an enum for type-safe plan status.The
planStatusfield uses a String type with a comment listing possible values. Consider defining aSponsorStatusenum similar toPaymentStatusandSubscriptionStatusfor better type safety and validation at the database level.Add an enum definition:
+enum SponsorStatus { + active + cancelled + pending_payment + pending_submission + failed +} + model Sponsor { id String @id @default(cuid()) companyName String description String website String imageUrl String razorpayPaymentId String? razorpaySubId String? - planStatus String // active, cancelled, pending_payment, pending_submission, failed + planStatus SponsorStatus createdAt DateTime @default(now()) }
112-113: Consider adding indexes for frequently queried fields.If
razorpayPaymentIdandrazorpaySubIdare frequently used in queries (as suggested by the sponsor router code), consider adding indexes to improve query performance.model Sponsor { id String @id @default(cuid()) companyName String description String website String imageUrl String razorpayPaymentId String? @unique razorpaySubId String? planStatus SponsorStatus createdAt DateTime @default(now()) + + @@index([razorpayPaymentId]) + @@index([razorpaySubId]) }apps/web/src/components/landing-sections/SponsorSection.tsx (3)
8-10: Define return type for the component function.The component is defined as an arrow function without an explicit return type.
As per coding guidelines, define a type when defining const functions for better type safety.
Apply this diff:
-const SponsorSection = () => { +const SponsorSection: React.FC = () => {
12-14: Add loading skeleton instead of returning null.Returning
nullduring loading creates a layout shift and poor UX. Consider showing a skeleton placeholder.if (isLoading) { - return null; // Or a skeleton + return ( + <section className="w-full py-20 px-4 md:px-8 border-b border-neutral-800 bg-neutral-950"> + <div className="max-w-7xl mx-auto"> + <div className="text-center mb-12"> + <div className="h-10 bg-neutral-800 rounded w-48 mx-auto mb-4 animate-pulse" /> + <div className="h-6 bg-neutral-800 rounded w-64 mx-auto animate-pulse" /> + </div> + <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"> + {[1, 2, 3].map((i) => ( + <div key={i} className="aspect-[16/10] bg-neutral-800 rounded-2xl animate-pulse" /> + ))} + </div> + </div> + </section> + ); }
9-10: Add error handling for the TRPC query.The query lacks error handling, which could result in undefined behavior if the request fails.
const { data: sponsors, isLoading } = trpc.sponsor.getActiveSponsors.useQuery(); + + // handle error state + if (!isLoading && !sponsors) { + return null; + }apps/web/src/app/(main)/sponsor/submit/page.tsx (1)
7-7: Define return type for the component function.As per coding guidelines, define a type when defining const functions.
-const SponsorSubmitPage = () => { +const SponsorSubmitPage: React.FC = () => {apps/web/src/app/(main)/(landing)/page.tsx (1)
15-15: Define return type for the component function.As per coding guidelines, define a type when defining const functions.
-const Landing = () => { +const Landing: React.FC = () => {apps/web/src/app/(main)/sponsor/page.tsx (1)
18-18: Define return type for the component function.As per coding guidelines, define a type when defining const functions.
-const SponsorPage = () => { +const SponsorPage: React.FC = () => {apps/web/src/components/sponsor/SponsorCard.tsx (1)
19-24: Consider adding aria-label for better accessibility.While the Link has proper
relattributes, an explicit aria-label would improve screen reader experience.As per coding guidelines, include proper aria labels for accessibility.
<Link href={sponsor.website} target="_blank" rel="noopener noreferrer" className="group block" + aria-label={`Visit ${sponsor.company_name} website`} >apps/api/src/webhooks.ts (2)
86-93: Validate database operation success.The
updateManyoperation doesn't check if any records were actually updated, which could indicate a data inconsistency.- await prisma.sponsor.updateMany({ + const result = await prisma.sponsor.updateMany({ where: { razorpay_sub_id: subId, }, data: { plan_status: "active", }, }); + + if (result.count === 0) { + console.warn(`No sponsor found for subscription ${subId}`); + }
77-84: Clarify or remove uncertain implementation comments.The lengthy comments express uncertainty about the data flow and implementation approach.
These comments suggest the implementation logic may need review. Either clarify the flow or remove speculative comments to improve code readability.
apps/api/src/routers/sponsor.ts (1)
26-28: Add better error message for missing plan.The generic error doesn't help with debugging.
if (!plan) { - throw new Error("Plan not found"); + throw new Error(`Plan with ID '${input.planId}' not found`); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (18)
apps/api/prisma/schema.prisma(1 hunks)apps/api/src/index.ts(1 hunks)apps/api/src/routers/_app.ts(1 hunks)apps/api/src/routers/sponsor.ts(1 hunks)apps/api/src/webhooks.ts(1 hunks)apps/web/package.json(3 hunks)apps/web/src/app/(main)/(landing)/page.tsx(1 hunks)apps/web/src/app/(main)/sponsor/layout.tsx(1 hunks)apps/web/src/app/(main)/sponsor/page.tsx(1 hunks)apps/web/src/app/(main)/sponsor/submit/page.tsx(1 hunks)apps/web/src/components/dashboard/DashboardContainer.tsx(1 hunks)apps/web/src/components/dashboard/DashboardSponsorList.tsx(1 hunks)apps/web/src/components/dashboard/DashboardSponsorReminder.tsx(1 hunks)apps/web/src/components/landing-sections/SponsorSection.tsx(1 hunks)apps/web/src/components/sponsor/SponsorCard.tsx(1 hunks)apps/web/src/components/sponsor/SponsorForm.tsx(1 hunks)apps/web/src/components/ui/accordion.tsx(4 hunks)apps/web/src/components/ui/custom-button.tsx(1 hunks)
🧰 Additional context used
📓 Path-based instructions (14)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx,js,jsx}: Always use lowercase when writing comments
Avoid unnecessary comments; code should be self-documenting when possible
Use comments to explain 'why', not 'what'
Remove unused imports
Use UPPER_SNAKE_CASE for constants
Use camelCase for functions and variables
Files:
apps/web/src/components/dashboard/DashboardSponsorReminder.tsxapps/api/src/webhooks.tsapps/web/src/app/(main)/sponsor/submit/page.tsxapps/web/src/components/sponsor/SponsorCard.tsxapps/web/src/components/landing-sections/SponsorSection.tsxapps/web/src/app/(main)/sponsor/layout.tsxapps/web/src/components/sponsor/SponsorForm.tsxapps/web/src/components/ui/custom-button.tsxapps/web/src/components/ui/accordion.tsxapps/api/src/index.tsapps/web/src/components/dashboard/DashboardContainer.tsxapps/api/src/routers/sponsor.tsapps/web/src/app/(main)/sponsor/page.tsxapps/web/src/components/dashboard/DashboardSponsorList.tsxapps/api/src/routers/_app.tsapps/web/src/app/(main)/(landing)/page.tsx
apps/web/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
apps/web/src/**/*.{ts,tsx}: Always follow the design system defined inapps/web/src/lib/design-tokens.tsandapps/web/tailwind.config.ts
NEVER use hardcoded hex values (e.g.,#5519f7) directly in components; ALWAYS reference colors from the design token system using Tailwind classes
Use semantic color names that describe purpose, not appearance
Usefont-sansfor standard UI text (Geist Sans) andfont-monofor code, technical content, or monospace needs (DM Mono)
Follow Tailwind's spacing scale (0.25rem increments); for section padding use mobilep-4(1rem) and desktopp-[60px]
Use appropriate border radius: small elementsrounded-lg, mediumrounded-xl, largerounded-2xl, buttonsrounded-[16px]
Use animation durations: fastduration-100(0.1s), normalduration-300(0.3s), slowduration-600(0.6s)
Files:
apps/web/src/components/dashboard/DashboardSponsorReminder.tsxapps/web/src/app/(main)/sponsor/submit/page.tsxapps/web/src/components/sponsor/SponsorCard.tsxapps/web/src/components/landing-sections/SponsorSection.tsxapps/web/src/app/(main)/sponsor/layout.tsxapps/web/src/components/sponsor/SponsorForm.tsxapps/web/src/components/ui/custom-button.tsxapps/web/src/components/ui/accordion.tsxapps/web/src/components/dashboard/DashboardContainer.tsxapps/web/src/app/(main)/sponsor/page.tsxapps/web/src/components/dashboard/DashboardSponsorList.tsxapps/web/src/app/(main)/(landing)/page.tsx
**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{tsx,ts}: Prefer functional components with TypeScript and use proper TypeScript types, avoidany
Extract reusable logic into custom hooks
Use descriptive prop names and define prop types using TypeScript interfaces or types
Prefer controlled components over uncontrolled
Use zustand for global state (located insrc/store/)
Use absolute imports from@/prefix when available
Include proper aria labels for accessibility
Ensure keyboard navigation works
Maintain proper heading hierarchy
Provide alt text for images
Avoid unnecessary re-renders
Files:
apps/web/src/components/dashboard/DashboardSponsorReminder.tsxapps/api/src/webhooks.tsapps/web/src/app/(main)/sponsor/submit/page.tsxapps/web/src/components/sponsor/SponsorCard.tsxapps/web/src/components/landing-sections/SponsorSection.tsxapps/web/src/app/(main)/sponsor/layout.tsxapps/web/src/components/sponsor/SponsorForm.tsxapps/web/src/components/ui/custom-button.tsxapps/web/src/components/ui/accordion.tsxapps/api/src/index.tsapps/web/src/components/dashboard/DashboardContainer.tsxapps/api/src/routers/sponsor.tsapps/web/src/app/(main)/sponsor/page.tsxapps/web/src/components/dashboard/DashboardSponsorList.tsxapps/api/src/routers/_app.tsapps/web/src/app/(main)/(landing)/page.tsx
**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (.cursorrules)
Organize imports: react → third-party → local components → utils → types
Files:
apps/web/src/components/dashboard/DashboardSponsorReminder.tsxapps/api/src/webhooks.tsapps/web/src/app/(main)/sponsor/submit/page.tsxapps/web/src/components/sponsor/SponsorCard.tsxapps/web/src/components/landing-sections/SponsorSection.tsxapps/web/src/app/(main)/sponsor/layout.tsxapps/web/src/components/sponsor/SponsorForm.tsxapps/web/src/components/ui/custom-button.tsxapps/web/src/components/ui/accordion.tsxapps/api/src/index.tsapps/web/src/components/dashboard/DashboardContainer.tsxapps/api/src/routers/sponsor.tsapps/web/src/app/(main)/sponsor/page.tsxapps/web/src/components/dashboard/DashboardSponsorList.tsxapps/api/src/routers/_app.tsapps/web/src/app/(main)/(landing)/page.tsx
**/*[A-Z]*.{tsx,ts}
📄 CodeRabbit inference engine (.cursorrules)
Use PascalCase for component file names (e.g.,
UserProfile.tsx)
Files:
apps/web/src/components/dashboard/DashboardSponsorReminder.tsxapps/web/src/components/sponsor/SponsorCard.tsxapps/web/src/components/landing-sections/SponsorSection.tsxapps/web/src/components/sponsor/SponsorForm.tsxapps/web/src/components/dashboard/DashboardContainer.tsxapps/web/src/components/dashboard/DashboardSponsorList.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx}: Use PascalCase for types and interfaces with descriptive names
Use dynamic imports for code splitting when appropriate
Memoize expensive computations
Files:
apps/web/src/components/dashboard/DashboardSponsorReminder.tsxapps/api/src/webhooks.tsapps/web/src/app/(main)/sponsor/submit/page.tsxapps/web/src/components/sponsor/SponsorCard.tsxapps/web/src/components/landing-sections/SponsorSection.tsxapps/web/src/app/(main)/sponsor/layout.tsxapps/web/src/components/sponsor/SponsorForm.tsxapps/web/src/components/ui/custom-button.tsxapps/web/src/components/ui/accordion.tsxapps/api/src/index.tsapps/web/src/components/dashboard/DashboardContainer.tsxapps/api/src/routers/sponsor.tsapps/web/src/app/(main)/sponsor/page.tsxapps/web/src/components/dashboard/DashboardSponsorList.tsxapps/api/src/routers/_app.tsapps/web/src/app/(main)/(landing)/page.tsx
apps/web/src/**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursorrules)
Optimize images using next/image
apps/web/src/**/*.{tsx,ts}: Use Zustand for global state, located insrc/store/
Use PascalCase for types and interfaces with descriptive names
Use dynamic imports for code splitting when appropriate
Optimize images using next/image
Memoize expensive computations
Define a type when defining const functions
Files:
apps/web/src/components/dashboard/DashboardSponsorReminder.tsxapps/web/src/app/(main)/sponsor/submit/page.tsxapps/web/src/components/sponsor/SponsorCard.tsxapps/web/src/components/landing-sections/SponsorSection.tsxapps/web/src/app/(main)/sponsor/layout.tsxapps/web/src/components/sponsor/SponsorForm.tsxapps/web/src/components/ui/custom-button.tsxapps/web/src/components/ui/accordion.tsxapps/web/src/components/dashboard/DashboardContainer.tsxapps/web/src/app/(main)/sponsor/page.tsxapps/web/src/components/dashboard/DashboardSponsorList.tsxapps/web/src/app/(main)/(landing)/page.tsx
**/*.{js,jsx,ts,tsx,py,java,go,rb,php}
📄 CodeRabbit inference engine (.cursor/rules/general_rules.mdc)
**/*.{js,jsx,ts,tsx,py,java,go,rb,php}: Always use lowercase when writing comments
Avoid unnecessary comments; code should be self-documenting when possible
Use comments to explain 'why', not 'what'
Files:
apps/web/src/components/dashboard/DashboardSponsorReminder.tsxapps/api/src/webhooks.tsapps/web/src/app/(main)/sponsor/submit/page.tsxapps/web/src/components/sponsor/SponsorCard.tsxapps/web/src/components/landing-sections/SponsorSection.tsxapps/web/src/app/(main)/sponsor/layout.tsxapps/web/src/components/sponsor/SponsorForm.tsxapps/web/src/components/ui/custom-button.tsxapps/web/src/components/ui/accordion.tsxapps/api/src/index.tsapps/web/src/components/dashboard/DashboardContainer.tsxapps/api/src/routers/sponsor.tsapps/web/src/app/(main)/sponsor/page.tsxapps/web/src/components/dashboard/DashboardSponsorList.tsxapps/api/src/routers/_app.tsapps/web/src/app/(main)/(landing)/page.tsx
apps/web/src/components/**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (apps/web/.cursor/rules/frontend_rules.mdc)
apps/web/src/components/**/*.{tsx,ts,jsx,js}: Never use hardcoded hex values directly in components; always reference colors from the design token system using Tailwind classes
Use semantic color names from the design token system that describe purpose, not appearance (e.g., bg-brand-purple, bg-surface-primary, text-text-primary)
Use font-sans for standard UI text (Geist Sans) and font-mono for code, technical content, or monospace needs (DM Mono)
Follow Tailwind's spacing scale for section padding: p-4 (1rem) on mobile, p-[60px] on desktop
Use rounded-lg (0.5rem) for small elements, rounded-xl (1rem) for medium elements, rounded-2xl (1.5rem) for large elements, and rounded-[16px] for buttons
Use duration-100 (0.1s) for fast transitions, duration-300 (0.3s) for normal transitions, and duration-600 (0.6s) for slow transitions
Use available custom animations: animate-accordion-down, animate-accordion-up, animate-scrollRight, animate-scrollLeft, animate-customspin, animate-spin-slow, animate-spin-slow-reverse, animate-marquee, animate-marquee-vertical, animate-shine
Prefer functional components with TypeScript
Extract reusable logic into custom hooks
Prefer controlled components over uncontrolled
Include proper aria labels for accessibility
Ensure keyboard navigation works in interactive components
Maintain proper heading hierarchy in page components
Provide alt text for images
Use 'class:' instead of the ternary operator in class tags whenever possible
Implement accessibility features on interactive elements (e.g., tabindex='0', aria-label, onClick, onKeyDown)
Always follow the design system defined inapps/web/src/lib/design-tokens.tsandapps/web/tailwind.config.ts
Files:
apps/web/src/components/dashboard/DashboardSponsorReminder.tsxapps/web/src/components/sponsor/SponsorCard.tsxapps/web/src/components/landing-sections/SponsorSection.tsxapps/web/src/components/sponsor/SponsorForm.tsxapps/web/src/components/ui/custom-button.tsxapps/web/src/components/ui/accordion.tsxapps/web/src/components/dashboard/DashboardContainer.tsxapps/web/src/components/dashboard/DashboardSponsorList.tsx
apps/web/src/components/**/*.{tsx,ts}
📄 CodeRabbit inference engine (apps/web/.cursor/rules/frontend_rules.mdc)
apps/web/src/components/**/*.{tsx,ts}: Use proper TypeScript types and avoid usinganytype
Use descriptive prop names and define prop types using TypeScript interfaces or types
Name components using PascalCase (e.g., UserProfile.tsx)
Files:
apps/web/src/components/dashboard/DashboardSponsorReminder.tsxapps/web/src/components/sponsor/SponsorCard.tsxapps/web/src/components/landing-sections/SponsorSection.tsxapps/web/src/components/sponsor/SponsorForm.tsxapps/web/src/components/ui/custom-button.tsxapps/web/src/components/ui/accordion.tsxapps/web/src/components/dashboard/DashboardContainer.tsxapps/web/src/components/dashboard/DashboardSponsorList.tsx
apps/web/src/**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (apps/web/.cursor/rules/frontend_rules.mdc)
apps/web/src/**/*.{tsx,ts,jsx,js}: Organize imports in order: React → third-party → local components → utils → types
Use absolute imports from@/prefix when available
Remove unused imports
Use UPPER_SNAKE_CASE for constants
Use camelCase for functions and variables
Always use Tailwind classes for styling HTML elements; avoid using CSS or style tags
Use descriptive variable and function names; name event functions with a 'handle' prefix (e.g., handleClick, handleKeyDown)
Use const with arrow functions instead of function declarations (e.g., 'const toggle = () =>')
Files:
apps/web/src/components/dashboard/DashboardSponsorReminder.tsxapps/web/src/app/(main)/sponsor/submit/page.tsxapps/web/src/components/sponsor/SponsorCard.tsxapps/web/src/components/landing-sections/SponsorSection.tsxapps/web/src/app/(main)/sponsor/layout.tsxapps/web/src/components/sponsor/SponsorForm.tsxapps/web/src/components/ui/custom-button.tsxapps/web/src/components/ui/accordion.tsxapps/web/src/components/dashboard/DashboardContainer.tsxapps/web/src/app/(main)/sponsor/page.tsxapps/web/src/components/dashboard/DashboardSponsorList.tsxapps/web/src/app/(main)/(landing)/page.tsx
apps/api/src/**/*.{js,ts}
📄 CodeRabbit inference engine (apps/api/.cursor/rules/backend_rules.mdc)
apps/api/src/**/*.{js,ts}: Log errors with context (userId, endpoint, timestamp) for debugging
Always await async operations; never forget to handle promise rejections
Never log sensitive information (passwords, tokens, credit card numbers)
Files:
apps/api/src/webhooks.tsapps/api/src/index.tsapps/api/src/routers/sponsor.tsapps/api/src/routers/_app.ts
apps/api/src/**/*.ts
📄 CodeRabbit inference engine (apps/api/.cursor/rules/backend_rules.mdc)
Avoid
anytype; useunknownfor truly dynamic data and narrow with type guards
Files:
apps/api/src/webhooks.tsapps/api/src/index.tsapps/api/src/routers/sponsor.tsapps/api/src/routers/_app.ts
apps/api/src/{index,main,app,server}.{js,ts}
📄 CodeRabbit inference engine (apps/api/.cursor/rules/backend_rules.mdc)
Validate required environment variables on startup; fail fast if missing
Files:
apps/api/src/index.ts
🧠 Learnings (26)
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/components/**/*.{tsx,ts} : Use descriptive prop names and define prop types using TypeScript interfaces or types
Applied to files:
apps/web/src/components/sponsor/SponsorCard.tsxapps/web/src/components/landing-sections/SponsorSection.tsxapps/web/src/components/sponsor/SponsorForm.tsx
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/components/**/*.{tsx,ts,jsx,js} : Include proper aria labels for accessibility
Applied to files:
apps/web/src/components/sponsor/SponsorCard.tsxapps/web/src/components/sponsor/SponsorForm.tsxapps/web/src/components/ui/accordion.tsx
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/components/**/*.{tsx,ts,jsx,js} : Provide alt text for images
Applied to files:
apps/web/src/components/sponsor/SponsorCard.tsx
📚 Learning: 2025-11-25T07:34:30.473Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T07:34:30.473Z
Learning: Applies to apps/web/src/**/*.{tsx,ts} : Optimize images using next/image
Applied to files:
apps/web/src/components/sponsor/SponsorCard.tsx
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/components/**/*.{tsx,ts,jsx,js} : Maintain proper heading hierarchy in page components
Applied to files:
apps/web/src/components/landing-sections/SponsorSection.tsxapps/web/src/app/(main)/sponsor/layout.tsxapps/web/src/app/(main)/(landing)/page.tsx
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/components/**/*.{tsx,ts,jsx,js} : Prefer functional components with TypeScript
Applied to files:
apps/web/src/components/landing-sections/SponsorSection.tsx
📚 Learning: 2025-11-25T07:34:30.473Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T07:34:30.473Z
Learning: Applies to **/*[Cc]omponent.{tsx,ts} : Keep components focused and single-responsibility
Applied to files:
apps/web/src/components/landing-sections/SponsorSection.tsxapps/web/src/app/(main)/(landing)/page.tsx
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/**/*.{tsx,ts,jsx,js} : Organize imports in order: React → third-party → local components → utils → types
Applied to files:
apps/web/src/components/landing-sections/SponsorSection.tsxapps/web/src/app/(main)/sponsor/layout.tsxapps/web/src/components/ui/accordion.tsxapps/web/src/app/(main)/(landing)/page.tsxapps/web/package.json
📚 Learning: 2025-11-25T07:34:30.473Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T07:34:30.473Z
Learning: Applies to **/*.{tsx,ts} : Maintain proper heading hierarchy
Applied to files:
apps/web/src/app/(main)/sponsor/layout.tsxapps/web/src/components/ui/accordion.tsxapps/web/src/app/(main)/(landing)/page.tsx
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/components/**/*.{tsx,ts,jsx,js} : Always follow the design system defined in `apps/web/src/lib/design-tokens.ts` and `apps/web/tailwind.config.ts`
Applied to files:
apps/web/src/app/(main)/sponsor/layout.tsxapps/web/package.json
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/**/*.{tsx,ts,jsx,js} : Use absolute imports from `@/` prefix when available
Applied to files:
apps/web/src/app/(main)/sponsor/layout.tsx
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/components/**/*.{tsx,ts,jsx,js} : Use available custom animations: animate-accordion-down, animate-accordion-up, animate-scrollRight, animate-scrollLeft, animate-customspin, animate-spin-slow, animate-spin-slow-reverse, animate-marquee, animate-marquee-vertical, animate-shine
Applied to files:
apps/web/src/components/ui/custom-button.tsxapps/web/src/components/ui/accordion.tsx
📚 Learning: 2025-11-25T07:34:30.473Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T07:34:30.473Z
Learning: Applies to **/*.{tsx,ts} : Include proper aria labels for accessibility
Applied to files:
apps/web/src/components/ui/accordion.tsx
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/**/*.{tsx,ts,jsx,js} : Remove unused imports
Applied to files:
apps/web/src/components/ui/accordion.tsx
📚 Learning: 2025-11-25T07:34:30.473Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T07:34:30.473Z
Learning: Applies to apps/web/src/**/*.{ts,tsx} : Use semantic color names that describe purpose, not appearance
Applied to files:
apps/web/src/components/ui/accordion.tsx
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/components/**/*.{tsx,ts,jsx,js} : Implement accessibility features on interactive elements (e.g., tabindex='0', aria-label, onClick, onKeyDown)
Applied to files:
apps/web/src/components/ui/accordion.tsx
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/**/*.{tsx,ts} : Use PascalCase for types and interfaces with descriptive names
Applied to files:
apps/web/src/components/ui/accordion.tsx
📚 Learning: 2025-11-25T07:34:30.473Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T07:34:30.473Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : Organize imports: react → third-party → local components → utils → types
Applied to files:
apps/web/src/components/ui/accordion.tsxapps/web/src/app/(main)/(landing)/page.tsxapps/web/package.json
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{middleware,services,routes,controllers}/*.{js,ts} : Log all critical operations (auth attempts, payment processing, data mutations)
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{database,services}/*.{js,ts} : Handle database connection failures gracefully with retry logic
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{routes,middleware}/*.{js,ts} : Implement rate limiting on all public endpoints to prevent abuse
Applied to files:
apps/api/src/routers/_app.ts
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{routes,middleware}/*.{js,ts} : Use middleware for auth checks; never duplicate auth logic in route handlers
Applied to files:
apps/api/src/routers/_app.ts
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/components/**/*.{tsx,ts,jsx,js} : Extract reusable logic into custom hooks
Applied to files:
apps/web/src/app/(main)/(landing)/page.tsx
📚 Learning: 2025-11-25T07:34:30.473Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T07:34:30.473Z
Learning: Applies to apps/web/src/**/*.{ts,tsx} : Always follow the design system defined in `apps/web/src/lib/design-tokens.ts` and `apps/web/tailwind.config.ts`
Applied to files:
apps/web/package.json
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/**/*.{tsx,ts,jsx,js} : Always use Tailwind classes for styling HTML elements; avoid using CSS or style tags
Applied to files:
apps/web/package.json
📚 Learning: 2025-11-25T07:34:30.473Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T07:34:30.473Z
Learning: Applies to apps/web/src/**/*.{ts,tsx} : Follow Tailwind's spacing scale (0.25rem increments); for section padding use mobile `p-4` (1rem) and desktop `p-[60px]`
Applied to files:
apps/web/package.json
🧬 Code graph analysis (12)
apps/web/src/components/dashboard/DashboardSponsorReminder.tsx (1)
apps/web/src/lib/trpc.ts (1)
trpc(4-4)
apps/api/src/webhooks.ts (1)
apps/api/src/services/payment.service.ts (2)
verifyPaymentSignature(110-138)RazorpayError(33-43)
apps/web/src/app/(main)/sponsor/submit/page.tsx (1)
apps/web/src/components/sponsor/SponsorForm.tsx (1)
SponsorForm(22-220)
apps/web/src/components/landing-sections/SponsorSection.tsx (2)
apps/web/src/lib/trpc.ts (1)
trpc(4-4)apps/web/src/components/sponsor/SponsorCard.tsx (1)
SponsorCard(17-45)
apps/web/src/components/sponsor/SponsorForm.tsx (2)
apps/api/src/trpc.ts (1)
router(38-38)apps/web/src/lib/trpc.ts (1)
trpc(4-4)
apps/web/src/components/ui/custom-button.tsx (1)
apps/web/src/lib/utils.ts (1)
cn(4-6)
apps/api/src/index.ts (1)
apps/api/src/webhooks.ts (1)
handleRazorpayWebhook(7-64)
apps/web/src/components/dashboard/DashboardContainer.tsx (1)
apps/web/src/components/dashboard/ProjectsContainer.tsx (1)
ProjectsContainer(54-179)
apps/web/src/app/(main)/sponsor/page.tsx (2)
apps/web/src/hooks/useRazorpay.ts (1)
useRazorpay(18-80)apps/web/src/lib/trpc.ts (1)
trpc(4-4)
apps/web/src/components/dashboard/DashboardSponsorList.tsx (2)
apps/web/src/lib/trpc.ts (1)
trpc(4-4)apps/web/src/components/sponsor/SponsorCard.tsx (1)
SponsorCard(17-45)
apps/api/src/routers/_app.ts (2)
apps/api/src/trpc.ts (1)
router(38-38)apps/api/src/routers/sponsor.ts (1)
sponsorRouter(8-151)
apps/web/src/app/(main)/(landing)/page.tsx (2)
apps/web/src/components/landing-sections/how-it-works.tsx (1)
HowItWorks(33-66)apps/web/src/components/faq/FaqSection.tsx (1)
FaqSection(10-62)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 9
🧹 Nitpick comments (12)
apps/web/src/components/sponsor/SponsorForm.tsx (3)
48-76: consider surfacing upload errors in‑ui instead of using alerts
handleImageUploadcurrently reports validation and upload failures viaalert(...), which is blocking and not aligned with typical app‑level ux.it would be nicer to:
- track an
uploadErrorstate and render it near the upload area, or- use your existing toast/notification system if one exists.
for example:
- const [imageUrl, setImageUrl] = useState<string | null>(null); + const [imageUrl, setImageUrl] = useState<string | null>(null); + const [uploadError, setUploadError] = useState<string | null>(null); const handleImageUpload = async (e: React.ChangeEvent<HTMLInputElement>) => { const file = e.target.files?.[0]; if (!file) return; - // validate file size (e.g. 5MB) + // validate file size (e.g. 5mb) if (file.size > 5 * 1024 * 1024) { - alert("File size too large. Max 5MB allowed."); + setUploadError("file size too large. max 5mb allowed."); return; } setUploading(true); + setUploadError(null); try { const base64 = await new Promise<string>((resolve, reject) => { const reader = new FileReader(); @@ const result = await uploadImageMutation.mutateAsync({ file: base64 }); setImageUrl(result.url); } catch (error) { - console.error("Upload failed", error); - alert("Failed to upload image. Please try again."); + console.error("upload failed", error); + setUploadError("failed to upload image. please try again."); } finally { setUploading(false); } };and then render
uploadErrorunder the upload area if present.
94-206: tweak comments to follow lowercase / “why not what” guidelinelayout comments like
{/* Logo Upload Section */},{/* Upload Area */},{/* Preview Area */}describe what the code does and use capitalized phrases. guidelines ask for lowercase comments and comments explaining why rather than what.either:
- remove these comments (the jsx structure is already self‑explanatory), or
- reword them briefly to explain intent in lowercase if there’s a non‑obvious reason for the structure.
for example:
- {/* Logo Upload Section */} + {/* logo upload, kept separate from details for better visual focus */} @@ - {/* Upload Area */} + {/* upload area */} @@ - {/* Preview Area */} + {/* preview area */}
292-327: optional: add subtle inline validation hint for required logoyou already disable the submit button when
!imageUrland show a small note; this is good. if you want to make it more consistent with other field errors, you could style this message similarly to the zod error text (but with neutral color), or surface a formal validation error when submitting without a logo.this is non‑blocking; the current behavior is functionally correct.
apps/api/src/webhooks.ts (5)
64-67: Avoidanytype; useunknownand narrow with type guards.Per coding guidelines, avoid
anytype. Useunknownfor error handling and narrow appropriately.- } catch (error: any) { + } catch (error: unknown) { console.error("Webhook error:", error);
71-77: Define a TypeScript interface for the payload structure.Using
anyforpayloadbypasses type safety. Define an interface for the expected Razorpay payment webhook payload to catch access errors at compile time and improve maintainability. Based on learnings, strict TypeScript interfaces should be defined for request/response bodies.interface RazorpayPaymentPayload { payment: { entity: { id: string; order_id: string; amount: number; currency: string; contact?: string; email?: string; notes?: { name?: string }; }; }; }
106-109: Add context to error log for debugging.Per coding guidelines, log errors with context. Include
paymentIdto aid debugging when payment detail fetches fail.} catch (error) { - console.error("failed to fetch payment details from razorpay:", error); + console.error("failed to fetch payment details from razorpay:", { paymentId, error }); // continue without contact details if fetch fails }
199-209: Remove dead code and clarify default status logic.Lines 199-201 contain an empty conditional block that does nothing. Additionally, the default
newStatus = "active"is never used since all handled event types overwrite it. Consider removing the dead code and using explicit status mapping.- // If we don't have subscription entity directly (e.g. payment.failed), try to get from payment - if (!subId && payment && payment.description) { - // sometimes description contains sub id or we check notes - } - if (!subId) return; - let newStatus = "active"; - if (eventType === "subscription.pending") newStatus = "pending_payment"; - if (eventType === "subscription.halted") newStatus = "unpaid"; // or halted - if (eventType === "subscription.cancelled") newStatus = "cancelled"; - if (eventType === "payment.failed") newStatus = "failed"; + const statusMap: Record<string, string> = { + "subscription.pending": "pending_payment", + "subscription.halted": "unpaid", + "subscription.cancelled": "cancelled", + "payment.failed": "failed", + }; + const newStatus = statusMap[eventType]; + if (!newStatus) return;
162-190: Apply consistent typing to subscription webhook handlers.Similar to
handlePaymentCaptured, this function should use typed interfaces for the payload parameter instead ofany. Define interfaces for subscription and payment entities.interface RazorpaySubscriptionPayload { payment: { entity: { id: string } }; subscription: { entity: { id: string } }; } async function handleSubscriptionCharged(payload: RazorpaySubscriptionPayload) { // ... }apps/api/prisma/schema.prisma (2)
34-46: user–sponsor relation looks correct but consider delete behaviorthe
sponsors Sponsor[]relation correctly mirrorsSponsor.user? @relation(fields: [userId], references: [id]), so prisma will wire this as expected. however, if you ever delete users, currentSponsor.userhas noonDeletestrategy, so deleting a user with sponsors will likely fail due to fk constraints.consider explicitly choosing a strategy (e.g. cascade or set null) to make user deletion behavior predictable:
model Sponsor { // ... user User? @relation(fields: [userId], references: [id], onDelete: SetNull) }
106-122: consider stronger typing and constraints on sponsor status and payment linkagethe
Sponsormodel covers all required fields, but a few improvements would make it safer:
plan_statusis a rawStringwith a comment for allowed values. using a prisma enum (e.g.enum SponsorPlanStatus { active cancelled pending_payment pending_submission failed }) would prevent invalid states at both db and typescript levels.razorpay_payment_idis conceptually one‑to‑one with a sponsor, but there is no@uniqueon it. adding a unique constraint (or at least an index) would protect against accidental duplicates and help lookups.- field naming mixes snake_case here (
razorpay_payment_id,image_url,created_at) with camelCase elsewhere (e.g.Payment.razorpayPaymentId,createdAt). for long‑term maintainability, consider standardizing on one convention.none of these are blockers, but tightening them now will reduce bugs in the sponsor lifecycle and simplify querying.
apps/api/src/routers/sponsor.ts (2)
1-21: double‑check sponsor currency and environment assumptionsdefining
SPONSOR_MONTHLY_AMOUNT = 50000andSPONSOR_CURRENCY = "USD"is clear, but note that:
- the
Paymentmodel’scurrencydefault is"INR"and its comment mentions paise; here we’re using cents and"USD".- whether razorpay supports usd on your account is configuration‑dependent.
createSubscriptionand the manualPaymentinsert both rely on these constants, so if you ever change the sponsor price/currency, you must update them in one place only.also,
cloudinary.configis called with empty strings if env vars are missing; in that case uploads will just fail at runtime. consider failing fast (e.g. throwing during startup) if required env vars likeCLOUDINARY_CLOUD_NAMEorRAZORPAY_KEY_IDare not set so misconfiguration isn’t only discovered on first request.
38-65: order creation looks fine, but handle razorpay key presence explicitlyusing
paymentService.createOrderwith a sponsor‑specific receipt andnotes: { type: "sponsor" }is a good separation from other order types.two small things to tighten:
process.env.RAZORPAY_KEY_IDcan beundefined, which would be returned to clients askey: undefinedand cause confusing frontend failures. better to detect this and throw a server error:- return { - orderId: order.id, - amount: order.amount, - currency: order.currency, - key: process.env.RAZORPAY_KEY_ID, - }; + const keyId = process.env.RAZORPAY_KEY_ID; + if (!keyId) { + throw new TRPCError({ + code: "INTERNAL_SERVER_ERROR", + message: "razorpay key id is not configured on the server", + }); + } + + return { + orderId: order.id, + amount: order.amount, + currency: order.currency, + key: keyId, + };
- if
paymentService.createOrdercan throw (network / auth errors), consider wrapping it with try/catch and converting to aTRPCErrorinstead of a bareError, for consistent error codes.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (11)
apps/api/package.json(1 hunks)apps/api/prisma/clear_sponsors.sql(1 hunks)apps/api/prisma/schema.prisma(4 hunks)apps/api/src/index.ts(2 hunks)apps/api/src/routers/sponsor.ts(1 hunks)apps/api/src/webhooks.ts(1 hunks)apps/web/next.config.js(1 hunks)apps/web/src/app/(main)/sponsor/page.tsx(1 hunks)apps/web/src/app/(main)/sponsor/submit/page.tsx(1 hunks)apps/web/src/components/dashboard/DashboardContainer.tsx(1 hunks)apps/web/src/components/sponsor/SponsorForm.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/web/src/app/(main)/sponsor/page.tsx
- apps/web/src/components/dashboard/DashboardContainer.tsx
🧰 Additional context used
📓 Path-based instructions (14)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx,js,jsx}: Always use lowercase when writing comments
Avoid unnecessary comments; code should be self-documenting when possible
Use comments to explain 'why', not 'what'
Remove unused imports
Use UPPER_SNAKE_CASE for constants
Use camelCase for functions and variables
Files:
apps/api/src/index.tsapps/web/src/components/sponsor/SponsorForm.tsxapps/api/src/webhooks.tsapps/web/next.config.jsapps/api/src/routers/sponsor.tsapps/web/src/app/(main)/sponsor/submit/page.tsx
**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{tsx,ts}: Prefer functional components with TypeScript and use proper TypeScript types, avoidany
Extract reusable logic into custom hooks
Use descriptive prop names and define prop types using TypeScript interfaces or types
Prefer controlled components over uncontrolled
Use zustand for global state (located insrc/store/)
Use absolute imports from@/prefix when available
Include proper aria labels for accessibility
Ensure keyboard navigation works
Maintain proper heading hierarchy
Provide alt text for images
Avoid unnecessary re-renders
Files:
apps/api/src/index.tsapps/web/src/components/sponsor/SponsorForm.tsxapps/api/src/webhooks.tsapps/api/src/routers/sponsor.tsapps/web/src/app/(main)/sponsor/submit/page.tsx
**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (.cursorrules)
Organize imports: react → third-party → local components → utils → types
Files:
apps/api/src/index.tsapps/web/src/components/sponsor/SponsorForm.tsxapps/api/src/webhooks.tsapps/web/next.config.jsapps/api/src/routers/sponsor.tsapps/web/src/app/(main)/sponsor/submit/page.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx}: Use PascalCase for types and interfaces with descriptive names
Use dynamic imports for code splitting when appropriate
Memoize expensive computations
Files:
apps/api/src/index.tsapps/web/src/components/sponsor/SponsorForm.tsxapps/api/src/webhooks.tsapps/api/src/routers/sponsor.tsapps/web/src/app/(main)/sponsor/submit/page.tsx
**/*.{js,jsx,ts,tsx,py,java,go,rb,php}
📄 CodeRabbit inference engine (.cursor/rules/general_rules.mdc)
**/*.{js,jsx,ts,tsx,py,java,go,rb,php}: Always use lowercase when writing comments
Avoid unnecessary comments; code should be self-documenting when possible
Use comments to explain 'why', not 'what'
Files:
apps/api/src/index.tsapps/web/src/components/sponsor/SponsorForm.tsxapps/api/src/webhooks.tsapps/web/next.config.jsapps/api/src/routers/sponsor.tsapps/web/src/app/(main)/sponsor/submit/page.tsx
apps/api/src/**/*.{js,ts}
📄 CodeRabbit inference engine (apps/api/.cursor/rules/backend_rules.mdc)
apps/api/src/**/*.{js,ts}: Log errors with context (userId, endpoint, timestamp) for debugging
Always await async operations; never forget to handle promise rejections
Never log sensitive information (passwords, tokens, credit card numbers)
Files:
apps/api/src/index.tsapps/api/src/webhooks.tsapps/api/src/routers/sponsor.ts
apps/api/src/**/*.ts
📄 CodeRabbit inference engine (apps/api/.cursor/rules/backend_rules.mdc)
Avoid
anytype; useunknownfor truly dynamic data and narrow with type guards
Files:
apps/api/src/index.tsapps/api/src/webhooks.tsapps/api/src/routers/sponsor.ts
apps/api/src/{index,main,app,server}.{js,ts}
📄 CodeRabbit inference engine (apps/api/.cursor/rules/backend_rules.mdc)
Validate required environment variables on startup; fail fast if missing
Files:
apps/api/src/index.ts
apps/web/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
apps/web/src/**/*.{ts,tsx}: Always follow the design system defined inapps/web/src/lib/design-tokens.tsandapps/web/tailwind.config.ts
NEVER use hardcoded hex values (e.g.,#5519f7) directly in components; ALWAYS reference colors from the design token system using Tailwind classes
Use semantic color names that describe purpose, not appearance
Usefont-sansfor standard UI text (Geist Sans) andfont-monofor code, technical content, or monospace needs (DM Mono)
Follow Tailwind's spacing scale (0.25rem increments); for section padding use mobilep-4(1rem) and desktopp-[60px]
Use appropriate border radius: small elementsrounded-lg, mediumrounded-xl, largerounded-2xl, buttonsrounded-[16px]
Use animation durations: fastduration-100(0.1s), normalduration-300(0.3s), slowduration-600(0.6s)
Files:
apps/web/src/components/sponsor/SponsorForm.tsxapps/web/src/app/(main)/sponsor/submit/page.tsx
**/*[A-Z]*.{tsx,ts}
📄 CodeRabbit inference engine (.cursorrules)
Use PascalCase for component file names (e.g.,
UserProfile.tsx)
Files:
apps/web/src/components/sponsor/SponsorForm.tsx
apps/web/src/**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursorrules)
Optimize images using next/image
apps/web/src/**/*.{tsx,ts}: Use Zustand for global state, located insrc/store/
Use PascalCase for types and interfaces with descriptive names
Use dynamic imports for code splitting when appropriate
Optimize images using next/image
Memoize expensive computations
Define a type when defining const functions
Files:
apps/web/src/components/sponsor/SponsorForm.tsxapps/web/src/app/(main)/sponsor/submit/page.tsx
apps/web/src/components/**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (apps/web/.cursor/rules/frontend_rules.mdc)
apps/web/src/components/**/*.{tsx,ts,jsx,js}: Never use hardcoded hex values directly in components; always reference colors from the design token system using Tailwind classes
Use semantic color names from the design token system that describe purpose, not appearance (e.g., bg-brand-purple, bg-surface-primary, text-text-primary)
Use font-sans for standard UI text (Geist Sans) and font-mono for code, technical content, or monospace needs (DM Mono)
Follow Tailwind's spacing scale for section padding: p-4 (1rem) on mobile, p-[60px] on desktop
Use rounded-lg (0.5rem) for small elements, rounded-xl (1rem) for medium elements, rounded-2xl (1.5rem) for large elements, and rounded-[16px] for buttons
Use duration-100 (0.1s) for fast transitions, duration-300 (0.3s) for normal transitions, and duration-600 (0.6s) for slow transitions
Use available custom animations: animate-accordion-down, animate-accordion-up, animate-scrollRight, animate-scrollLeft, animate-customspin, animate-spin-slow, animate-spin-slow-reverse, animate-marquee, animate-marquee-vertical, animate-shine
Prefer functional components with TypeScript
Extract reusable logic into custom hooks
Prefer controlled components over uncontrolled
Include proper aria labels for accessibility
Ensure keyboard navigation works in interactive components
Maintain proper heading hierarchy in page components
Provide alt text for images
Use 'class:' instead of the ternary operator in class tags whenever possible
Implement accessibility features on interactive elements (e.g., tabindex='0', aria-label, onClick, onKeyDown)
Always follow the design system defined inapps/web/src/lib/design-tokens.tsandapps/web/tailwind.config.ts
Files:
apps/web/src/components/sponsor/SponsorForm.tsx
apps/web/src/components/**/*.{tsx,ts}
📄 CodeRabbit inference engine (apps/web/.cursor/rules/frontend_rules.mdc)
apps/web/src/components/**/*.{tsx,ts}: Use proper TypeScript types and avoid usinganytype
Use descriptive prop names and define prop types using TypeScript interfaces or types
Name components using PascalCase (e.g., UserProfile.tsx)
Files:
apps/web/src/components/sponsor/SponsorForm.tsx
apps/web/src/**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (apps/web/.cursor/rules/frontend_rules.mdc)
apps/web/src/**/*.{tsx,ts,jsx,js}: Organize imports in order: React → third-party → local components → utils → types
Use absolute imports from@/prefix when available
Remove unused imports
Use UPPER_SNAKE_CASE for constants
Use camelCase for functions and variables
Always use Tailwind classes for styling HTML elements; avoid using CSS or style tags
Use descriptive variable and function names; name event functions with a 'handle' prefix (e.g., handleClick, handleKeyDown)
Use const with arrow functions instead of function declarations (e.g., 'const toggle = () =>')
Files:
apps/web/src/components/sponsor/SponsorForm.tsxapps/web/src/app/(main)/sponsor/submit/page.tsx
🧠 Learnings (8)
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{routes,controllers,handlers,types}/*.ts : Define strict TypeScript interfaces for request/response bodies
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{routes,middleware}/*.{js,ts} : Implement rate limiting on all public endpoints to prevent abuse
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{routes,controllers,handlers,middleware}/*.{js,ts} : Use zod or similar for runtime validation of incoming data
Applied to files:
apps/api/src/index.tsapps/api/package.json
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{middleware,services,routes,controllers}/*.{js,ts} : Log all critical operations (auth attempts, payment processing, data mutations)
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{database,services}/*.{js,ts} : Handle database connection failures gracefully with retry logic
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/components/**/*.{tsx,ts} : Use descriptive prop names and define prop types using TypeScript interfaces or types
Applied to files:
apps/web/src/components/sponsor/SponsorForm.tsx
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/components/**/*.{tsx,ts,jsx,js} : Include proper aria labels for accessibility
Applied to files:
apps/web/src/components/sponsor/SponsorForm.tsx
📚 Learning: 2025-11-25T07:34:30.473Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T07:34:30.473Z
Learning: Applies to apps/web/src/**/*.{tsx,ts} : Optimize images using next/image
Applied to files:
apps/web/next.config.js
🧬 Code graph analysis (4)
apps/api/src/index.ts (1)
apps/api/src/webhooks.ts (1)
handleRazorpayWebhook(8-68)
apps/web/src/components/sponsor/SponsorForm.tsx (2)
apps/api/src/trpc.ts (1)
router(38-38)apps/web/src/lib/trpc.ts (1)
trpc(4-4)
apps/api/src/webhooks.ts (1)
apps/api/src/clients/razorpay.ts (1)
rz_instance(18-21)
apps/web/src/app/(main)/sponsor/submit/page.tsx (1)
apps/web/src/components/sponsor/SponsorForm.tsx (1)
SponsorForm(22-332)
🔇 Additional comments (6)
apps/web/src/app/(main)/sponsor/submit/page.tsx (1)
7-22: sponsor submit flow and payment id handling look consistentearly-return on missing
paymentIdplus themountedguard keeps the render logic simple and avoids potential client/server search param mismatches. wiring ofpaymentIdinto the sponsor form via props is clear and matches the intended flow.apps/web/src/components/sponsor/SponsorForm.tsx (1)
18-44: props and form schema wiring look solid
SponsorFormPropshas a clear, descriptiverazorpayPaymentIdprop, and the inferred form type from the schema keeps the inputs and validation in sync. this matches the guidance about descriptive prop names and typed props. based on learnings, this is aligned with the preferred pattern.apps/web/next.config.js (1)
17-20: LGTM!The Cloudinary remote pattern is correctly configured, enabling Next.js image optimization for sponsor images stored in Cloudinary. This aligns with the sponsor feature requirements.
apps/api/package.json (1)
40-41: Verify Zod 4 compatibility and update validation schemas if needed.Zod 4 introduces breaking changes from Zod 3 including unified error customization, new string validators, and modified default behaviors. Review existing validation schemas throughout the codebase (especially in routes, controllers, and middleware) to ensure they're compatible with Zod 4 syntax. The Cloudinary ^2.0.0 addition is appropriate for sponsor image storage functionality.
apps/api/prisma/schema.prisma (1)
66-79: makingpayment.userIdoptional is reasonable, but ensure all call sites handle nullswitching
userIdanduserto optional onPaymentmatches the sponsor flow where payments can exist without an authenticated user, andonDelete: Cascadeonuseris consistent with the rest of the schema. the main risk is existing code assumingpayment.userId/payment.userare always present.please sanity‑check usages of these fields elsewhere (api and web) to avoid runtime errors or missing auth checks when
userIdis null.apps/api/src/routers/sponsor.ts (1)
22-37: Public image upload endpoint needs basic abuse protection and validation
uploadImageis fully public and accepts any string, directly forwarding it to cloudinary. This aligns with "no auth required", but also means:
- Anyone can script uploads to your
opensox/sponsorsfolder, potentially driving up storage/traffic costs.- There is no validation on content type, size, or dimensions, even though the issue mentions validating image ratio/file.
Consider at minimum:
- .input(z.object({ file: z.string() })) + .input( + z.object({ + // require a data url and keep a reasonable size limit + file: z + .string() + .regex(/^data:image\/(png|jpe?g|webp);base64,/, "invalid image data url"), + }) +) - .mutation(async ({ input }: { input: { file: string } }) => { + .mutation(async ({ input }) => {And, if possible, add simple server-side checks on the decoded payload size and/or use a locked-down cloudinary upload preset for this folder.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (3)
apps/web/src/components/sponsor/SponsorCard.tsx (3)
7-15: Consider removing unused interface fields.The
idanddescriptionfields are defined in the interface but never referenced in the component. If these fields are not needed for this component, consider removing them to keep the interface minimal and focused.Apply this diff if the fields are genuinely unused:
interface SponsorCardProps { sponsor: { - id: string; company_name: string; - description: string; website: string; image_url: string; }; }If these fields are kept for consistency with the backend model or future use, consider adding a comment explaining this.
19-24: Add aria-label for better accessibility.The link lacks an aria-label, which would help screen reader users understand the link's purpose. Consider adding a descriptive label.
Apply this diff:
<Link href={sponsor.website} target="_blank" rel="noopener noreferrer" + aria-label={`Visit ${sponsor.company_name} website`} className="group block" >Based on coding guidelines, proper aria labels should be included for accessibility.
35-35: Use semantic color naming instead of appearance-based colors.The
text-green-400class uses appearance-based naming rather than semantic naming that describes purpose. Consider using a semantic color from your design token system.Apply this diff:
- <h3 className="text-white font-medium text-lg group-hover:text-green-400 transition-colors"> + <h3 className="text-white font-medium text-lg group-hover:text-brand-success transition-colors">(Replace
text-brand-successwith the appropriate semantic color class from your design token system as defined inapps/web/src/lib/design-tokens.ts)As per coding guidelines, use semantic color names that describe purpose, not appearance.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/web/src/components/landing-sections/Hero.tsx(1 hunks)apps/web/src/components/landing-sections/SponsorSection.tsx(1 hunks)apps/web/src/components/sponsor/SponsorCard.tsx(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- apps/web/src/components/landing-sections/Hero.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/web/src/components/landing-sections/SponsorSection.tsx
🧰 Additional context used
📓 Path-based instructions (11)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx,js,jsx}: Always use lowercase when writing comments
Avoid unnecessary comments; code should be self-documenting when possible
Use comments to explain 'why', not 'what'
Remove unused imports
Use UPPER_SNAKE_CASE for constants
Use camelCase for functions and variables
Files:
apps/web/src/components/sponsor/SponsorCard.tsx
apps/web/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
apps/web/src/**/*.{ts,tsx}: Always follow the design system defined inapps/web/src/lib/design-tokens.tsandapps/web/tailwind.config.ts
NEVER use hardcoded hex values (e.g.,#5519f7) directly in components; ALWAYS reference colors from the design token system using Tailwind classes
Use semantic color names that describe purpose, not appearance
Usefont-sansfor standard UI text (Geist Sans) andfont-monofor code, technical content, or monospace needs (DM Mono)
Follow Tailwind's spacing scale (0.25rem increments); for section padding use mobilep-4(1rem) and desktopp-[60px]
Use appropriate border radius: small elementsrounded-lg, mediumrounded-xl, largerounded-2xl, buttonsrounded-[16px]
Use animation durations: fastduration-100(0.1s), normalduration-300(0.3s), slowduration-600(0.6s)
Files:
apps/web/src/components/sponsor/SponsorCard.tsx
**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{tsx,ts}: Prefer functional components with TypeScript and use proper TypeScript types, avoidany
Extract reusable logic into custom hooks
Use descriptive prop names and define prop types using TypeScript interfaces or types
Prefer controlled components over uncontrolled
Use zustand for global state (located insrc/store/)
Use absolute imports from@/prefix when available
Include proper aria labels for accessibility
Ensure keyboard navigation works
Maintain proper heading hierarchy
Provide alt text for images
Avoid unnecessary re-renders
Files:
apps/web/src/components/sponsor/SponsorCard.tsx
**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (.cursorrules)
Organize imports: react → third-party → local components → utils → types
Files:
apps/web/src/components/sponsor/SponsorCard.tsx
**/*[A-Z]*.{tsx,ts}
📄 CodeRabbit inference engine (.cursorrules)
Use PascalCase for component file names (e.g.,
UserProfile.tsx)
Files:
apps/web/src/components/sponsor/SponsorCard.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx}: Use PascalCase for types and interfaces with descriptive names
Use dynamic imports for code splitting when appropriate
Memoize expensive computations
Files:
apps/web/src/components/sponsor/SponsorCard.tsx
apps/web/src/**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursorrules)
Optimize images using next/image
apps/web/src/**/*.{tsx,ts}: Use Zustand for global state, located insrc/store/
Use PascalCase for types and interfaces with descriptive names
Use dynamic imports for code splitting when appropriate
Optimize images using next/image
Memoize expensive computations
Define a type when defining const functions
Files:
apps/web/src/components/sponsor/SponsorCard.tsx
**/*.{js,jsx,ts,tsx,py,java,go,rb,php}
📄 CodeRabbit inference engine (.cursor/rules/general_rules.mdc)
**/*.{js,jsx,ts,tsx,py,java,go,rb,php}: Always use lowercase when writing comments
Avoid unnecessary comments; code should be self-documenting when possible
Use comments to explain 'why', not 'what'
Files:
apps/web/src/components/sponsor/SponsorCard.tsx
apps/web/src/components/**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (apps/web/.cursor/rules/frontend_rules.mdc)
apps/web/src/components/**/*.{tsx,ts,jsx,js}: Never use hardcoded hex values directly in components; always reference colors from the design token system using Tailwind classes
Use semantic color names from the design token system that describe purpose, not appearance (e.g., bg-brand-purple, bg-surface-primary, text-text-primary)
Use font-sans for standard UI text (Geist Sans) and font-mono for code, technical content, or monospace needs (DM Mono)
Follow Tailwind's spacing scale for section padding: p-4 (1rem) on mobile, p-[60px] on desktop
Use rounded-lg (0.5rem) for small elements, rounded-xl (1rem) for medium elements, rounded-2xl (1.5rem) for large elements, and rounded-[16px] for buttons
Use duration-100 (0.1s) for fast transitions, duration-300 (0.3s) for normal transitions, and duration-600 (0.6s) for slow transitions
Use available custom animations: animate-accordion-down, animate-accordion-up, animate-scrollRight, animate-scrollLeft, animate-customspin, animate-spin-slow, animate-spin-slow-reverse, animate-marquee, animate-marquee-vertical, animate-shine
Prefer functional components with TypeScript
Extract reusable logic into custom hooks
Prefer controlled components over uncontrolled
Include proper aria labels for accessibility
Ensure keyboard navigation works in interactive components
Maintain proper heading hierarchy in page components
Provide alt text for images
Use 'class:' instead of the ternary operator in class tags whenever possible
Implement accessibility features on interactive elements (e.g., tabindex='0', aria-label, onClick, onKeyDown)
Always follow the design system defined inapps/web/src/lib/design-tokens.tsandapps/web/tailwind.config.ts
Files:
apps/web/src/components/sponsor/SponsorCard.tsx
apps/web/src/components/**/*.{tsx,ts}
📄 CodeRabbit inference engine (apps/web/.cursor/rules/frontend_rules.mdc)
apps/web/src/components/**/*.{tsx,ts}: Use proper TypeScript types and avoid usinganytype
Use descriptive prop names and define prop types using TypeScript interfaces or types
Name components using PascalCase (e.g., UserProfile.tsx)
Files:
apps/web/src/components/sponsor/SponsorCard.tsx
apps/web/src/**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (apps/web/.cursor/rules/frontend_rules.mdc)
apps/web/src/**/*.{tsx,ts,jsx,js}: Organize imports in order: React → third-party → local components → utils → types
Use absolute imports from@/prefix when available
Remove unused imports
Use UPPER_SNAKE_CASE for constants
Use camelCase for functions and variables
Always use Tailwind classes for styling HTML elements; avoid using CSS or style tags
Use descriptive variable and function names; name event functions with a 'handle' prefix (e.g., handleClick, handleKeyDown)
Use const with arrow functions instead of function declarations (e.g., 'const toggle = () =>')
Files:
apps/web/src/components/sponsor/SponsorCard.tsx
🧠 Learnings (5)
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/components/**/*.{tsx,ts} : Use descriptive prop names and define prop types using TypeScript interfaces or types
Applied to files:
apps/web/src/components/sponsor/SponsorCard.tsx
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/components/**/*.{tsx,ts,jsx,js} : Include proper aria labels for accessibility
Applied to files:
apps/web/src/components/sponsor/SponsorCard.tsx
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/components/**/*.{tsx,ts,jsx,js} : Prefer functional components with TypeScript
Applied to files:
apps/web/src/components/sponsor/SponsorCard.tsx
📚 Learning: 2025-11-25T07:34:30.473Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T07:34:30.473Z
Learning: Applies to **/*[Cc]omponent.{tsx,ts} : Keep components focused and single-responsibility
Applied to files:
apps/web/src/components/sponsor/SponsorCard.tsx
📚 Learning: 2025-11-25T07:34:30.473Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T07:34:30.473Z
Learning: Applies to apps/web/src/**/*.{tsx,ts} : Optimize images using next/image
Applied to files:
apps/web/src/components/sponsor/SponsorCard.tsx
🔇 Additional comments (2)
apps/web/src/components/sponsor/SponsorCard.tsx (2)
1-6: LGTM: Imports are properly organized.The imports follow the correct order (React → third-party) as specified in the coding guidelines.
27-32: LGTM: Image implementation follows best practices.The Image component correctly uses Next.js optimization, includes proper alt text, and implements smooth hover transitions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (5)
apps/web/src/components/dashboard/DashboardSponsorList.tsx (2)
3-9: clean up imports and make component typing explicitthe
reactimport is not used and can be removed, and imports should follow the repo convention:react→ third-party (next/link,lucide-react) → local (@/lib/trpc,@/components/...). also consider typing the component explicitly, e.g.const DashboardSponsorList: React.FC = () => { ... }, to align with the “define a type when defining const functions” guideline. as per coding guidelines.
13-19: improve loading state accessibilitythe loading branch currently renders only the
Loader2icon, which is invisible to screen readers. wrapping this in a container withrole="status"and anaria-label(and/or an sr-only text node) plus marking the iconaria-hiddenwill make the state accessible while keeping the visual the same. based on learnings, accessibility labels are expected in interactive or dynamic ui.apps/web/src/components/landing-sections/SponsorSection.tsx (3)
3-8: align imports and component typing with conventions
reactis imported but not used and can be dropped. also,Link(third-party) should come before local imports so the order isreact→ third-party → local. optionally, add an explicit component type (const SponsorSection: React.FC = () => { ... }) to follow the “define a type for const functions” rule. as per coding guidelines.
12-14: avoid null loading ui and remove inline todo-style commentreturning
nullwhile sponsors load means the section pops in only after data is ready, which can cause layout shifts. consider rendering a lightweight skeleton or placeholder grid instead, and drop the// Or a skeletoncomment once you do so, since guidelines prefer avoiding todo-style inline comments. based on learnings, loading states and comments should be explicit and purposeful.
30-55: consider extracting a shared sponsor placeholder cardthe “become a sponsor” placeholder card here is very similar to the dashboard’s “your logo here” placeholder. extracting a small
SponsorPlaceholderCardcomponent (with configurable label/size) would reduce duplication and keep future visual tweaks in one place. this is non-blocking but would improve maintainability.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/web/src/app/(main)/sponsor/page.tsx(1 hunks)apps/web/src/components/dashboard/DashboardSponsorList.tsx(1 hunks)apps/web/src/components/landing-sections/SponsorSection.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/web/src/app/(main)/sponsor/page.tsx
🧰 Additional context used
📓 Path-based instructions (11)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx,js,jsx}: Always use lowercase when writing comments
Avoid unnecessary comments; code should be self-documenting when possible
Use comments to explain 'why', not 'what'
Remove unused imports
Use UPPER_SNAKE_CASE for constants
Use camelCase for functions and variables
Files:
apps/web/src/components/landing-sections/SponsorSection.tsxapps/web/src/components/dashboard/DashboardSponsorList.tsx
apps/web/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
apps/web/src/**/*.{ts,tsx}: Always follow the design system defined inapps/web/src/lib/design-tokens.tsandapps/web/tailwind.config.ts
NEVER use hardcoded hex values (e.g.,#5519f7) directly in components; ALWAYS reference colors from the design token system using Tailwind classes
Use semantic color names that describe purpose, not appearance
Usefont-sansfor standard UI text (Geist Sans) andfont-monofor code, technical content, or monospace needs (DM Mono)
Follow Tailwind's spacing scale (0.25rem increments); for section padding use mobilep-4(1rem) and desktopp-[60px]
Use appropriate border radius: small elementsrounded-lg, mediumrounded-xl, largerounded-2xl, buttonsrounded-[16px]
Use animation durations: fastduration-100(0.1s), normalduration-300(0.3s), slowduration-600(0.6s)
Files:
apps/web/src/components/landing-sections/SponsorSection.tsxapps/web/src/components/dashboard/DashboardSponsorList.tsx
**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{tsx,ts}: Prefer functional components with TypeScript and use proper TypeScript types, avoidany
Extract reusable logic into custom hooks
Use descriptive prop names and define prop types using TypeScript interfaces or types
Prefer controlled components over uncontrolled
Use zustand for global state (located insrc/store/)
Use absolute imports from@/prefix when available
Include proper aria labels for accessibility
Ensure keyboard navigation works
Maintain proper heading hierarchy
Provide alt text for images
Avoid unnecessary re-renders
Files:
apps/web/src/components/landing-sections/SponsorSection.tsxapps/web/src/components/dashboard/DashboardSponsorList.tsx
**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (.cursorrules)
Organize imports: react → third-party → local components → utils → types
Files:
apps/web/src/components/landing-sections/SponsorSection.tsxapps/web/src/components/dashboard/DashboardSponsorList.tsx
**/*[A-Z]*.{tsx,ts}
📄 CodeRabbit inference engine (.cursorrules)
Use PascalCase for component file names (e.g.,
UserProfile.tsx)
Files:
apps/web/src/components/landing-sections/SponsorSection.tsxapps/web/src/components/dashboard/DashboardSponsorList.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx}: Use PascalCase for types and interfaces with descriptive names
Use dynamic imports for code splitting when appropriate
Memoize expensive computations
Files:
apps/web/src/components/landing-sections/SponsorSection.tsxapps/web/src/components/dashboard/DashboardSponsorList.tsx
apps/web/src/**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursorrules)
Optimize images using next/image
apps/web/src/**/*.{tsx,ts}: Use Zustand for global state, located insrc/store/
Use PascalCase for types and interfaces with descriptive names
Use dynamic imports for code splitting when appropriate
Optimize images using next/image
Memoize expensive computations
Define a type when defining const functions
Files:
apps/web/src/components/landing-sections/SponsorSection.tsxapps/web/src/components/dashboard/DashboardSponsorList.tsx
**/*.{js,jsx,ts,tsx,py,java,go,rb,php}
📄 CodeRabbit inference engine (.cursor/rules/general_rules.mdc)
**/*.{js,jsx,ts,tsx,py,java,go,rb,php}: Always use lowercase when writing comments
Avoid unnecessary comments; code should be self-documenting when possible
Use comments to explain 'why', not 'what'
Files:
apps/web/src/components/landing-sections/SponsorSection.tsxapps/web/src/components/dashboard/DashboardSponsorList.tsx
apps/web/src/components/**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (apps/web/.cursor/rules/frontend_rules.mdc)
apps/web/src/components/**/*.{tsx,ts,jsx,js}: Never use hardcoded hex values directly in components; always reference colors from the design token system using Tailwind classes
Use semantic color names from the design token system that describe purpose, not appearance (e.g., bg-brand-purple, bg-surface-primary, text-text-primary)
Use font-sans for standard UI text (Geist Sans) and font-mono for code, technical content, or monospace needs (DM Mono)
Follow Tailwind's spacing scale for section padding: p-4 (1rem) on mobile, p-[60px] on desktop
Use rounded-lg (0.5rem) for small elements, rounded-xl (1rem) for medium elements, rounded-2xl (1.5rem) for large elements, and rounded-[16px] for buttons
Use duration-100 (0.1s) for fast transitions, duration-300 (0.3s) for normal transitions, and duration-600 (0.6s) for slow transitions
Use available custom animations: animate-accordion-down, animate-accordion-up, animate-scrollRight, animate-scrollLeft, animate-customspin, animate-spin-slow, animate-spin-slow-reverse, animate-marquee, animate-marquee-vertical, animate-shine
Prefer functional components with TypeScript
Extract reusable logic into custom hooks
Prefer controlled components over uncontrolled
Include proper aria labels for accessibility
Ensure keyboard navigation works in interactive components
Maintain proper heading hierarchy in page components
Provide alt text for images
Use 'class:' instead of the ternary operator in class tags whenever possible
Implement accessibility features on interactive elements (e.g., tabindex='0', aria-label, onClick, onKeyDown)
Always follow the design system defined inapps/web/src/lib/design-tokens.tsandapps/web/tailwind.config.ts
Files:
apps/web/src/components/landing-sections/SponsorSection.tsxapps/web/src/components/dashboard/DashboardSponsorList.tsx
apps/web/src/components/**/*.{tsx,ts}
📄 CodeRabbit inference engine (apps/web/.cursor/rules/frontend_rules.mdc)
apps/web/src/components/**/*.{tsx,ts}: Use proper TypeScript types and avoid usinganytype
Use descriptive prop names and define prop types using TypeScript interfaces or types
Name components using PascalCase (e.g., UserProfile.tsx)
Files:
apps/web/src/components/landing-sections/SponsorSection.tsxapps/web/src/components/dashboard/DashboardSponsorList.tsx
apps/web/src/**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (apps/web/.cursor/rules/frontend_rules.mdc)
apps/web/src/**/*.{tsx,ts,jsx,js}: Organize imports in order: React → third-party → local components → utils → types
Use absolute imports from@/prefix when available
Remove unused imports
Use UPPER_SNAKE_CASE for constants
Use camelCase for functions and variables
Always use Tailwind classes for styling HTML elements; avoid using CSS or style tags
Use descriptive variable and function names; name event functions with a 'handle' prefix (e.g., handleClick, handleKeyDown)
Use const with arrow functions instead of function declarations (e.g., 'const toggle = () =>')
Files:
apps/web/src/components/landing-sections/SponsorSection.tsxapps/web/src/components/dashboard/DashboardSponsorList.tsx
🧠 Learnings (7)
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/components/**/*.{tsx,ts,jsx,js} : Maintain proper heading hierarchy in page components
Applied to files:
apps/web/src/components/landing-sections/SponsorSection.tsx
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/**/*.{tsx,ts,jsx,js} : Organize imports in order: React → third-party → local components → utils → types
Applied to files:
apps/web/src/components/landing-sections/SponsorSection.tsx
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/components/**/*.{tsx,ts,jsx,js} : Include proper aria labels for accessibility
Applied to files:
apps/web/src/components/landing-sections/SponsorSection.tsx
📚 Learning: 2025-11-25T07:34:30.473Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T07:34:30.473Z
Learning: Applies to **/*[Cc]omponent.{tsx,ts} : Keep components focused and single-responsibility
Applied to files:
apps/web/src/components/landing-sections/SponsorSection.tsx
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/components/**/*.{tsx,ts} : Use descriptive prop names and define prop types using TypeScript interfaces or types
Applied to files:
apps/web/src/components/landing-sections/SponsorSection.tsx
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/components/**/*.{tsx,ts,jsx,js} : Prefer functional components with TypeScript
Applied to files:
apps/web/src/components/landing-sections/SponsorSection.tsx
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/components/**/*.{tsx,ts,jsx,js} : Follow Tailwind's spacing scale for section padding: p-4 (1rem) on mobile, p-[60px] on desktop
Applied to files:
apps/web/src/components/landing-sections/SponsorSection.tsx
🧬 Code graph analysis (2)
apps/web/src/components/landing-sections/SponsorSection.tsx (3)
apps/web/src/lib/trpc.ts (1)
trpc(4-4)apps/web/src/components/sponsor/SponsorCard.tsx (1)
SponsorCard(17-42)apps/web/src/providers/trpc-provider.tsx (1)
TRPCProvider(11-53)
apps/web/src/components/dashboard/DashboardSponsorList.tsx (2)
apps/web/src/lib/trpc.ts (1)
trpc(4-4)apps/web/src/components/sponsor/SponsorCard.tsx (1)
SponsorCard(17-42)
🔇 Additional comments (2)
apps/web/src/components/dashboard/DashboardSponsorList.tsx (1)
9-52: sponsor list logic and placeholder behavior look goodquery usage, slicing to three sponsors, and backfilling with “your logo here” placeholders keeps the grid stable and matches the described dashboard sponsor slot behavior. no blocking issues from my side here.
apps/web/src/components/landing-sections/SponsorSection.tsx (1)
8-57: landing sponsor section behavior matches the sponsor flowfetching active sponsors, capping to three, and backfilling the grid with cta placeholders to
/sponsoraligns with the described landing-page sponsor requirements. layout, spacing, and overall flow look good once the design-token color issue is addressed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (1)
apps/web/src/components/sponsor/SponsorForm.tsx (1)
136-176: replace hardcoded hex colors with design token classeslines 138 and 159 use
text-[#4dd0a4]which violates the design system rule against hardcoded hex values. use semantic color tokens instead.{uploading ? ( <div className="flex flex-col items-center gap-3"> - <Loader2 className="w-8 h-8 text-[#4dd0a4] animate-spin" /> + <Loader2 className="w-8 h-8 text-primary animate-spin" /> <p className="text-sm text-neutral-400">Uploading...</p> </div><div className="w-12 h-12 rounded-full bg-green-500/10 flex items-center justify-center"> <svg - className="w-6 h-6 text-[#4dd0a4]" + className="w-6 h-6 text-primary" fill="none"based on learnings, always reference colors from the design token system using tailwind classes.
🧹 Nitpick comments (10)
apps/web/src/app/(main)/sponsor/submit/page.tsx (2)
13-19: remove or enable the commented redirect logicthe redirect code on line 17 is commented out but the comment on line 16 suggests it should redirect. this creates confusion about the intended behavior. either enable the redirect or remove the dead code and comment.
useEffect(() => { setMounted(true); - if (!paymentId) { - // If no payment ID, redirect back to sponsor page - // router.push("/sponsor"); - } - }, [paymentId, router]); + }, []);alternatively, if redirect is intended:
useEffect(() => { setMounted(true); - if (!paymentId) { - // If no payment ID, redirect back to sponsor page - // router.push("/sponsor"); - } + if (!paymentId) { + router.push("/sponsor"); + } }, [paymentId, router]);
30-41: button styling looks good, minor radius adjustment suggestedthe button correctly uses semantic color tokens (
bg-primary,text-primary-foreground). per coding guidelines, buttons should userounded-[16px]instead ofrounded-lg.className=" bg-primary text-primary-foreground font-bold py-2 px-6 rounded-lg + rounded-[16px] hover:bg-primary/90apps/api/src/index.ts (1)
23-28: validate cloudinary credentials on startupcloudinary is configured with empty string fallbacks. if credentials are missing, uploads will silently fail at runtime. per coding guidelines, validate required environment variables on startup.
+// validate cloudinary credentials +const CLOUDINARY_CLOUD_NAME = process.env.CLOUDINARY_CLOUD_NAME; +const CLOUDINARY_API_KEY = process.env.CLOUDINARY_API_KEY; +const CLOUDINARY_API_SECRET = process.env.CLOUDINARY_API_SECRET; + +if (!CLOUDINARY_CLOUD_NAME || !CLOUDINARY_API_KEY || !CLOUDINARY_API_SECRET) { + console.warn("Cloudinary credentials not configured - sponsor image uploads will fail"); +} + // Configure Cloudinary (kept local to this route) cloudinary.config({ - cloud_name: process.env.CLOUDINARY_CLOUD_NAME || "", - api_key: process.env.CLOUDINARY_API_KEY || "", - api_secret: process.env.CLOUDINARY_API_SECRET || "", + cloud_name: CLOUDINARY_CLOUD_NAME || "", + api_key: CLOUDINARY_API_KEY || "", + api_secret: CLOUDINARY_API_SECRET || "", });apps/api/src/webhooks.ts (3)
71-110: define proper types for webhook payloadsthe
payload: anyparameter and nested access patterns lack type safety. consider defining interfaces for razorpay webhook payloads to catch errors at compile time.interface RazorpayPaymentEntity { id: string; order_id: string; amount: number; currency: string; contact?: string; email?: string; notes?: { name?: string }; } interface PaymentCapturedPayload { payment: { entity: RazorpayPaymentEntity }; } async function handlePaymentCaptured(payload: PaymentCapturedPayload) { const payment = payload.payment.entity; // ... }
162-190: consider logging when no sponsors are updated
updateManysilently succeeds even if no records match. for observability, consider logging when a subscription charge doesn't match any sponsor.- await prisma.sponsor.updateMany({ + const result = await prisma.sponsor.updateMany({ where: { razorpay_sub_id: subId, }, data: { plan_status: "active", }, }); + + if (result.count === 0) { + console.warn(`subscription.charged: no sponsor found for sub_id ${subId}`); + }
221-221: remove unnecessary commentthe trailing comment "No changes required for webhook handlers in this change set" appears to be a leftover from development and should be removed.
-// No changes required for webhook handlers in this change set.apps/web/src/components/sponsor/SponsorForm.tsx (4)
49-77: consider using the dedicated upload endpoint instead of base64the image upload converts files to base64, which increases payload size by ~33% and can be slow for larger files. the api already has a dedicated
/upload/sponsor-imageendpoint that handles multipart uploads more efficiently.// alternative using fetch with FormData const handleImageUpload = async (e: React.ChangeEvent<HTMLInputElement>) => { const file = e.target.files?.[0]; if (!file) return; if (file.size > 5 * 1024 * 1024) { alert("File size too large. Max 5MB allowed."); return; } setUploading(true); try { const formData = new FormData(); formData.append("file", file); const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/upload/sponsor-image`, { method: "POST", body: formData, }); if (!response.ok) throw new Error("Upload failed"); const result = await response.json(); setImageUrl(result.url); } catch (error) { console.error("Upload failed", error); alert("Failed to upload image. Please try again."); } finally { setUploading(false); } };
227-231: add aria-describedby for accessibilityinputs should reference their error messages for screen readers when validation fails.
<input {...form.register("companyName")} + aria-describedby={form.formState.errors.companyName ? "companyName-error" : undefined} + aria-invalid={!!form.formState.errors.companyName} className="w-full bg-neutral-900 border border-neutral-800 rounded-xl px-4 py-3 text-white placeholder:text-neutral-600 focus:border-neutral-700 focus:ring-1 focus:ring-neutral-700 outline-none transition-colors" placeholder="Acme Corporation" /> {form.formState.errors.companyName && ( - <p className="text-xs text-red-400 flex items-center gap-1"> + <p id="companyName-error" className="text-xs text-red-400 flex items-center gap-1" role="alert">
306-334: LGTM on semantic colors, minor radius suggestionthe submit button now correctly uses semantic color tokens (
bg-primary,text-primary-foreground). per coding guidelines, buttons should userounded-[16px]instead ofrounded-lg.className="w-full sm:w-auto sm:min-w-[200px] bg-primary text-primary-foreground font-semibold py-3.5 px-8 rounded-lg hover:bg-primary/90 transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2 group" + className="w-full sm:w-auto sm:min-w-[200px] bg-primary text-primary-foreground font-semibold py-3.5 px-8 rounded-[16px] hover:bg-primary/90 transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2 group"
92-101: simplify form validity checkthe manual validation checks duplicate the zod schema logic. since
mode: "onChange"is set,formState.isValidalready reflects the schema validation state.- // watch form values to check if all fields are completed - const watchedValues = form.watch(); - const isFormValid = - watchedValues.companyName?.trim().length >= 2 && - watchedValues.description?.trim().length >= 10 && - watchedValues.website?.trim().length > 0 && - form.formState.isValid && - imageUrl && - !uploading; + const isFormValid = form.formState.isValid && imageUrl && !uploading; const isSubmitting = submitAssetsMutation.isPending;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (6)
apps/api/src/index.ts(4 hunks)apps/api/src/routers/sponsor.ts(1 hunks)apps/api/src/webhooks.ts(1 hunks)apps/web/src/app/(main)/sponsor/submit/page.tsx(1 hunks)apps/web/src/components/landing-sections/SponsorSection.tsx(1 hunks)apps/web/src/components/sponsor/SponsorForm.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/web/src/components/landing-sections/SponsorSection.tsx
- apps/api/src/routers/sponsor.ts
🧰 Additional context used
📓 Path-based instructions (14)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx,js,jsx}: Always use lowercase when writing comments
Avoid unnecessary comments; code should be self-documenting when possible
Use comments to explain 'why', not 'what'
Remove unused imports
Use UPPER_SNAKE_CASE for constants
Use camelCase for functions and variables
Files:
apps/web/src/components/sponsor/SponsorForm.tsxapps/api/src/index.tsapps/api/src/webhooks.tsapps/web/src/app/(main)/sponsor/submit/page.tsx
apps/web/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
apps/web/src/**/*.{ts,tsx}: Always follow the design system defined inapps/web/src/lib/design-tokens.tsandapps/web/tailwind.config.ts
NEVER use hardcoded hex values (e.g.,#5519f7) directly in components; ALWAYS reference colors from the design token system using Tailwind classes
Use semantic color names that describe purpose, not appearance
Usefont-sansfor standard UI text (Geist Sans) andfont-monofor code, technical content, or monospace needs (DM Mono)
Follow Tailwind's spacing scale (0.25rem increments); for section padding use mobilep-4(1rem) and desktopp-[60px]
Use appropriate border radius: small elementsrounded-lg, mediumrounded-xl, largerounded-2xl, buttonsrounded-[16px]
Use animation durations: fastduration-100(0.1s), normalduration-300(0.3s), slowduration-600(0.6s)
Files:
apps/web/src/components/sponsor/SponsorForm.tsxapps/web/src/app/(main)/sponsor/submit/page.tsx
**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{tsx,ts}: Prefer functional components with TypeScript and use proper TypeScript types, avoidany
Extract reusable logic into custom hooks
Use descriptive prop names and define prop types using TypeScript interfaces or types
Prefer controlled components over uncontrolled
Use zustand for global state (located insrc/store/)
Use absolute imports from@/prefix when available
Include proper aria labels for accessibility
Ensure keyboard navigation works
Maintain proper heading hierarchy
Provide alt text for images
Avoid unnecessary re-renders
Files:
apps/web/src/components/sponsor/SponsorForm.tsxapps/api/src/index.tsapps/api/src/webhooks.tsapps/web/src/app/(main)/sponsor/submit/page.tsx
**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (.cursorrules)
Organize imports: react → third-party → local components → utils → types
Files:
apps/web/src/components/sponsor/SponsorForm.tsxapps/api/src/index.tsapps/api/src/webhooks.tsapps/web/src/app/(main)/sponsor/submit/page.tsx
**/*[A-Z]*.{tsx,ts}
📄 CodeRabbit inference engine (.cursorrules)
Use PascalCase for component file names (e.g.,
UserProfile.tsx)
Files:
apps/web/src/components/sponsor/SponsorForm.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx}: Use PascalCase for types and interfaces with descriptive names
Use dynamic imports for code splitting when appropriate
Memoize expensive computations
Files:
apps/web/src/components/sponsor/SponsorForm.tsxapps/api/src/index.tsapps/api/src/webhooks.tsapps/web/src/app/(main)/sponsor/submit/page.tsx
apps/web/src/**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursorrules)
Optimize images using next/image
apps/web/src/**/*.{tsx,ts}: Use Zustand for global state, located insrc/store/
Use PascalCase for types and interfaces with descriptive names
Use dynamic imports for code splitting when appropriate
Optimize images using next/image
Memoize expensive computations
Define a type when defining const functions
Files:
apps/web/src/components/sponsor/SponsorForm.tsxapps/web/src/app/(main)/sponsor/submit/page.tsx
**/*.{js,jsx,ts,tsx,py,java,go,rb,php}
📄 CodeRabbit inference engine (.cursor/rules/general_rules.mdc)
**/*.{js,jsx,ts,tsx,py,java,go,rb,php}: Always use lowercase when writing comments
Avoid unnecessary comments; code should be self-documenting when possible
Use comments to explain 'why', not 'what'
Files:
apps/web/src/components/sponsor/SponsorForm.tsxapps/api/src/index.tsapps/api/src/webhooks.tsapps/web/src/app/(main)/sponsor/submit/page.tsx
apps/web/src/components/**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (apps/web/.cursor/rules/frontend_rules.mdc)
apps/web/src/components/**/*.{tsx,ts,jsx,js}: Never use hardcoded hex values directly in components; always reference colors from the design token system using Tailwind classes
Use semantic color names from the design token system that describe purpose, not appearance (e.g., bg-brand-purple, bg-surface-primary, text-text-primary)
Use font-sans for standard UI text (Geist Sans) and font-mono for code, technical content, or monospace needs (DM Mono)
Follow Tailwind's spacing scale for section padding: p-4 (1rem) on mobile, p-[60px] on desktop
Use rounded-lg (0.5rem) for small elements, rounded-xl (1rem) for medium elements, rounded-2xl (1.5rem) for large elements, and rounded-[16px] for buttons
Use duration-100 (0.1s) for fast transitions, duration-300 (0.3s) for normal transitions, and duration-600 (0.6s) for slow transitions
Use available custom animations: animate-accordion-down, animate-accordion-up, animate-scrollRight, animate-scrollLeft, animate-customspin, animate-spin-slow, animate-spin-slow-reverse, animate-marquee, animate-marquee-vertical, animate-shine
Prefer functional components with TypeScript
Extract reusable logic into custom hooks
Prefer controlled components over uncontrolled
Include proper aria labels for accessibility
Ensure keyboard navigation works in interactive components
Maintain proper heading hierarchy in page components
Provide alt text for images
Use 'class:' instead of the ternary operator in class tags whenever possible
Implement accessibility features on interactive elements (e.g., tabindex='0', aria-label, onClick, onKeyDown)
Always follow the design system defined inapps/web/src/lib/design-tokens.tsandapps/web/tailwind.config.ts
Files:
apps/web/src/components/sponsor/SponsorForm.tsx
apps/web/src/components/**/*.{tsx,ts}
📄 CodeRabbit inference engine (apps/web/.cursor/rules/frontend_rules.mdc)
apps/web/src/components/**/*.{tsx,ts}: Use proper TypeScript types and avoid usinganytype
Use descriptive prop names and define prop types using TypeScript interfaces or types
Name components using PascalCase (e.g., UserProfile.tsx)
Files:
apps/web/src/components/sponsor/SponsorForm.tsx
apps/web/src/**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (apps/web/.cursor/rules/frontend_rules.mdc)
apps/web/src/**/*.{tsx,ts,jsx,js}: Organize imports in order: React → third-party → local components → utils → types
Use absolute imports from@/prefix when available
Remove unused imports
Use UPPER_SNAKE_CASE for constants
Use camelCase for functions and variables
Always use Tailwind classes for styling HTML elements; avoid using CSS or style tags
Use descriptive variable and function names; name event functions with a 'handle' prefix (e.g., handleClick, handleKeyDown)
Use const with arrow functions instead of function declarations (e.g., 'const toggle = () =>')
Files:
apps/web/src/components/sponsor/SponsorForm.tsxapps/web/src/app/(main)/sponsor/submit/page.tsx
apps/api/src/**/*.{js,ts}
📄 CodeRabbit inference engine (apps/api/.cursor/rules/backend_rules.mdc)
apps/api/src/**/*.{js,ts}: Log errors with context (userId, endpoint, timestamp) for debugging
Always await async operations; never forget to handle promise rejections
Never log sensitive information (passwords, tokens, credit card numbers)
Files:
apps/api/src/index.tsapps/api/src/webhooks.ts
apps/api/src/**/*.ts
📄 CodeRabbit inference engine (apps/api/.cursor/rules/backend_rules.mdc)
Avoid
anytype; useunknownfor truly dynamic data and narrow with type guards
Files:
apps/api/src/index.tsapps/api/src/webhooks.ts
apps/api/src/{index,main,app,server}.{js,ts}
📄 CodeRabbit inference engine (apps/api/.cursor/rules/backend_rules.mdc)
Validate required environment variables on startup; fail fast if missing
Files:
apps/api/src/index.ts
🧠 Learnings (23)
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/components/**/*.{tsx,ts} : Use descriptive prop names and define prop types using TypeScript interfaces or types
Applied to files:
apps/web/src/components/sponsor/SponsorForm.tsx
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/components/**/*.{tsx,ts,jsx,js} : Include proper aria labels for accessibility
Applied to files:
apps/web/src/components/sponsor/SponsorForm.tsx
📚 Learning: 2025-11-25T07:34:30.473Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T07:34:30.473Z
Learning: Applies to apps/web/src/**/*.{ts,tsx} : NEVER use hardcoded hex values (e.g., `#5519f7`) directly in components; ALWAYS reference colors from the design token system using Tailwind classes
Applied to files:
apps/web/src/components/sponsor/SponsorForm.tsxapps/web/src/app/(main)/sponsor/submit/page.tsx
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/components/**/*.{tsx,ts,jsx,js} : Never use hardcoded hex values directly in components; always reference colors from the design token system using Tailwind classes
Applied to files:
apps/web/src/components/sponsor/SponsorForm.tsxapps/web/src/app/(main)/sponsor/submit/page.tsx
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/components/**/*.{tsx,ts,jsx,js} : Use semantic color names from the design token system that describe purpose, not appearance (e.g., bg-brand-purple, bg-surface-primary, text-text-primary)
Applied to files:
apps/web/src/components/sponsor/SponsorForm.tsxapps/web/src/app/(main)/sponsor/submit/page.tsx
📚 Learning: 2025-11-25T07:34:30.473Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T07:34:30.473Z
Learning: Applies to apps/web/src/**/*.{ts,tsx} : Use semantic color names that describe purpose, not appearance
Applied to files:
apps/web/src/components/sponsor/SponsorForm.tsxapps/web/src/app/(main)/sponsor/submit/page.tsx
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/components/**/*.{tsx,ts,jsx,js} : Always follow the design system defined in `apps/web/src/lib/design-tokens.ts` and `apps/web/tailwind.config.ts`
Applied to files:
apps/web/src/components/sponsor/SponsorForm.tsxapps/web/src/app/(main)/sponsor/submit/page.tsx
📚 Learning: 2025-11-25T07:34:30.473Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T07:34:30.473Z
Learning: Applies to apps/web/src/**/*.{ts,tsx} : Always follow the design system defined in `apps/web/src/lib/design-tokens.ts` and `apps/web/tailwind.config.ts`
Applied to files:
apps/web/src/components/sponsor/SponsorForm.tsxapps/web/src/app/(main)/sponsor/submit/page.tsx
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/components/**/*.{tsx,ts,jsx,js} : Use 'class:' instead of the ternary operator in class tags whenever possible
Applied to files:
apps/web/src/components/sponsor/SponsorForm.tsxapps/web/src/app/(main)/sponsor/submit/page.tsx
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/**/*.{tsx,ts,jsx,js} : Always use Tailwind classes for styling HTML elements; avoid using CSS or style tags
Applied to files:
apps/web/src/components/sponsor/SponsorForm.tsxapps/web/src/app/(main)/sponsor/submit/page.tsx
📚 Learning: 2025-11-25T07:34:30.473Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T07:34:30.473Z
Learning: Applies to **/*.{tsx,ts} : Include proper aria labels for accessibility
Applied to files:
apps/web/src/components/sponsor/SponsorForm.tsx
📚 Learning: 2025-11-25T07:34:30.473Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T07:34:30.473Z
Learning: Applies to apps/web/src/**/*.{ts,tsx} : Use appropriate border radius: small elements `rounded-lg`, medium `rounded-xl`, large `rounded-2xl`, buttons `rounded-[16px]`
Applied to files:
apps/web/src/components/sponsor/SponsorForm.tsxapps/web/src/app/(main)/sponsor/submit/page.tsx
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/components/**/*.{tsx,ts,jsx,js} : Use rounded-lg (0.5rem) for small elements, rounded-xl (1rem) for medium elements, rounded-2xl (1.5rem) for large elements, and rounded-[16px] for buttons
Applied to files:
apps/web/src/components/sponsor/SponsorForm.tsx
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{routes,middleware}/*.{js,ts} : Implement rate limiting on all public endpoints to prevent abuse
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{routes,controllers,handlers,middleware}/*.{js,ts} : Use zod or similar for runtime validation of incoming data
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/**/*.{tsx,ts,jsx,js} : Organize imports in order: React → third-party → local components → utils → types
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/**/*.{tsx,ts,jsx,js} : Remove unused imports
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:34:30.473Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T07:34:30.473Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : Organize imports: react → third-party → local components → utils → types
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/**/*.{tsx,ts,jsx,js} : Use descriptive variable and function names; name event functions with a 'handle' prefix (e.g., handleClick, handleKeyDown)
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{routes,middleware}/*.{js,ts} : Use middleware for auth checks; never duplicate auth logic in route handlers
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{middleware,services,routes,controllers}/*.{js,ts} : Log all critical operations (auth attempts, payment processing, data mutations)
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{routes,controllers,handlers,types}/*.ts : Define strict TypeScript interfaces for request/response bodies
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{database,services}/*.{js,ts} : Handle database connection failures gracefully with retry logic
Applied to files:
apps/api/src/index.ts
🧬 Code graph analysis (3)
apps/web/src/components/sponsor/SponsorForm.tsx (3)
apps/api/src/trpc.ts (1)
router(38-38)apps/web/src/lib/trpc.ts (1)
trpc(4-4)apps/web/src/providers/trpc-provider.tsx (1)
TRPCProvider(11-53)
apps/api/src/index.ts (1)
apps/api/src/webhooks.ts (1)
handleRazorpayWebhook(8-68)
apps/api/src/webhooks.ts (1)
apps/api/src/clients/razorpay.ts (1)
rz_instance(18-21)
🔇 Additional comments (7)
apps/web/src/app/(main)/sponsor/submit/page.tsx (1)
46-59: LGTM!the success state rendering is well-structured with responsive layout and proper prop passing to
SponsorForm.apps/api/src/index.ts (3)
112-126: LGTM!the multer configuration has appropriate security measures: memory storage to avoid temp file issues, 10MB size limit, single file restriction, and strict MIME type validation for images only.
75-77: LGTM!the global request size limits have been appropriately reduced to 5mb, addressing the previous concern about DoS risk from excessive limits.
222-223: LGTM!the webhook handler is properly delegated to the external
handleRazorpayWebhookfunction, with the import correctly placed at the top of the file.apps/api/src/webhooks.ts (1)
8-68: LGTM on webhook signature validationthe signature validation uses proper HMAC-SHA256 with timing-safe comparison to prevent timing attacks. the event routing is well-structured with appropriate handlers for each event type.
apps/web/src/components/sponsor/SponsorForm.tsx (2)
1-11: LGTM!imports are well-organized following the pattern: react → third-party (react-hook-form, zod, lucide-react) → local (trpc, router, Image).
12-20: LGTM!the zod schema has appropriate validation rules and the
SponsorFormPropsinterface is properly typed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (2)
apps/api/src/index.ts (1)
128-167: protect sponsor upload endpoint and removeanyfrom upload flowthis endpoint is currently unauthenticated, so anyone can upload images into your
opensox/sponsorscloudinary folder, limited only byapiLimiter. given this is part of the paid sponsor flow, it should be behind your existing auth middleware (per backend rule to do auth via middleware, not in handlers) beforeupload.single("file").the implementation also introduces
Promise<any>andcatch (err: any), which breaks the “avoidany” rule forapps/api/src/**/*.ts. you can keep things typed without pulling in cloudinary’s full types by defining a small local result shape and treating errors asunknown, e.g.:+interface SponsorImageUploadResult { + secure_url: string; +} @@ - const result = await new Promise<any>((resolve, reject) => { + const result = await new Promise<SponsorImageUploadResult>((resolve, reject) => { const stream = cloudinary.uploader.upload_stream({ folder }, (error, uploadResult) => { if (error) return reject(error); - resolve(uploadResult); + resolve(uploadResult as SponsorImageUploadResult); }); stream.end(file.buffer); }); @@ - } catch (err: any) { - const isLimit = err?.message?.toLowerCase()?.includes("file too large"); - return res.status(isLimit ? 413 : 400).json({ error: err.message || "Upload failed" }); + } catch (err: unknown) { + const message = + typeof err === "object" && + err !== null && + "message" in err && + typeof (err as { message?: unknown }).message === "string" + ? (err as { message: string }).message + : "upload failed"; + const isLimit = message.toLowerCase().includes("file too large"); + return res.status(isLimit ? 413 : 400).json({ error: message }); }and then insert your existing auth middleware into the chain:
app.post( "/upload/sponsor-image", - apiLimiter, + apiLimiter, + authMiddleware, // or whatever shared auth guard you use elsewhere (req, res, next) => {lastly, please update the new comments in this block (
// Dedicated upload endpoint...,// Stream upload to Cloudinary) to use lower-case to match the project convention.apps/api/src/webhooks.ts (1)
192-219: complete or remove fallback subscription id extractionthe block
if (!subId && payment && payment.description) { // sometimes description contains sub id or we check notes }is still empty, so in cases like
payment.failedwhere the subscription id must be derived from the payment,subIdwill remain null and the function returns early without updating any sponsor records. either implement the intended extraction (e.g., frompayment.notes.subscription_idor a well-defined pattern indescription) or remove the unused conditional to avoid dead code and clarify behavior. the existing comment here can also be made lower-case to match the repo style.
🧹 Nitpick comments (3)
apps/api/src/index.ts (1)
112-126: multer config is solid; consider route-level handling for filter/limit errorsthe multer setup (memory storage, 10mb per-file limit, strict image mimetype allowlist) looks good for sponsor uploads. note that errors from
fileFilteror size limits will currently bubble to the global error handler and return a 500; you may want a small error-handling middleware for this route to translate invalid type/too-large cases into 400/413 responses instead. also, adjust the new comments here to lower-case per repository style.apps/api/src/webhooks.ts (2)
8-68: tighten webhook payload typing and basic validationthe main webhook handler currently treats the parsed
event/payloadas implicitanyand usescatch (error: any). per backend rules forapps/api/src/**/*.ts, it would be better to define a minimal type for the razorpay webhook envelope (witheventandpayloadfields) or to typebodyasunknownand narrow it with runtime checks before accessingevent/payload. similarly, type the caught error asunknownand narrow when logging. this will make it harder for unexpected payload shapes to cause runtime errors and aligns with the “avoidany” guideline. also, the new inline comments here (// Get signature,// Verify webhook signature,// Parse the event) should be lower-case to match the project’s comment style.
221-221: remove stale file-level comment
// No changes required for webhook handlers in this change set.is misleading in a new file that defines the handlers; suggest removing it to avoid confusion.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (2)
apps/api/src/index.ts(4 hunks)apps/api/src/webhooks.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx,js,jsx}: Always use lowercase when writing comments
Avoid unnecessary comments; code should be self-documenting when possible
Use comments to explain 'why', not 'what'
Remove unused imports
Use UPPER_SNAKE_CASE for constants
Use camelCase for functions and variables
Files:
apps/api/src/webhooks.tsapps/api/src/index.ts
**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{tsx,ts}: Prefer functional components with TypeScript and use proper TypeScript types, avoidany
Extract reusable logic into custom hooks
Use descriptive prop names and define prop types using TypeScript interfaces or types
Prefer controlled components over uncontrolled
Use zustand for global state (located insrc/store/)
Use absolute imports from@/prefix when available
Include proper aria labels for accessibility
Ensure keyboard navigation works
Maintain proper heading hierarchy
Provide alt text for images
Avoid unnecessary re-renders
Files:
apps/api/src/webhooks.tsapps/api/src/index.ts
**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (.cursorrules)
Organize imports: react → third-party → local components → utils → types
Files:
apps/api/src/webhooks.tsapps/api/src/index.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx}: Use PascalCase for types and interfaces with descriptive names
Use dynamic imports for code splitting when appropriate
Memoize expensive computations
Files:
apps/api/src/webhooks.tsapps/api/src/index.ts
**/*.{js,jsx,ts,tsx,py,java,go,rb,php}
📄 CodeRabbit inference engine (.cursor/rules/general_rules.mdc)
**/*.{js,jsx,ts,tsx,py,java,go,rb,php}: Always use lowercase when writing comments
Avoid unnecessary comments; code should be self-documenting when possible
Use comments to explain 'why', not 'what'
Files:
apps/api/src/webhooks.tsapps/api/src/index.ts
apps/api/src/**/*.{js,ts}
📄 CodeRabbit inference engine (apps/api/.cursor/rules/backend_rules.mdc)
apps/api/src/**/*.{js,ts}: Log errors with context (userId, endpoint, timestamp) for debugging
Always await async operations; never forget to handle promise rejections
Never log sensitive information (passwords, tokens, credit card numbers)
Files:
apps/api/src/webhooks.tsapps/api/src/index.ts
apps/api/src/**/*.ts
📄 CodeRabbit inference engine (apps/api/.cursor/rules/backend_rules.mdc)
Avoid
anytype; useunknownfor truly dynamic data and narrow with type guards
Files:
apps/api/src/webhooks.tsapps/api/src/index.ts
apps/api/src/{index,main,app,server}.{js,ts}
📄 CodeRabbit inference engine (apps/api/.cursor/rules/backend_rules.mdc)
Validate required environment variables on startup; fail fast if missing
Files:
apps/api/src/index.ts
🧠 Learnings (12)
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{routes,middleware}/*.{js,ts} : Implement rate limiting on all public endpoints to prevent abuse
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{routes,controllers,handlers,middleware}/*.{js,ts} : Use zod or similar for runtime validation of incoming data
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/**/*.{tsx,ts,jsx,js} : Organize imports in order: React → third-party → local components → utils → types
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:34:30.473Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T07:34:30.473Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : Organize imports: react → third-party → local components → utils → types
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/**/*.{tsx,ts,jsx,js} : Remove unused imports
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/**/*.{tsx,ts,jsx,js} : Use descriptive variable and function names; name event functions with a 'handle' prefix (e.g., handleClick, handleKeyDown)
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/*.ts : Avoid `any` type; use `unknown` for truly dynamic data and narrow with type guards
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/components/**/*.{tsx,ts} : Use proper TypeScript types and avoid using `any` type
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{routes,middleware}/*.{js,ts} : Use middleware for auth checks; never duplicate auth logic in route handlers
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{middleware,services,routes,controllers}/*.{js,ts} : Log all critical operations (auth attempts, payment processing, data mutations)
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{routes,controllers,handlers,types}/*.ts : Define strict TypeScript interfaces for request/response bodies
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{database,services}/*.{js,ts} : Handle database connection failures gracefully with retry logic
Applied to files:
apps/api/src/index.ts
🧬 Code graph analysis (2)
apps/api/src/webhooks.ts (1)
apps/api/src/clients/razorpay.ts (1)
rz_instance(18-21)
apps/api/src/index.ts (1)
apps/api/src/webhooks.ts (1)
handleRazorpayWebhook(8-68)
🔇 Additional comments (3)
apps/api/src/index.ts (2)
75-77: body size limit change looks appropriatereducing the global json/urlencoded limits to 5mb while keeping
/webhook/razorpayonexpress.rawis a good balance between dos protection and usability; this aligns with the earlier feedback about overly large body limits.
224-225: webhook routing is wired correctlyregistering
app.post("/webhook/razorpay", handleRazorpayWebhook)here, together with the earlierexpress.rawmiddleware on the same path, is the right pattern for keeping the raw body available for signature verification while isolating this route from the global json parser.apps/api/src/webhooks.ts (1)
162-190: subscription charged handler logic looks straightforwardupdating sponsors matched by
razorpay_sub_idtoplan_status: "active"onsubscription.chargedis a clear mapping and aligns with the described sponsor lifecycle; as long asrazorpay_sub_idis populated elsewhere in the flow, this handler is fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (1)
apps/api/src/webhooks.ts (1)
112-128: Replace check-then-create with upsert to avoid race condition on retries.The current
findUniquefollowed by conditionalcreatecan lead to duplicate-key errors when Razorpay retries webhook delivery and two concurrent requests race into thecreatecall.Apply this diff to make the operation idempotent:
- // check if payment already exists - const existingPayment = await prisma.payment.findUnique({ - where: { razorpayPaymentId: paymentId }, - }); - - if (!existingPayment) { - // create payment record without user (for sponsors) - await prisma.payment.create({ - data: { - razorpayPaymentId: paymentId, - razorpayOrderId: orderId, - amount: amount, - currency: currency, - status: "captured", - }, - }); - } + // upsert payment to handle retries idempotently + await prisma.payment.upsert({ + where: { razorpayPaymentId: paymentId }, + create: { + razorpayPaymentId: paymentId, + razorpayOrderId: orderId, + amount, + currency, + status: "captured", + }, + update: {}, + });
🧹 Nitpick comments (4)
apps/api/src/webhooks.ts (3)
40-43: Replaceanytype with proper webhook payload typing.The
payloadvariable is typed asany, which bypasses TypeScript's type safety. Consider defining proper types for Razorpay webhook payloads or usingunknownwith type guards.As per coding guidelines, avoid
anytype; useunknownfor truly dynamic data and narrow with type guards.- // Parse the event - const event = JSON.parse(body); - const eventType = event.event; - const payload = event.payload; + // parse the event + const event = JSON.parse(body) as { event: string; payload: unknown }; + const eventType = event.event; + const payload = event.payload;
162-165: Remove unusedpaymentvariable.The
paymentvariable is extracted but never used in this function.async function handleSubscriptionCharged(payload: any) { - const payment = payload.payment.entity; const subscription = payload.subscription.entity; - // Update sponsor status to active if it matches a known subscription - + // update sponsor status to active if it matches a known subscription
70-71: Avoidanytype for webhook payload parameters.All three handler functions use
anyfor theirpayloadparameter. Define proper types for Razorpay webhook payloads or useunknownwith type guards to maintain type safety.As per coding guidelines, avoid
anytype; useunknownfor truly dynamic data and narrow with type guards.Example for
handlePaymentCaptured:-async function handlePaymentCaptured(payload: any) { +type PaymentCapturedPayload = { + payment: { + entity: { + id: string; + order_id: string; + amount: number; + currency: string; + contact?: string | number; + email?: string; + notes?: { name?: string } | null; + }; + }; +}; + +async function handlePaymentCaptured(payload: unknown) { + const typedPayload = payload as PaymentCapturedPayload; + const payment = typedPayload.payment.entity;Also applies to: 162-162, 181-181
apps/api/src/routers/sponsor.ts (1)
221-222: Type payment fetch response instead of usinganycast.The
as anycast bypasses type safety when accessingorder_id.As per coding guidelines, avoid
anytype.- // Fetch payment details from Razorpay to get the linked order_id - const rpPayment = await rz_instance.payments.fetch(input.razorpayPaymentId); - const linkedOrderId = (rpPayment as any)?.order_id; + // fetch payment details from razorpay to get the linked order_id + type RazorpayPaymentWithOrder = { + order_id?: string; + }; + const rpPayment = (await rz_instance.payments.fetch( + input.razorpayPaymentId + )) as RazorpayPaymentWithOrder; + const linkedOrderId = rpPayment.order_id;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/api/src/routers/sponsor.ts(1 hunks)apps/api/src/webhooks.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx,js,jsx}: Always use lowercase when writing comments
Avoid unnecessary comments; code should be self-documenting when possible
Use comments to explain 'why', not 'what'
Remove unused imports
Use UPPER_SNAKE_CASE for constants
Use camelCase for functions and variables
Files:
apps/api/src/webhooks.tsapps/api/src/routers/sponsor.ts
**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{tsx,ts}: Prefer functional components with TypeScript and use proper TypeScript types, avoidany
Extract reusable logic into custom hooks
Use descriptive prop names and define prop types using TypeScript interfaces or types
Prefer controlled components over uncontrolled
Use zustand for global state (located insrc/store/)
Use absolute imports from@/prefix when available
Include proper aria labels for accessibility
Ensure keyboard navigation works
Maintain proper heading hierarchy
Provide alt text for images
Avoid unnecessary re-renders
Files:
apps/api/src/webhooks.tsapps/api/src/routers/sponsor.ts
**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (.cursorrules)
Organize imports: react → third-party → local components → utils → types
Files:
apps/api/src/webhooks.tsapps/api/src/routers/sponsor.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx}: Use PascalCase for types and interfaces with descriptive names
Use dynamic imports for code splitting when appropriate
Memoize expensive computations
Files:
apps/api/src/webhooks.tsapps/api/src/routers/sponsor.ts
**/*.{js,jsx,ts,tsx,py,java,go,rb,php}
📄 CodeRabbit inference engine (.cursor/rules/general_rules.mdc)
**/*.{js,jsx,ts,tsx,py,java,go,rb,php}: Always use lowercase when writing comments
Avoid unnecessary comments; code should be self-documenting when possible
Use comments to explain 'why', not 'what'
Files:
apps/api/src/webhooks.tsapps/api/src/routers/sponsor.ts
apps/api/src/**/*.{js,ts}
📄 CodeRabbit inference engine (apps/api/.cursor/rules/backend_rules.mdc)
apps/api/src/**/*.{js,ts}: Log errors with context (userId, endpoint, timestamp) for debugging
Always await async operations; never forget to handle promise rejections
Never log sensitive information (passwords, tokens, credit card numbers)
Files:
apps/api/src/webhooks.tsapps/api/src/routers/sponsor.ts
apps/api/src/**/*.ts
📄 CodeRabbit inference engine (apps/api/.cursor/rules/backend_rules.mdc)
Avoid
anytype; useunknownfor truly dynamic data and narrow with type guards
Files:
apps/api/src/webhooks.tsapps/api/src/routers/sponsor.ts
🧠 Learnings (2)
📓 Common learnings
Learnt from: huamanraj
Repo: apsinghdev/opensox PR: 239
File: apps/api/src/index.ts:139-166
Timestamp: 2025-12-06T08:42:03.292Z
Learning: In the sponsor feature (apps/api/src), sponsor-related upload endpoints like /upload/sponsor-image do not require user authentication because sponsors are paying customers who may not be registered OpenSox users. The uploaded assets are validated through payment verification in subsequent steps.
📚 Learning: 2025-12-06T08:42:03.292Z
Learnt from: huamanraj
Repo: apsinghdev/opensox PR: 239
File: apps/api/src/index.ts:139-166
Timestamp: 2025-12-06T08:42:03.292Z
Learning: In the sponsor feature (apps/api/src), sponsor-related upload endpoints like /upload/sponsor-image do not require user authentication because sponsors are paying customers who may not be registered OpenSox users. The uploaded assets are validated through payment verification in subsequent steps.
Applied to files:
apps/api/src/routers/sponsor.ts
🧬 Code graph analysis (1)
apps/api/src/webhooks.ts (1)
apps/api/src/clients/razorpay.ts (1)
rz_instance(18-21)
🔇 Additional comments (7)
apps/api/src/webhooks.ts (1)
188-232: Subscription ID extraction logic is now complete.The fallback logic for extracting subscription IDs from payment data has been properly implemented with pattern matching and multiple fallback strategies. This addresses the incomplete implementation flagged in previous reviews.
apps/api/src/routers/sponsor.ts (6)
18-20: LGTM!Constants are properly defined in UPPER_SNAKE_CASE, making the sponsor pricing configuration clear and centralized.
38-65: LGTM!Order creation logic is correct, with proper
notes.type = "sponsor"metadata for validation in subsequent steps. The receipt ID generation ensures uniqueness.
92-104: Critical security validation now in place.The order validation (amount, currency, and
notes.type === "sponsor") prevents unauthorized activation of sponsor slots using unrelated payments. This addresses the critical issue flagged in previous reviews.
107-122: Race condition resolved with upsert.Replacing
findUnique+createwithupsertmakes payment creation idempotent and prevents duplicate-key errors on concurrent webhook retries. This addresses the issue flagged in previous reviews.
220-242: Order validation prevents unauthorized sponsor activation.The addition of order validation (amount, currency, notes.type) and enforcement of the
pending_submissionstate prevents attackers from using arbitrary payments to activate sponsor slots. This addresses the critical authorization gap flagged in previous reviews.
282-300: PII exposure resolved with selective field projection.The endpoint now uses
selectto return only public-facing fields (id, company_name, image_url, website, plan_status, created_at), removing the privacy issue with exposed contact details. This addresses the major issue flagged in previous reviews.Note: The
descriptionfield is currently omitted. If sponsor descriptions are meant to be displayed publicly on the landing page, consider adding it to the select clause.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (1)
apps/api/src/index.ts (1)
127-182: ReplacePromise<any>with proper Cloudinary response typing.The upload endpoint is well-structured with appropriate validation, rate limiting, and multipart enforcement. However, line 164 uses
Promise<any>which violates the coding guideline to avoidanytypes.Apply this diff to add proper typing:
+ // cloudinary upload response type + interface CloudinaryUploadResult { + secure_url: string; + public_id: string; + bytes: number; + format: string; + } + // Stream upload to Cloudinary const folder = "opensox/sponsors"; - const result = await new Promise<any>((resolve, reject) => { + const result = await new Promise<CloudinaryUploadResult>((resolve, reject) => { const stream = cloudinary.uploader.upload_stream({ folder }, (error, uploadResult) => { if (error) return reject(error); - resolve(uploadResult); + resolve(uploadResult as CloudinaryUploadResult); }); stream.end(file.buffer); });Based on coding guidelines: Avoid
anytype; use proper TypeScript types.
🧹 Nitpick comments (1)
apps/api/src/routers/sponsor.ts (1)
45-57: Use TRPCError for consistency with other procedures.The uploadImage procedure throws a generic
Erroron line 55, while other procedures in this router consistently useTRPCError. This creates inconsistent error handling across the API.Apply this diff:
} catch (error) { console.error("cloudinary upload error:", error); - throw new Error("image upload failed"); + throw new TRPCError({ + code: "INTERNAL_SERVER_ERROR", + message: "image upload failed", + cause: error, + }); }This matches the error handling pattern used in other procedures (e.g., lines 208-212, 294-299).
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (3)
apps/api/src/index.ts(4 hunks)apps/api/src/routers/sponsor.ts(1 hunks)apps/api/src/webhooks.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/api/src/webhooks.ts
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx,js,jsx}: Always use lowercase when writing comments
Avoid unnecessary comments; code should be self-documenting when possible
Use comments to explain 'why', not 'what'
Remove unused imports
Use UPPER_SNAKE_CASE for constants
Use camelCase for functions and variables
Files:
apps/api/src/index.tsapps/api/src/routers/sponsor.ts
**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{tsx,ts}: Prefer functional components with TypeScript and use proper TypeScript types, avoidany
Extract reusable logic into custom hooks
Use descriptive prop names and define prop types using TypeScript interfaces or types
Prefer controlled components over uncontrolled
Use zustand for global state (located insrc/store/)
Use absolute imports from@/prefix when available
Include proper aria labels for accessibility
Ensure keyboard navigation works
Maintain proper heading hierarchy
Provide alt text for images
Avoid unnecessary re-renders
Files:
apps/api/src/index.tsapps/api/src/routers/sponsor.ts
**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (.cursorrules)
Organize imports: react → third-party → local components → utils → types
Files:
apps/api/src/index.tsapps/api/src/routers/sponsor.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx}: Use PascalCase for types and interfaces with descriptive names
Use dynamic imports for code splitting when appropriate
Memoize expensive computations
Files:
apps/api/src/index.tsapps/api/src/routers/sponsor.ts
**/*.{js,jsx,ts,tsx,py,java,go,rb,php}
📄 CodeRabbit inference engine (.cursor/rules/general_rules.mdc)
**/*.{js,jsx,ts,tsx,py,java,go,rb,php}: Always use lowercase when writing comments
Avoid unnecessary comments; code should be self-documenting when possible
Use comments to explain 'why', not 'what'
Files:
apps/api/src/index.tsapps/api/src/routers/sponsor.ts
apps/api/src/**/*.{js,ts}
📄 CodeRabbit inference engine (apps/api/.cursor/rules/backend_rules.mdc)
apps/api/src/**/*.{js,ts}: Log errors with context (userId, endpoint, timestamp) for debugging
Always await async operations; never forget to handle promise rejections
Never log sensitive information (passwords, tokens, credit card numbers)
Files:
apps/api/src/index.tsapps/api/src/routers/sponsor.ts
apps/api/src/**/*.ts
📄 CodeRabbit inference engine (apps/api/.cursor/rules/backend_rules.mdc)
Avoid
anytype; useunknownfor truly dynamic data and narrow with type guards
Files:
apps/api/src/index.tsapps/api/src/routers/sponsor.ts
apps/api/src/{index,main,app,server}.{js,ts}
📄 CodeRabbit inference engine (apps/api/.cursor/rules/backend_rules.mdc)
Validate required environment variables on startup; fail fast if missing
Files:
apps/api/src/index.ts
🧠 Learnings (17)
📓 Common learnings
Learnt from: huamanraj
Repo: apsinghdev/opensox PR: 239
File: apps/api/src/index.ts:139-166
Timestamp: 2025-12-06T08:42:03.292Z
Learning: In the sponsor feature (apps/api/src), sponsor-related upload endpoints like /upload/sponsor-image do not require user authentication because sponsors are paying customers who may not be registered OpenSox users. The uploaded assets are validated through payment verification in subsequent steps.
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{routes,middleware}/*.{js,ts} : Implement rate limiting on all public endpoints to prevent abuse
Applied to files:
apps/api/src/index.tsapps/api/src/routers/sponsor.ts
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{middleware,services,routes,controllers}/*.{js,ts} : Log all critical operations (auth attempts, payment processing, data mutations)
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{routes,controllers,handlers,middleware}/*.{js,ts} : Use zod or similar for runtime validation of incoming data
Applied to files:
apps/api/src/index.tsapps/api/src/routers/sponsor.ts
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/**/*.{tsx,ts,jsx,js} : Organize imports in order: React → third-party → local components → utils → types
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:34:30.473Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T07:34:30.473Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : Organize imports: react → third-party → local components → utils → types
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/**/*.{tsx,ts,jsx,js} : Remove unused imports
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/**/*.{tsx,ts,jsx,js} : Use descriptive variable and function names; name event functions with a 'handle' prefix (e.g., handleClick, handleKeyDown)
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/*.ts : Avoid `any` type; use `unknown` for truly dynamic data and narrow with type guards
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:35:19.071Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/web/.cursor/rules/frontend_rules.mdc:0-0
Timestamp: 2025-11-25T07:35:19.071Z
Learning: Applies to apps/web/src/components/**/*.{tsx,ts} : Use proper TypeScript types and avoid using `any` type
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-12-06T08:42:03.292Z
Learnt from: huamanraj
Repo: apsinghdev/opensox PR: 239
File: apps/api/src/index.ts:139-166
Timestamp: 2025-12-06T08:42:03.292Z
Learning: In the sponsor feature (apps/api/src), sponsor-related upload endpoints like /upload/sponsor-image do not require user authentication because sponsors are paying customers who may not be registered OpenSox users. The uploaded assets are validated through payment verification in subsequent steps.
Applied to files:
apps/api/src/index.tsapps/api/src/routers/sponsor.ts
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/{index,main,app,server}.{js,ts} : Validate required environment variables on startup; fail fast if missing
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{config,environment,setup}/*.{js,ts} : Use type-safe environment variable access with proper defaults
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/*.{js,ts} : Never log sensitive information (passwords, tokens, credit card numbers)
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{routes,middleware}/*.{js,ts} : Use middleware for auth checks; never duplicate auth logic in route handlers
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{routes,controllers,handlers,types}/*.ts : Define strict TypeScript interfaces for request/response bodies
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-11-25T07:34:58.984Z
Learnt from: CR
Repo: apsinghdev/opensox PR: 0
File: apps/api/.cursor/rules/backend_rules.mdc:0-0
Timestamp: 2025-11-25T07:34:58.984Z
Learning: Applies to apps/api/src/**/{database,services}/*.{js,ts} : Handle database connection failures gracefully with retry logic
Applied to files:
apps/api/src/index.ts
🧬 Code graph analysis (1)
apps/api/src/routers/sponsor.ts (3)
apps/api/src/trpc.ts (2)
router(38-38)publicProcedure(39-39)apps/api/src/services/payment.service.ts (1)
paymentService(54-257)apps/api/src/clients/razorpay.ts (1)
rz_instance(18-21)
🔇 Additional comments (10)
apps/api/src/index.ts (5)
17-19: LGTM!The new imports are properly organized at the top of the file and follow the coding guidelines for import organization.
23-36: LGTM!The early environment variable validation follows the coding guideline to validate required env vars on startup and fail fast if missing. The implementation correctly checks for both missing and empty values.
90-92: LGTM!The global request size limits have been appropriately reduced to 5mb to prevent DoS attacks, while the dedicated upload endpoint uses multer with its own stricter limits. This addresses the previous security concern.
239-240: LGTM!The webhook handler is properly delegated to the centralized
handleRazorpayWebhookfunction, and the import is correctly placed at the top of the file. This addresses the previous review concern about inline imports.
38-43: Remove duplicate Cloudinary configuration or consolidate to single initialization.The original review comment raises a valid architectural concern: Cloudinary's SDK should be configured once at application startup, not in multiple modules. Web search confirms this aligns with Cloudinary best practices—initializing the SDK in one place creates a single source of truth and prevents fragmented configuration.
However, I cannot access the repository to verify that
apps/api/src/routers/sponsor.tscontains the claimed duplicate configuration with empty string fallbacks. To complete this review, confirm whethersponsor.tshas a duplicatecloudinary.config()call and whether it can be safely removed without breaking functionality.apps/api/src/routers/sponsor.ts (5)
18-20: LGTM!The constants follow the coding guideline to use UPPER_SNAKE_CASE and are properly defined for the sponsor subscription pricing.
60-86: LGTM!The createSubscription procedure correctly creates a Razorpay order with the fixed sponsor amount, currency, and includes the
type: "sponsor"note that will be used for order validation in subsequent steps.
89-214: LGTM!The verifyPayment procedure correctly implements critical security validations:
- Signature verification (lines 100-104)
- Order invariant validation for amount, currency, and sponsor type (lines 114-125)
- Payment upsert to prevent race conditions (lines 128-143)
- Proper TypeScript typing instead of
any(lines 146-154)- Creates sponsor record with
pending_submissionstatus to enforce proper flowThis addresses all the critical security concerns from previous reviews.
252-279: LGTM!The submitAssets procedure correctly implements critical security validations:
- Fetches and validates the linked order's amount, currency, and sponsor type (lines 252-263)
- Enforces the proper flow by checking for
pending_submissionstate (lines 266-279)This prevents unauthorized sponsor activation via payment replay attacks, addressing the critical security concern from previous reviews.
304-321: LGTM!The getActiveSponsors procedure correctly returns only public-facing fields, excluding contact PII (email, phone). This addresses the privacy concern from previous reviews.
fix #230
2025-12-06_12-59-05.mp4
2025-12-06_13-00-27.mp4
Summary by CodeRabbit
New Features
Bug Fixes / Reliability
Dependencies
Refactor
Chores
✏️ Tip: You can customize this high-level summary in your review settings.