Skip to content

Roadmap Page#26

Merged
FindMalek merged 23 commits intomainfrom
findmalek/fin-49-roadmap-page
Oct 18, 2025
Merged

Roadmap Page#26
FindMalek merged 23 commits intomainfrom
findmalek/fin-49-roadmap-page

Conversation

@FindMalek
Copy link
Copy Markdown
Owner

@FindMalek FindMalek commented Oct 12, 2025

Summary by CodeRabbit

  • New Features

    • Dedicated roadmap page and interactive roadmap list with subscription
    • Roadmap subscription and waitlist email notifications (confirmation emails)
    • New marketing pages: Rate Limit Test page and improved marketing layout/header
  • Chores

    • Added marketing-related environment entries and new email provider dependency
  • Documentation

    • Updated README hero image reference

@FindMalek FindMalek self-assigned this Oct 12, 2025
@vercel
Copy link
Copy Markdown
Contributor

vercel bot commented Oct 12, 2025

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

Project Deployment Preview Comments Updated (UTC)
zero-locker Ready Ready Preview Comment Oct 18, 2025 11:42pm

💡 Enable Vercel Agent with $100 free credit for automated AI reviews

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Oct 12, 2025

Walkthrough

Adds roadmap subscription and email-sending via Resend, a new rate-limiting subsystem (in-memory sliding window + middleware), marketing pages/components (roadmap, rate-limit test), Prisma model/migration for roadmap subscriptions, ORPC procedure/hook for subscribing, and supporting utilities and types.

Changes

Cohort / File(s) Summary
Env & Config
\.env.example`, `env.ts``
Added RESEND_API_KEY and MARKETING_SUBSCRIPTION_EMAIL (empty defaults); wrapped two token values in quotes; mirrored new vars in runtime env schema.
Database & Migration
\prisma/schema/auth.prisma`, `prisma/schema/migrations/.../migration.sql``
New RoadmapSubscription Prisma model and corresponding SQL migration creating roadmap_subscription table with unique email index and metadata fields.
Email infra & utilities
\lib/email/index.ts`, `lib/email/resend-client.ts`, `lib/email/send-waitlist-email.ts`, `lib/email/send-roadmap-subscription-email.ts``
New Resend client singleton and exported send functions for waitlist and roadmap subscription emails; index re-exports email modules.
Email components & footer
\components/app/email-waitlist.tsx`, `components/app/email-roadmap-subscription.tsx`, `components/shared/email-footer.tsx``
New React email templates (waitlist + roadmap subscription) and reusable email footer (simple/detailed) using @react-email/components.
Rate-limiting core
\lib/utils/rate-limit.ts`, `lib/utils/index.ts``
New in-memory sliding-window rate limiter, presets, cache API, and handleORPCError helper for oRPC error extraction (rate-limit-aware).
Middleware
\middleware/rate-limit.ts`, `middleware/index.ts``
New rate-limit middleware producing ORPCError on throttling; wrapper presets (strict/moderate/lenient/veryLenient); re-exported from middleware index.
oRPC context, types & router
\orpc/context.ts`, `orpc/types.ts`, `orpc/routers/user.ts`, `orpc/hooks/use-users.ts``
Context now extracts client IP; ORPCContext includes ip and optional rateLimit; added RateLimitInfo type; user router adds subscribeToRoadmap and wraps procedures with rate-limit variants; new useSubscribeToRoadmap hook.
Schemas & Types
\schemas/user/roadmap.ts`, `schemas/user/roadmap-subscription.ts`, `types/index.d.ts``
Zod input/output schemas for roadmap subscription; new RoadmapStatus and RoadmapItem types.
Marketing pages & layout
\app/(marketing)/layout.tsx`, `app/(marketing)/page.tsx`, `app/(marketing)/roadmap/page.tsx`, `app/(marketing)/rate-limit-test/page.tsx``
New MarketingLayout; main marketing page simplified; added roadmap page and a client-side rate-limit test page.
Marketing components
\components/app/marketing-header-desktop.tsx`, `components/app/marketing-roadmap-item.tsx`, `components/app/marketing-roadmap-list.tsx`, `components/app/marketing-roadmap-subscription.tsx`, `components/app/marketing-waitlist-form.tsx``
Header updated (roadmap link); new roadmap item + scrollable list + subscription component; waitlist form improved error handling and toasts.
Config mapping
\config/converter.tsx``
Added roadmapStatusConfig mapping RoadmapStatus to label and color classes.
Entity import path changes
multiple files under \entities/`*`
Many entity files updated to use absolute alias imports (@/...) instead of relative ./query imports.
Auth util import
\lib/auth/verify.ts``
Switched an auth import to absolute alias (@/lib/auth/server).
Lib exports
\lib/utils/index.ts`, `lib/email/index.ts``
New exports (handleORPCError, rate-limit exports, email re-exports).
Docs & deps
\README.md`, `package.json``
README hero image path updated; added runtime deps @react-email/components and resend.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant UI as Roadmap Page
    participant Hook as useSubscribeToRoadmap
    participant oRPC as orpc.users.subscribeToRoadmap
    participant Middleware as RateLimit Middleware
    participant DB as Prisma
    participant Email as Resend

    User->>UI: Submit email
    UI->>Hook: mutate({ email })
    Hook->>oRPC: RPC call
    oRPC->>Middleware: rateLimit check (ip+identifier)
    alt throttled
        Middleware-->>oRPC: throw TOO_MANY_REQUESTS (retryAfter)
        oRPC-->>Hook: error
        Hook-->>UI: show error toast
    else allowed
        Middleware-->>oRPC: proceed (rateLimit meta)
        oRPC->>DB: ensure not duplicate / create subscription
        alt duplicate
            DB-->>oRPC: constraint error -> return error response
            oRPC-->>Hook: { success: false, error }
            Hook-->>UI: show error
        else created
            oRPC->>Email: send roadmap email (non-fatal on failure)
            Email-->>oRPC: success / error (logged)
            oRPC-->>Hook: { success: true }
            Hook-->>UI: show success toast
        end
    end
Loading
sequenceDiagram
    participant Request as Incoming Request
    participant Context as ORPC Context
    participant RateLib as checkRateLimit()
    participant Cache as In-Memory Cache
    participant Next as Next Middleware / Handler

    Request->>Context: createContext(headers)
    Context->>RateLib: checkRateLimit(ip, config)
    RateLib->>Cache: get/set entry + increment
    alt over limit
        RateLib-->>Context: { allowed: false, retryAfter, resetAt }
        Context-->>Request: throw ORPCError(TOO_MANY_REQUESTS, payload)
    else allowed
        RateLib-->>Context: { allowed: true, remaining, limit, resetAt }
        Context->>Next: call next() with rateLimit meta
        Next-->>Request: response
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

  • Feat/orpc #6 — Adds or modifies oRPC routers/hooks/middleware; likely overlaps with rate-limiting and ORPC changes.
  • Style/auth marketing #8 — Touches marketing UI components/pages; related to marketing page/header edits.
  • Disable Browser Auto Save #14 — Changes forms and autofill behavior; may overlap with marketing waitlist/subscription form handling.

Poem

🐰
I nibble code and stitch the map,
Subscriptions hop into my lap.
Emails take flight on gentle breeze,
Rate limits guard each careful squeeze.
Roadmap blooms — a joyful clap!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 56.25% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The PR title "Roadmap Page" directly refers to a major user-facing feature being added to the codebase—specifically, the new roadmap page at app/(marketing)/roadmap/page.tsx and its associated roadmap subscription functionality. While the pull request includes additional supporting infrastructure such as rate limiting utilities, email sending capabilities, database schema changes, and a rate limit test page, the instructions acknowledge that titles don't need to cover every detail of the changeset. The title is clear, specific, and accurately reflects the primary feature being delivered without being vague or misleading.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch findmalek/fin-49-roadmap-page

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

❤️ Share

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

@FindMalek FindMalek marked this pull request as ready for review October 18, 2025 23:03
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 14

🧹 Nitpick comments (19)
orpc/hooks/use-users.ts (1)

93-101: Consider adding onSuccess handler for user feedback.

The mutation only has an onError handler. Users should receive confirmation when they successfully subscribe to roadmap updates. Other mutations in this file (e.g., useJoinWaitlist on lines 28-45) include onSuccess handlers for cache invalidation or user feedback.

Consider adding success handling:

 export function useSubscribeToRoadmap() {
   return useMutation({
     mutationFn: orpc.users.subscribeToRoadmap.call,
+    onSuccess: (data) => {
+      // Show success toast or trigger other success feedback
+    },
     onError: (error) => {
       console.error("Failed to subscribe to roadmap:", error)
     },
   })
 }
app/(marketing)/roadmap/page.tsx (1)

21-58: Consider making roadmap items configurable.

The roadmap items are hard-coded in the component. While this works for now, consider:

  • Moving the items to a config file for easier updates
  • The "in-progress" status from RoadmapStatus is defined but never used

If you plan to update the roadmap frequently, you might want to extract this to config/roadmap.ts:

// config/roadmap.ts
import type { RoadmapItem } from "@/types"

export const roadmapItems: RoadmapItem[] = [
  // ... items here
]

Then import and use in the page component.

components/app/marketing-roadmap-subscription.tsx (1)

23-25: Consider reusing the imported schema.

The local subscriptionSchema duplicates subscribeToRoadmapInputSchema from schemas/user/roadmap-subscription.ts. While functional, this creates maintenance overhead if validation rules change.

Consider importing and reusing the existing schema:

+import { subscribeToRoadmapInputSchema } from "@/schemas/user/roadmap-subscription"
-import { z } from "zod"

-const subscriptionSchema = z.object({
-  email: z.string().min(1, "Email is required").email("Invalid email address"),
-})
-
-type SubscriptionFormData = z.infer<typeof subscriptionSchema>
+type SubscriptionFormData = z.infer<typeof subscribeToRoadmapInputSchema>

 export function MarketingRoadmapSubscription() {
   const subscribeToRoadmapMutation = useSubscribeToRoadmap()
   
   // ...
   
   const form = useForm<SubscriptionFormData>({
-    resolver: zodResolver(subscriptionSchema),
+    resolver: zodResolver(subscribeToRoadmapInputSchema),
     defaultValues: {
       email: "",
     },
   })
schemas/user/roadmap.ts (1)

4-6: Normalize email to avoid case/whitespace duplicates.

Trim and lowercase the input so Foo@bar.com and foo@bar.com don’t create separate records.

 export const subscribeToRoadmapInputSchema = z.object({
-  email: z.string().min(1, "Email is required").email("Invalid email address"),
+  email: z
+    .string()
+    .min(1, "Email is required")
+    .email("Invalid email address")
+    .transform((v) => v.trim().toLowerCase()),
 })
lib/email/send-roadmap-subscription-email.ts (1)

11-31: Replace console logging with structured logger and add explicit return type.

Avoid console usage per repo rules; return type clarity helps callers. Also consider a friendly “From” display name.

-interface SendRoadmapSubscriptionEmailOptions {
+interface SendRoadmapSubscriptionEmailOptions {
   to: string
 }
 
-export async function sendRoadmapSubscriptionEmail({
-  to,
-}: SendRoadmapSubscriptionEmailOptions) {
+export async function sendRoadmapSubscriptionEmail({
+  to,
+}: SendRoadmapSubscriptionEmailOptions): Promise<{ success: true; data: unknown }> {
   try {
     const { data, error } = await resendClient.emails.send({
-      from: env.MARKETING_SUBSCRIPTION_EMAIL,
+      // Consider using a friendly from-name:
+      from: `Zero Locker <${env.MARKETING_SUBSCRIPTION_EMAIL}>`,
       to,
       subject: "You're Subscribed to Zero-Locker Updates! 🎉",
-      react: EmailRoadmapSubscription({ email: to }),
+      react: EmailRoadmapSubscription({ email: to }),
     })
 
     if (error) {
-      console.error("Failed to send roadmap subscription email:", error)
+      // logger.error("Failed to send roadmap subscription email", { error })
       throw new Error("Failed to send roadmap subscription email")
     }
 
     return { success: true, data }
   } catch (error) {
-    console.error("Error sending roadmap subscription email:", error)
+    // logger.error("Error sending roadmap subscription email", { error })
     throw error
   }
 }
app/(marketing)/rate-limit-test/page.tsx (2)

233-266: Use spinner + text for loading states instead of only changing label.

Follow the UI guideline: show Icons.spinner with animate-spin and keep text; add disabled opacity.

-              <Button
-                onClick={() => testEndpoint("userCount", "User Count", 100)}
-                disabled={userCountQuery.isFetching}
-                className="w-full"
-              >
-                {userCountQuery.isFetching ? "Testing..." : "Test User Count"}
-              </Button>
+              <Button
+                onClick={() => testEndpoint("userCount", "User Count", 100)}
+                disabled={userCountQuery.isFetching}
+                className="w-full disabled:opacity-50"
+              >
+                {userCountQuery.isFetching ? (
+                  <>
+                    <Icons.spinner className="mr-2 size-4 animate-spin" />
+                    Testing
+                  </>
+                ) : (
+                  "Test User Count"
+                )}
+              </Button>

Apply the same pattern to “Waitlist Count”, “Encrypted Data Count”, and “Test Join Waitlist” buttons.

Also applies to: 278-287


53-57: Use cn() for conditional classNames.

Keep class composition consistent with the project convention.

+import { cn, handleORPCError } from "@/lib/utils"
-import { handleORPCError } from "@/lib/utils"
...
-      <div
-        className={`from-background via-background/50 pointer-events-none absolute bottom-0 left-0 right-0 h-32 rounded-b-lg bg-gradient-to-t to-transparent transition-opacity duration-500 ${
-          showScrollIndicator ? "opacity-100" : "opacity-0"
-        }`}
-      />
+      <div
+        className={cn(
+          "pointer-events-none absolute bottom-0 left-0 right-0 h-32 rounded-b-lg bg-gradient-to-t from-background via-background/50 to-transparent transition-opacity duration-500",
+          showScrollIndicator ? "opacity-100" : "opacity-0",
+        )}
+      />
...
-      <div
-        className={`pointer-events-none absolute bottom-4 left-1/2 -translate-x-1/2 animate-bounce transition-opacity duration-500 ${
-          showScrollIndicator ? "opacity-100" : "opacity-0"
-        }`}
-      >
+      <div
+        className={cn(
+          "pointer-events-none absolute bottom-4 left-1/2 -translate-x-1/2 animate-bounce transition-opacity duration-500",
+          showScrollIndicator ? "opacity-100" : "opacity-0",
+        )}
+      >

Also applies to: 60-66

components/app/marketing-roadmap-list.tsx (2)

42-49: Avoid Array index in keys; prefer a stable unique key.

Index-based keys hurt reconciliation. Use a unique id/slug; if titles are unique, use title alone.

-        {items.map((item, index) => (
+        {items.map((item) => (
           <MarketingRoadmapItem
-            key={`${item.title}-${index}`}
+            key={item.title} // or item.id if available
             title={item.title}
             description={item.description}
             status={item.status}
           />
         ))}

If titles aren’t guaranteed unique, extend RoadmapItem with an id and use that as key.


53-57: Use cn() for conditional classes.

Aligns with the codebase style for class concatenation.

+import { cn } from "@/lib/utils"
...
-      <div
-        className={`from-background via-background/50 pointer-events-none absolute bottom-0 left-0 right-0 h-32 rounded-b-lg bg-gradient-to-t to-transparent transition-opacity duration-500 ${
-          showScrollIndicator ? "opacity-100" : "opacity-0"
-        }`}
-      />
+      <div
+        className={cn(
+          "pointer-events-none absolute bottom-0 left-0 right-0 h-32 rounded-b-lg bg-gradient-to-t from-background via-background/50 to-transparent transition-opacity duration-500",
+          showScrollIndicator ? "opacity-100" : "opacity-0",
+        )}
+      />
...
-      <div
-        className={`pointer-events-none absolute bottom-4 left-1/2 -translate-x-1/2 animate-bounce transition-opacity duration-500 ${
-          showScrollIndicator ? "opacity-100" : "opacity-0"
-        }`}
-      >
+      <div
+        className={cn(
+          "pointer-events-none absolute bottom-4 left-1/2 -translate-x-1/2 animate-bounce transition-opacity duration-500",
+          showScrollIndicator ? "opacity-100" : "opacity-0",
+        )}
+      >

Also applies to: 60-66

middleware/rate-limit.ts (1)

50-60: Consider normalizing resetAt units in context.

checkRateLimit returns seconds; if consumers expect ms, convert here or add a JSDoc note to prevent drift.

orpc/routers/user.ts (3)

41-53: Simplify middleware usage — pass the middleware function directly.

The extra wrapper is unnecessary; .use(lenientRateLimit()) etc. is cleaner.

-const publicProcedure = baseProcedure.use(({ context, next }) =>
-  lenientRateLimit()({ context, next })
-)
+const publicProcedure = baseProcedure.use(lenientRateLimit())
...
-const strictPublicProcedure = baseProcedure.use(({ context, next }) =>
-  strictRateLimit()({ context, next })
-)
+const strictPublicProcedure = baseProcedure.use(strictRateLimit())
...
-const moderatePublicProcedure = baseProcedure.use(({ context, next }) =>
-  moderateRateLimit()({ context, next })
-)
+const moderatePublicProcedure = baseProcedure.use(moderateRateLimit())

216-253: Email case sensitivity — ensure DB uniqueness aligns with input normalization.

If you adopt .toLowerCase().trim() in the schema, you’re good; otherwise, consider lowercasing before findUnique/create to avoid duplicates by case.


327-333: Magic number for expected defaults.

Extract EXPECTED_DEFAULT_CONTAINER_COUNT = 3 as a named constant to avoid magic numbers and ease future changes.

-      const expectedDefaultCount = 3
+      const EXPECTED_DEFAULT_CONTAINER_COUNT = 3
-      if (existingDefaultContainers.length >= expectedDefaultCount) {
+      if (existingDefaultContainers.length >= EXPECTED_DEFAULT_CONTAINER_COUNT) {
lib/utils/rate-limit.ts (6)

7-12: Doc says “sliding window”, implementation is fixed-window. Pick one (or implement sliding).

The code resets a fixed window at first hit; it is not a true sliding/rolling window. Update docs or switch algorithm to sliding window log/token bucket.

Apply doc tweak if you intend fixed window:

- * - Sliding window rate limiting
+ * - Fixed-window rate limiting (window anchored at first request)

135-137: Singleton leaks across Next.js dev HMR; reuse a global to prevent duplicate intervals.

Dev reloads can instantiate multiple caches/intervals. Reuse one via globalThis.

-const rateLimitCache = new RateLimitCache()
+const rateLimitCache: RateLimitCache =
+  (globalThis as any).__rateLimitCache ?? ((globalThis as any).__rateLimitCache = new RateLimitCache())

159-166: Async function without await.

checkRateLimit is async but synchronous. Either remove async (and return a non‑Promise) or keep async only if you’ll await a store (e.g., Redis) soon. Pick one for consistency.

Option A (simpler now):

-export async function checkRateLimit(
+export function checkRateLimit(
   ip: string,
   config: RateLimitConfig
-): Promise<RateLimitResult> {
+): RateLimitResult {

Option B (keep async): add a small awaited no‑op and a TODO to switch to external store soon.


206-215: Clamp retryAfter to non‑negative.

At exact boundary, subtraction can yield 0 or negative due to clock rounding. Clamp.

   if (entry.count > maxRequests) {
     return {
       allowed: false,
       remaining: 0,
       limit: maxRequests,
       resetAt: entry.resetAt,
-      retryAfter: entry.resetAt - now,
+      retryAfter: Math.max(0, entry.resetAt - now),
     }
   }

63-67: Operational note: in‑memory cache isn’t production‑safe across instances.

Serverless/multi‑instance deployments will bypass limits per instance/invocation. Ensure production uses a distributed store (Redis/Upstash) and wire this utility to it before enabling globally.


203-206: Minor: extra Map.set after mutating the entry is unnecessary.

Map stores the object reference; after entry.count++, re‑setting is redundant. Safe to remove for micro‑perf/readability.

-  entry.count++
-  rateLimitCache.set(key, entry)
+  entry.count++
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 78fa796 and 99dc5da.

⛔ Files ignored due to path filters (4)
  • github.png is excluded by !**/*.png
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • public/email/roadmap.png is excluded by !**/*.png
  • public/og.png is excluded by !**/*.png
📒 Files selected for processing (33)
  • .env.example (1 hunks)
  • README.md (1 hunks)
  • app/(marketing)/layout.tsx (1 hunks)
  • app/(marketing)/page.tsx (1 hunks)
  • app/(marketing)/rate-limit-test/page.tsx (1 hunks)
  • app/(marketing)/roadmap/page.tsx (1 hunks)
  • components/app/email-roadmap-subscription.tsx (1 hunks)
  • components/app/email-waitlist.tsx (1 hunks)
  • components/app/marketing-header-desktop.tsx (1 hunks)
  • components/app/marketing-roadmap-item.tsx (1 hunks)
  • components/app/marketing-roadmap-list.tsx (1 hunks)
  • components/app/marketing-roadmap-subscription.tsx (1 hunks)
  • components/app/marketing-waitlist-form.tsx (3 hunks)
  • components/shared/email-footer.tsx (1 hunks)
  • env.ts (2 hunks)
  • lib/email/index.ts (1 hunks)
  • lib/email/resend-client.ts (1 hunks)
  • lib/email/send-roadmap-subscription-email.ts (1 hunks)
  • lib/email/send-waitlist-email.ts (1 hunks)
  • lib/utils/index.ts (1 hunks)
  • lib/utils/rate-limit.ts (1 hunks)
  • middleware/index.ts (1 hunks)
  • middleware/rate-limit.ts (1 hunks)
  • orpc/context.ts (1 hunks)
  • orpc/hooks/use-users.ts (1 hunks)
  • orpc/routers/user.ts (5 hunks)
  • orpc/types.ts (1 hunks)
  • package.json (2 hunks)
  • prisma/schema/auth.prisma (1 hunks)
  • prisma/schema/migrations/20251018210700_added_roadmap_subscription/migration.sql (1 hunks)
  • schemas/user/roadmap-subscription.ts (1 hunks)
  • schemas/user/roadmap.ts (1 hunks)
  • types/index.d.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (49)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{js,jsx,ts,tsx}: Don't use consecutive spaces in regular expression literals
Don't use the arguments object
Don't use the comma operator
Don't write functions that exceed a given Cognitive Complexity score
Don't use unnecessary boolean casts
Don't use unnecessary callbacks with flatMap
Use for...of statements instead of Array.forEach
Don't create classes that only have static members
Don't use this and super in static contexts
Don't use unnecessary catch clauses
Don't use unnecessary constructors
Don't use unnecessary continue statements
Don't export empty modules that don't change anything
Don't use unnecessary escape sequences in regular expression literals
Don't use unnecessary labels
Don't use unnecessary nested block statements
Don't rename imports, exports, and destructured assignments to the same name
Don't use unnecessary string or template literal concatenation
Don't use String.raw in template literals when there are no escape sequences
Don't use useless case statements in switch statements
Don't use ternary operators when simpler alternatives exist
Don't use useless this aliasing
Don't initialize variables to undefined
Don't use void operators
Use arrow functions instead of function expressions
Use Date.now() to get milliseconds since the Unix Epoch
Use .flatMap() instead of map().flat() when possible
Use literal property access instead of computed property access
Don't use parseInt() or Number.parseInt() when binary, octal, or hexadecimal literals work
Use concise optional chaining instead of chained logical expressions
Use regular expression literals instead of the RegExp constructor when possible
Don't use number literal object member names that aren't base 10 or use underscore separators
Remove redundant terms from logical expressions
Use while loops instead of for loops when you don't need initializer and update expressions
Don't reassign const variables
Don't use constant expressions in conditions
Don't use Math.min and Math.max to clamp value...

Files:

  • schemas/user/roadmap-subscription.ts
  • lib/utils/index.ts
  • lib/email/send-waitlist-email.ts
  • components/app/marketing-roadmap-item.tsx
  • components/app/marketing-header-desktop.tsx
  • app/(marketing)/roadmap/page.tsx
  • env.ts
  • components/app/email-waitlist.tsx
  • components/app/marketing-roadmap-subscription.tsx
  • lib/email/send-roadmap-subscription-email.ts
  • lib/email/index.ts
  • components/shared/email-footer.tsx
  • components/app/marketing-roadmap-list.tsx
  • schemas/user/roadmap.ts
  • types/index.d.ts
  • lib/email/resend-client.ts
  • app/(marketing)/page.tsx
  • app/(marketing)/rate-limit-test/page.tsx
  • app/(marketing)/layout.tsx
  • components/app/marketing-waitlist-form.tsx
  • middleware/index.ts
  • orpc/hooks/use-users.ts
  • orpc/types.ts
  • middleware/rate-limit.ts
  • components/app/email-roadmap-subscription.tsx
  • orpc/context.ts
  • orpc/routers/user.ts
  • lib/utils/rate-limit.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{ts,tsx}: Don't use primitive type aliases or misleading types
Don't use empty type parameters in type aliases and interfaces
Don't use any or unknown as type constraints
Don't return a value from a function that has a 'void' return type
Don't use the TypeScript directive @ts-ignore
Make sure switch-case statements are exhaustive
Don't use TypeScript enums
Don't add type annotations to variables, parameters, and class properties that are initialized with literal expressions
Don't use TypeScript namespaces
Don't use non-null assertions with the ! postfix operator
Don't use parameter properties in class constructors
Don't use user-defined types
Use as const instead of literal types and type annotations
Use either T[] or Array consistently
Use consistent accessibility modifiers on class properties and methods
Put default function parameters and optional function parameters last
Initialize each enum member value explicitly
Use export type for types
Use import type for types
Make sure all enum members are literal values
Use function types instead of object types with call signatures
Don't use void type outside of generic or return types
Don't use TypeScript const enum
Don't declare empty interfaces
Don't let variables evolve into any type through reassignments
Don't use the any type
Don't misuse the non-null assertion operator (!) in TypeScript files
Don't use implicit any type on variable declarations
Don't merge interfaces and classes unsafely
Don't use overload signatures that aren't next to each other
Use the namespace keyword instead of the module keyword to declare TypeScript namespaces

Use type-only imports when possible

**/*.{ts,tsx}: Use camelCase for function and method names
Use UPPER_SNAKE_CASE for constants
Use camelCase for variables
Use PascalCase for classes and types
Use absolute imports for top-level modules (e.g., @/components, @/lib, @/entities) instead of long relative paths
Follow import order: React imports, third-party, internal abso...

Files:

  • schemas/user/roadmap-subscription.ts
  • lib/utils/index.ts
  • lib/email/send-waitlist-email.ts
  • components/app/marketing-roadmap-item.tsx
  • components/app/marketing-header-desktop.tsx
  • app/(marketing)/roadmap/page.tsx
  • env.ts
  • components/app/email-waitlist.tsx
  • components/app/marketing-roadmap-subscription.tsx
  • lib/email/send-roadmap-subscription-email.ts
  • lib/email/index.ts
  • components/shared/email-footer.tsx
  • components/app/marketing-roadmap-list.tsx
  • schemas/user/roadmap.ts
  • types/index.d.ts
  • lib/email/resend-client.ts
  • app/(marketing)/page.tsx
  • app/(marketing)/rate-limit-test/page.tsx
  • app/(marketing)/layout.tsx
  • components/app/marketing-waitlist-form.tsx
  • middleware/index.ts
  • orpc/hooks/use-users.ts
  • orpc/types.ts
  • middleware/rate-limit.ts
  • components/app/email-roadmap-subscription.tsx
  • orpc/context.ts
  • orpc/routers/user.ts
  • lib/utils/rate-limit.ts
**/*.{js,ts}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{js,ts}: Don't use __dirname and __filename in the global scope
Use with { type: "json" } for JSON module imports
Don't access namespace imports dynamically
Use node:assert/strict over node:assert
Use the node: protocol for Node.js builtin modules

Files:

  • schemas/user/roadmap-subscription.ts
  • lib/utils/index.ts
  • lib/email/send-waitlist-email.ts
  • env.ts
  • lib/email/send-roadmap-subscription-email.ts
  • lib/email/index.ts
  • schemas/user/roadmap.ts
  • types/index.d.ts
  • lib/email/resend-client.ts
  • middleware/index.ts
  • orpc/hooks/use-users.ts
  • orpc/types.ts
  • middleware/rate-limit.ts
  • orpc/context.ts
  • orpc/routers/user.ts
  • lib/utils/rate-limit.ts
schemas/**/[a-z0-9-]*.ts

📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)

Zod schemas should be placed in the schemas directory and named in kebab-case with .ts

Files:

  • schemas/user/roadmap-subscription.ts
  • schemas/user/roadmap.ts
schemas/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/schemas-folder.mdc)

schemas/**/*.ts: Use Zod for all validation in the /schemas folder (define schemas using z.object, z.enum, z.array, etc.)
Define enum schemas with z.enum and expose the enum and its values (e.g., accountStatusSchema, accountStatusEnum, LIST_*)
Use .optional() for optional fields, .nullable() for DB-nullable fields, and .nullish() for null or undefined
Provide clear, user-friendly validation messages on constraints (e.g., .min, .email)
Validate arrays with z.array(itemSchema); mark arrays optional with .optional() when appropriate
Validate nested objects by composing schemas (e.g., embed encryptedDataDtoSchema; use z.object({...}))
Compose schemas via .extend() and create update shapes via .partial().extend({...})
Reuse base schemas to avoid duplication (e.g., baseKeyValuePairSchema extended for domain-specific variants)
Generate and export TypeScript types from schemas with z.infer and export the types
Name schemas consistently: {entity}DtoSchema, {entity}SimpleRoSchema, {entity}IncludeRoSchema, {entity}FormDtoSchema; types as {Entity}Dto, {Entity}SimpleRo, etc.
Use custom validation with .refine() for complex rules (e.g., password strength) and provide messages
Use conditional validation patterns (schema.refine with path) when one field depends on another (e.g., 2FA code when has2FA)
Export both schemas and their associated types to ensure type-safe usage across the app

Define Zod validation schemas for API and forms under schemas/

schemas/**/*.ts: Define all input/output schemas in the /schemas folder
Export both the Zod schema and its inferred TypeScript type
Provide clear, field-specific, contextual validation error messages in Zod schemas
List endpoint input schemas must include pagination (page, limit), search, and filtering fields with consistent defaults and bounds

Schemas must be named in kebab-case.ts (e.g., credential-form-dto.ts)

Files:

  • schemas/user/roadmap-subscription.ts
  • schemas/user/roadmap.ts
{components,entities,lib,orpc,schemas,hooks,config,types}/**/index.ts

📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)

Use barrel exports: each folder should include an index.ts for clean imports

Files:

  • lib/utils/index.ts
  • lib/email/index.ts
lib/utils/**

📄 CodeRabbit inference engine (.cursor/rules/architecture.mdc)

Place general-purpose utilities under lib/utils/

Files:

  • lib/utils/index.ts
  • lib/utils/rate-limit.ts
**/*.{html,jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{html,jsx,tsx}: Don't use the accessKey attribute on any HTML element
Don't set aria-hidden="true" on focusable elements
Don't add ARIA roles, states, and properties to elements that don't support them
Don't use distracting elements like or
Only use the scope prop on elements
Don't assign non-interactive ARIA roles to interactive HTML elements
Make sure label elements have text content and are associated with an input
Don't assign interactive ARIA roles to non-interactive HTML elements
Don't assign tabIndex to non-interactive HTML elements
Don't use positive integers for the tabIndex property
Don't include "image", "picture", or "photo" in img alt prop
Don't use an explicit role property that's the same as the implicit/default role
Make static elements with click handlers use a valid role attribute
Give all elements requiring alt text meaningful information for screen readers
Make sure anchors have content that's accessible to screen readers
Assign tabIndex to non-interactive HTML elements with aria-activedescendant
Include all required ARIA attributes for elements with ARIA roles
Make sure ARIA properties are valid for the element's supported roles
Always include a type attribute for button elements
Make elements with interactive roles and handlers focusable
Give heading elements content that's accessible to screen readers (not hidden with aria-hidden)
Always include a title attribute for iframe elements
Include caption tracks for audio and video elements
Make sure all anchors are valid and navigable
Ensure all ARIA properties (aria-*) are valid
Use valid, non-abstract ARIA roles for elements with ARIA roles
Use valid ARIA state and property values
Use valid values for the autocomplete attribute on input elements
Use correct ISO language/country codes for the lang attribute
Don't use variables that haven't been declared in the document
Make sure void (self-closing) elements don't have children
Don't use event handlers on non-interactiv...

Files:

  • components/app/marketing-roadmap-item.tsx
  • components/app/marketing-header-desktop.tsx
  • app/(marketing)/roadmap/page.tsx
  • components/app/email-waitlist.tsx
  • components/app/marketing-roadmap-subscription.tsx
  • components/shared/email-footer.tsx
  • components/app/marketing-roadmap-list.tsx
  • app/(marketing)/page.tsx
  • app/(marketing)/rate-limit-test/page.tsx
  • app/(marketing)/layout.tsx
  • components/app/marketing-waitlist-form.tsx
  • components/app/email-roadmap-subscription.tsx
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{jsx,tsx}: Accompany onClick with at least one of: onKeyUp, onKeyDown, or onKeyPress
Accompany onMouseOver/onMouseOut with onFocus/onBlur
Use semantic elements instead of role attributes in JSX
Don't use unnecessary fragments
Don't pass children as props
Don't use the return value of React.render
Make sure all dependencies are correctly specified in React hooks
Make sure all React hooks are called from the top level of component functions
Don't forget key props in iterators and collection literals
Don't define React components inside other components
Don't assign to React component props
Don't use dangerous JSX props
Don't use both children and dangerouslySetInnerHTML props on the same element
Use <>...</> instead of ...
Don't add extra closing tags for components without children
Don't use Array index in keys
Don't insert comments as text nodes
Don't assign JSX properties multiple times
Watch out for possible "wrong" semicolons inside JSX elements
Don't put multiple components in one file; each file must have one component

Files:

  • components/app/marketing-roadmap-item.tsx
  • components/app/marketing-header-desktop.tsx
  • app/(marketing)/roadmap/page.tsx
  • components/app/email-waitlist.tsx
  • components/app/marketing-roadmap-subscription.tsx
  • components/shared/email-footer.tsx
  • components/app/marketing-roadmap-list.tsx
  • app/(marketing)/page.tsx
  • app/(marketing)/rate-limit-test/page.tsx
  • app/(marketing)/layout.tsx
  • components/app/marketing-waitlist-form.tsx
  • components/app/email-roadmap-subscription.tsx
**/*.{html,jsx,tsx,css}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

Don't use TailwindCSS class names 'h-NUMBER w-NUMBER'; instead use 'size-NUMBR'

Files:

  • components/app/marketing-roadmap-item.tsx
  • components/app/marketing-header-desktop.tsx
  • app/(marketing)/roadmap/page.tsx
  • components/app/email-waitlist.tsx
  • components/app/marketing-roadmap-subscription.tsx
  • components/shared/email-footer.tsx
  • components/app/marketing-roadmap-list.tsx
  • app/(marketing)/page.tsx
  • app/(marketing)/rate-limit-test/page.tsx
  • app/(marketing)/layout.tsx
  • components/app/marketing-waitlist-form.tsx
  • components/app/email-roadmap-subscription.tsx
components/app/**

📄 CodeRabbit inference engine (.cursor/rules/components-folder.mdc)

Place application-specific React components under components/app

Files:

  • components/app/marketing-roadmap-item.tsx
  • components/app/marketing-header-desktop.tsx
  • components/app/email-waitlist.tsx
  • components/app/marketing-roadmap-subscription.tsx
  • components/app/marketing-roadmap-list.tsx
  • components/app/marketing-waitlist-form.tsx
  • components/app/email-roadmap-subscription.tsx
components/app/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/components-folder.mdc)

Use naming pattern {feature}-{purpose}-{type}.tsx for app components

Files:

  • components/app/marketing-roadmap-item.tsx
  • components/app/marketing-header-desktop.tsx
  • components/app/email-waitlist.tsx
  • components/app/marketing-roadmap-subscription.tsx
  • components/app/marketing-roadmap-list.tsx
  • components/app/marketing-waitlist-form.tsx
  • components/app/email-roadmap-subscription.tsx
components/app/marketing-*.tsx

📄 CodeRabbit inference engine (.cursor/rules/components-folder.mdc)

Marketing components in components/app must be prefixed with marketing-

Place marketing components under components/app/ with filenames starting marketing-*.tsx

Files:

  • components/app/marketing-roadmap-item.tsx
  • components/app/marketing-header-desktop.tsx
  • components/app/marketing-roadmap-subscription.tsx
  • components/app/marketing-roadmap-list.tsx
  • components/app/marketing-waitlist-form.tsx
components/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/components-folder.mdc)

components/**/*.{ts,tsx}: Always define a TypeScript interface for component props
Follow established naming patterns consistently across files
Use strict, explicit TypeScript types for safety

Files:

  • components/app/marketing-roadmap-item.tsx
  • components/app/marketing-header-desktop.tsx
  • components/app/email-waitlist.tsx
  • components/app/marketing-roadmap-subscription.tsx
  • components/shared/email-footer.tsx
  • components/app/marketing-roadmap-list.tsx
  • components/app/marketing-waitlist-form.tsx
  • components/app/email-roadmap-subscription.tsx
components/**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/components-folder.mdc)

components/**/*.tsx: Add 'use client' directive for components that use client-side hooks/effects
Use cn() for conditional Tailwind classes
Use semantic Tailwind colors (e.g., text-foreground, bg-background) and consistent spacing (space-y-4, gap-4)
Use responsive Tailwind prefixes (md:, lg:, xl:) for adaptive layouts
Define component variants with cva and defaultVariants when variants are needed
Prefer useState for local state; use useReducer for complex state
Use TanStack Query hooks from /orpc/hooks for server state; prefer server-side data fetching when possible
Implement proper ARIA attributes and keyboard navigation for accessibility
Use React.memo for expensive components
Use useMemo and useCallback for expensive computations and stable callbacks
Lazy-load heavy components via dynamic import
Import only needed icons from lucide-react (no wildcard imports)
Wrap components that might fail in Error Boundaries
Provide loading and error states for async UI
Add JSDoc comments for complex components

components/**/*.tsx: Components must be named in kebab-case.tsx (e.g., dashboard-credential-form.tsx)
Use React Hook Form for form management in UI forms
Use React Hook Form error handling, display validation errors, and handle submission errors gracefully in forms

Files:

  • components/app/marketing-roadmap-item.tsx
  • components/app/marketing-header-desktop.tsx
  • components/app/email-waitlist.tsx
  • components/app/marketing-roadmap-subscription.tsx
  • components/shared/email-footer.tsx
  • components/app/marketing-roadmap-list.tsx
  • components/app/marketing-waitlist-form.tsx
  • components/app/email-roadmap-subscription.tsx
components/**/[a-z0-9-]*.tsx

📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)

Name React components in kebab-case with .tsx under the components directory (e.g., dashboard-credential-form.tsx)

Files:

  • components/app/marketing-roadmap-item.tsx
  • components/app/marketing-header-desktop.tsx
  • components/app/email-waitlist.tsx
  • components/app/marketing-roadmap-subscription.tsx
  • components/shared/email-footer.tsx
  • components/app/marketing-roadmap-list.tsx
  • components/app/marketing-waitlist-form.tsx
  • components/app/email-roadmap-subscription.tsx
components/{app,layout,shared,ui}/**

📄 CodeRabbit inference engine (.cursor/rules/architecture.mdc)

Organize React components under components/app, components/layout, components/shared, and components/ui

Files:

  • components/app/marketing-roadmap-item.tsx
  • components/app/marketing-header-desktop.tsx
  • components/app/email-waitlist.tsx
  • components/app/marketing-roadmap-subscription.tsx
  • components/shared/email-footer.tsx
  • components/app/marketing-roadmap-list.tsx
  • components/app/marketing-waitlist-form.tsx
  • components/app/email-roadmap-subscription.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/zero-locker-patterns.mdc)

**/*.tsx: Use Component Composition Pattern: build complex UI by composing smaller, reusable components (e.g., Form, FormField, FormItem)
Handle form errors with React Hook Form and Zod resolver for client-side validation
Avoid direct database access in React components; use hooks/services instead

**/*.tsx: Use PascalCase for React component names
Use functional components only, typed with explicit props interfaces
Optimize components using React.memo for expensive components, useMemo for heavy computations, and useCallback for stable handlers

**/*.tsx: Never use useState for form state; use React Hook Form (useForm) instead
Always use Zod schemas with zodResolver for form validation
Always use shadcn Form components: Form, FormField, FormItem, FormLabel, FormControl, FormMessage
Always use Icons.spinner with animate-spin for loading states
Never use text like "Deleting..." or "Loading..." for loading states
Use size-4 instead of h-4 w-4 for spinner sizing (Tailwind)
Disable buttons during loading: disabled={isLoading}
Show spinner + text inside buttons when loading
Use Button variant="destructive" for delete actions
Add disabled opacity class to buttons: className="disabled:opacity-50"
Avoid manual form validation; rely on Zod + resolver integration

Files:

  • components/app/marketing-roadmap-item.tsx
  • components/app/marketing-header-desktop.tsx
  • app/(marketing)/roadmap/page.tsx
  • components/app/email-waitlist.tsx
  • components/app/marketing-roadmap-subscription.tsx
  • components/shared/email-footer.tsx
  • components/app/marketing-roadmap-list.tsx
  • app/(marketing)/page.tsx
  • app/(marketing)/rate-limit-test/page.tsx
  • app/(marketing)/layout.tsx
  • components/app/marketing-waitlist-form.tsx
  • components/app/email-roadmap-subscription.tsx
app/**/page.tsx

📄 CodeRabbit inference engine (.cursor/rules/app-folder.mdc)

Page files must be named page.tsx and define the page component and metadata

Page components in the Next.js App Router must be named page.tsx

Pages must be named page.tsx

Files:

  • app/(marketing)/roadmap/page.tsx
  • app/(marketing)/page.tsx
  • app/(marketing)/rate-limit-test/page.tsx
app/**/[(]*[)]/**

📄 CodeRabbit inference engine (.cursor/rules/app-folder.mdc)

Use parentheses-named folders (group) to create route groups that don’t affect the URL

Files:

  • app/(marketing)/roadmap/page.tsx
  • app/(marketing)/page.tsx
  • app/(marketing)/rate-limit-test/page.tsx
  • app/(marketing)/layout.tsx
app/**/{page,layout}.tsx

📄 CodeRabbit inference engine (.cursor/rules/app-folder.mdc)

app/**/{page,layout}.tsx: Export a Metadata object as export const metadata in pages and layouts
Perform server-side data fetching in pages and layouts where possible

Files:

  • app/(marketing)/roadmap/page.tsx
  • app/(marketing)/page.tsx
  • app/(marketing)/rate-limit-test/page.tsx
  • app/(marketing)/layout.tsx
app/**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/app-folder.mdc)

app/**/*.tsx: Prefer Server Components by default in the app directory
Add "use client" only when necessary for Client Components

Files:

  • app/(marketing)/roadmap/page.tsx
  • app/(marketing)/page.tsx
  • app/(marketing)/rate-limit-test/page.tsx
  • app/(marketing)/layout.tsx
app/(marketing)/**

📄 CodeRabbit inference engine (.cursor/rules/architecture.mdc)

Place marketing and landing content within app/(marketing)/

Files:

  • app/(marketing)/roadmap/page.tsx
  • app/(marketing)/page.tsx
  • app/(marketing)/rate-limit-test/page.tsx
  • app/(marketing)/layout.tsx
components/shared/**

📄 CodeRabbit inference engine (.cursor/rules/components-folder.mdc)

Place reusable shared components under components/shared

Files:

  • components/shared/email-footer.tsx
components/{layout,shared,ui}/**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/zero-locker-rules.mdc)

Organize layout, shared, and base UI components under components/layout, components/shared, and components/ui

Files:

  • components/shared/email-footer.tsx
types/**/[a-z0-9-]*.d.ts

📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)

Type declaration files should be named in kebab-case with a .d.ts extension under the types directory

Files:

  • types/index.d.ts
types/**/*.d.ts

📄 CodeRabbit inference engine (.cursor/rules/types-folder.mdc)

types/**/*.d.ts: Group related types in the same file
Use descriptive names for types and interfaces
Export types as named exports
Define interfaces for all complex objects
Use type guards for runtime type checking
Create generic types for common patterns
Use utility types for transformations
Extend base interfaces for specific use cases
Add JSDoc comments for complex types
Document type parameters and constraints
Provide examples for complex types
Avoid circular type dependencies
Use conditional types sparingly
Use consistent naming conventions

Files:

  • types/index.d.ts
types/**

📄 CodeRabbit inference engine (.cursor/rules/architecture.mdc)

Keep shared TypeScript type definitions under types/

Files:

  • types/index.d.ts
**/*.d.ts

📄 CodeRabbit inference engine (.cursor/rules/zero-locker-rules.mdc)

Types definition files must be named in kebab-case.d.ts (e.g., dashboard.d.ts)

Files:

  • types/index.d.ts
{.env,.env.*}

📄 CodeRabbit inference engine (.cursor/rules/prisma-folder.mdc)

Configure DATABASE_URL for each environment in .env files (development/production)

Files:

  • .env.example
prisma/schema/!(schema).prisma

📄 CodeRabbit inference engine (.cursor/rules/prisma-folder.mdc)

Organize each entity/model into its own .prisma file under prisma/schema (multi-file schema)

Files:

  • prisma/schema/auth.prisma
prisma/schema/!(schema|enums).prisma

📄 CodeRabbit inference engine (.cursor/rules/prisma-folder.mdc)

prisma/schema/!(schema|enums).prisma: Follow base model conventions: id as String @id @default(cuid()), createdAt @default(now()), updatedAt @updatedat, status enum default ACTIVE, userId + User relation, and snake_case @@Map
Add indexes for frequently queried fields and foreign keys; use composite unique indexes when needed
Define relationships with proper @relation fields, foreign key references, and cascade deletes where appropriate
Choose appropriate data types, model nullability correctly, and prefer enums for status fields

Files:

  • prisma/schema/auth.prisma
prisma/schema/**

📄 CodeRabbit inference engine (.cursor/rules/architecture.mdc)

Maintain a multi-file Prisma schema under prisma/schema/

Files:

  • prisma/schema/auth.prisma
  • prisma/schema/migrations/20251018210700_added_roadmap_subscription/migration.sql
app/**/layout.tsx

📄 CodeRabbit inference engine (.cursor/rules/app-folder.mdc)

Layout files must be named layout.tsx and define shared UI/metadata for their segment

Files:

  • app/(marketing)/layout.tsx
app/**/[(]*[)]/layout.tsx

📄 CodeRabbit inference engine (.cursor/rules/app-folder.mdc)

Each route group can define its own layout.tsx for group-specific UI

Files:

  • app/(marketing)/layout.tsx
components/**/*-form.tsx

📄 CodeRabbit inference engine (.cursor/rules/components-folder.mdc)

components/**/*-form.tsx: Form components should follow the standard props interface (data?, form: UseFormReturn, onSubmit?, onCancel?)
Use React Hook Form with Zod validation for forms; keep schemas in /schemas

Files:

  • components/app/marketing-waitlist-form.tsx
middleware/index.ts

📄 CodeRabbit inference engine (.cursor/rules/middleware-folder.mdc)

middleware/index.ts: Protect /dashboard routes in Next.js middleware by checking the better-auth.session_token cookie and redirect unauthenticated users to /login
Redirect authenticated users away from auth routes (/login, /register) to /dashboard in Next.js middleware
Add CORS headers for /api/orpc routes in Next.js middleware (Allow-Origin: , Methods: GET, POST, PUT, PATCH, DELETE, OPTIONS; Headers: Content-Type, Authorization)
Export Next.js middleware config matcher for "/dashboard/:path
" and "/api/orpc/:path*"

Files:

  • middleware/index.ts
middleware/**

📄 CodeRabbit inference engine (.cursor/rules/architecture.mdc)

Implement authentication and permission access control middleware under middleware/

Files:

  • middleware/index.ts
  • middleware/rate-limit.ts
orpc/hooks/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/orpc-folder.mdc)

orpc/hooks/**/*.ts: Create React Query hooks that call orpc client methods with stable queryKey factories
Use enabled flags for queries that depend on optional parameters (e.g., only fetch detail when id is truthy)
On successful mutations, invalidate relevant list queries and update detail cache via setQueryData when possible
Centralize query keys with a factory (e.g., entityKeys) to ensure consistent cache keys across hooks

Use TanStack Query for server state in hooks

Files:

  • orpc/hooks/use-users.ts
orpc/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)

Ensure consistent error handling and responses within oRPC routes and client code

orpc/**/*.ts: Use oRPC standard error codes (ORPCError) with meaningful, contextual messages
Handle specific error types (e.g., Prisma codes), log errors, and map to appropriate ORPC error codes
Use FORBIDDEN for permission errors; include feature and action in the message and upgrade info when applicable

Always encrypt passwords before storage in server-side handlers/services

Files:

  • orpc/hooks/use-users.ts
  • orpc/types.ts
  • orpc/context.ts
  • orpc/routers/user.ts
orpc/hooks/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/architecture.mdc)

Place React Query hooks for API calls under orpc/hooks/

Files:

  • orpc/hooks/use-users.ts
**/use-*.ts

📄 CodeRabbit inference engine (.cursor/rules/zero-locker-rules.mdc)

Hooks files must be named use-kebab-case.ts (e.g., use-copy-to-clipboard.ts)

Files:

  • orpc/hooks/use-users.ts
orpc/hooks/use-*.ts

📄 CodeRabbit inference engine (.cursor/rules/zero-locker-rules.mdc)

Place oRPC-related hooks under orpc/hooks with use-*.ts naming

Files:

  • orpc/hooks/use-users.ts
orpc/types.ts

📄 CodeRabbit inference engine (.cursor/rules/orpc-folder.mdc)

Define and export ORPCContext, AuthenticatedContext, and PublicContext to type middleware and handlers

Files:

  • orpc/types.ts
orpc/context.ts

📄 CodeRabbit inference engine (.cursor/rules/orpc-folder.mdc)

Implement createContext to read the current session/user and return nulls on failure; log failures without throwing

Files:

  • orpc/context.ts
orpc/routers/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/orpc-folder.mdc)

orpc/routers/**/*.ts: In oRPC routers, build procedures using os.$context(), then compose authProcedure and permissionProcedure via .use(...) middleware chaining
Define routes with .input(zodSchema).output(zodSchema).handler(async (...) => { ... }) to enforce schema-validated inputs/outputs
For list endpoints, implement pagination (page, limit), deterministic orderBy, and compute total/hasMore
Apply authMiddleware to protected routes and requirePermission(feature, action) where feature-gated access is needed
Use ORPCError with standard codes (e.g., UNAUTHORIZED, FORBIDDEN, NOT_FOUND, BAD_REQUEST) for predictable error handling
Map known ORM errors (e.g., Prisma P2002) to meaningful ORPCError codes like CONFLICT and fall back to INTERNAL_SERVER_ERROR
Always validate inputs with Zod schemas and define explicit output schemas; handle validation errors gracefully
Never expose sensitive fields in responses; use client-safe entity transformations and selective include projections
Group related procedures in a single router file and use consistent naming for routes and files
Use include helpers (e.g., EntityQuery.getClientSafeInclude()) to fetch only client-safe relations
Use server-side caching or efficient queries where appropriate; prefer pagination over large result sets
Return deterministic ordering for list endpoints (e.g., orderBy createdAt desc)
Provide meaningful error messages when throwing BAD_REQUEST/CONFLICT while avoiding sensitive details

orpc/routers/**/*.ts: Group routes by feature (e.g., credentialRouter, cardRouter) in dedicated router files
Use descriptive, action-indicative procedure names within routers
Use action-based names: create, getById, list, update, delete
Keep procedure names consistent across all routers
Use camelCase for procedure names
Use Zod schemas for all procedure inputs via .input(schema)
List procedures must return metadata (total, hasMore, page, limit) alongside data
Apply authentication middleware to all protecte...

Files:

  • orpc/routers/user.ts
orpc/routers/{credential,card,secret,user}.ts

📄 CodeRabbit inference engine (.cursor/rules/architecture.mdc)

Define oRPC routers in orpc/routers/ with files credential.ts, card.ts, secret.ts, and user.ts

Files:

  • orpc/routers/user.ts
orpc/routers/**/!(*index).ts

📄 CodeRabbit inference engine (.cursor/rules/orpc-patterns.mdc)

Export routers individually from their own files

Files:

  • orpc/routers/user.ts
orpc/routers/*.ts

📄 CodeRabbit inference engine (.cursor/rules/zero-locker-rules.mdc)

Define route handlers in orpc/routers with one file per domain (e.g., credential.ts, card.ts)

Files:

  • orpc/routers/user.ts
🧠 Learnings (12)
📚 Learning: 2025-10-02T22:19:00.164Z
Learnt from: CR
PR: FindMalek/zero-locker#0
File: .cursor/rules/orpc-patterns.mdc:0-0
Timestamp: 2025-10-02T22:19:00.164Z
Learning: Applies to orpc/**/*.ts : Use oRPC standard error codes (ORPCError) with meaningful, contextual messages

Applied to files:

  • lib/utils/index.ts
📚 Learning: 2025-10-02T21:03:44.148Z
Learnt from: CR
PR: FindMalek/zero-locker#0
File: .cursor/rules/project-overview.mdc:0-0
Timestamp: 2025-10-02T21:03:44.148Z
Learning: Applies to orpc/**/*.ts : Ensure consistent error handling and responses within oRPC routes and client code

Applied to files:

  • lib/utils/index.ts
📚 Learning: 2025-10-02T22:19:00.164Z
Learnt from: CR
PR: FindMalek/zero-locker#0
File: .cursor/rules/orpc-patterns.mdc:0-0
Timestamp: 2025-10-02T22:19:00.164Z
Learning: Applies to orpc/**/*.ts : Handle specific error types (e.g., Prisma codes), log errors, and map to appropriate ORPC error codes

Applied to files:

  • lib/utils/index.ts
📚 Learning: 2025-10-02T21:01:44.094Z
Learnt from: CR
PR: FindMalek/zero-locker#0
File: .cursor/rules/orpc-folder.mdc:0-0
Timestamp: 2025-10-02T21:01:44.094Z
Learning: Applies to orpc/routers/**/*.ts : Use ORPCError with standard codes (e.g., UNAUTHORIZED, FORBIDDEN, NOT_FOUND, BAD_REQUEST) for predictable error handling

Applied to files:

  • lib/utils/index.ts
📚 Learning: 2025-10-02T22:21:11.735Z
Learnt from: CR
PR: FindMalek/zero-locker#0
File: .cursor/rules/zero-locker-rules.mdc:0-0
Timestamp: 2025-10-02T22:21:11.735Z
Learning: Applies to orpc/routers/**/*.ts : Use standard error codes (oRPCError), provide meaningful messages, and log errors in API handlers

Applied to files:

  • lib/utils/index.ts
📚 Learning: 2025-10-02T20:56:15.975Z
Learnt from: CR
PR: FindMalek/zero-locker#0
File: .cursor/rules/components-folder.mdc:0-0
Timestamp: 2025-10-02T20:56:15.975Z
Learning: Applies to components/app/marketing-*.tsx : Marketing components in components/app must be prefixed with marketing-

Applied to files:

  • components/app/marketing-roadmap-item.tsx
  • app/(marketing)/page.tsx
  • app/(marketing)/layout.tsx
📚 Learning: 2025-10-02T20:55:02.956Z
Learnt from: CR
PR: FindMalek/zero-locker#0
File: .cursor/rules/app-folder.mdc:0-0
Timestamp: 2025-10-02T20:55:02.956Z
Learning: Applies to app/**/{page,layout}.tsx : Export a Metadata object as `export const metadata` in pages and layouts

Applied to files:

  • app/(marketing)/roadmap/page.tsx
📚 Learning: 2025-10-02T20:55:02.956Z
Learnt from: CR
PR: FindMalek/zero-locker#0
File: .cursor/rules/app-folder.mdc:0-0
Timestamp: 2025-10-02T20:55:02.956Z
Learning: Use required environment variables: NEXT_PUBLIC_APP_URL, BETTER_AUTH_SECRET, DATABASE_URL, NODE_ENV

Applied to files:

  • env.ts
  • .env.example
📚 Learning: 2025-10-02T22:21:11.735Z
Learnt from: CR
PR: FindMalek/zero-locker#0
File: .cursor/rules/zero-locker-rules.mdc:0-0
Timestamp: 2025-10-02T22:21:11.735Z
Learning: Applies to components/app/marketing-*.tsx : Place marketing components under components/app/ with filenames starting marketing-*.tsx

Applied to files:

  • app/(marketing)/page.tsx
  • app/(marketing)/layout.tsx
📚 Learning: 2025-10-02T21:01:02.677Z
Learnt from: CR
PR: FindMalek/zero-locker#0
File: .cursor/rules/middleware-folder.mdc:0-0
Timestamp: 2025-10-02T21:01:02.677Z
Learning: Applies to middleware/auth.ts : Provide a publicMiddleware that passes through without authentication requirements

Applied to files:

  • middleware/index.ts
📚 Learning: 2025-10-02T21:01:44.094Z
Learnt from: CR
PR: FindMalek/zero-locker#0
File: .cursor/rules/orpc-folder.mdc:0-0
Timestamp: 2025-10-02T21:01:44.094Z
Learning: Applies to orpc/types.ts : Define and export ORPCContext, AuthenticatedContext, and PublicContext to type middleware and handlers

Applied to files:

  • orpc/types.ts
  • middleware/rate-limit.ts
  • orpc/context.ts
📚 Learning: 2025-10-02T21:01:44.094Z
Learnt from: CR
PR: FindMalek/zero-locker#0
File: .cursor/rules/orpc-folder.mdc:0-0
Timestamp: 2025-10-02T21:01:44.094Z
Learning: Applies to orpc/context.ts : Implement createContext to read the current session/user and return nulls on failure; log failures without throwing

Applied to files:

  • orpc/context.ts
🧬 Code graph analysis (20)
lib/email/send-waitlist-email.ts (3)
lib/email/resend-client.ts (1)
  • resendClient (5-5)
env.ts (1)
  • env (4-27)
components/app/email-waitlist.tsx (1)
  • EmailWaitlist (25-90)
components/app/marketing-header-desktop.tsx (2)
components/shared/icons.tsx (1)
  • Icons (139-262)
config/site.ts (1)
  • siteConfig (3-41)
app/(marketing)/roadmap/page.tsx (4)
config/site.ts (1)
  • siteConfig (3-41)
types/index.d.ts (1)
  • RoadmapItem (61-65)
components/app/marketing-roadmap-list.tsx (1)
  • MarketingRoadmapList (15-69)
components/app/marketing-roadmap-subscription.tsx (1)
  • MarketingRoadmapSubscription (29-146)
components/app/email-waitlist.tsx (2)
config/site.ts (1)
  • siteConfig (3-41)
components/shared/email-footer.tsx (1)
  • EmailFooter (14-42)
components/app/marketing-roadmap-subscription.tsx (3)
orpc/hooks/use-users.ts (1)
  • useSubscribeToRoadmap (94-101)
lib/utils/index.ts (1)
  • handleORPCError (199-234)
components/shared/icons.tsx (1)
  • Icons (139-262)
lib/email/send-roadmap-subscription-email.ts (3)
lib/email/resend-client.ts (1)
  • resendClient (5-5)
env.ts (1)
  • env (4-27)
components/app/email-roadmap-subscription.tsx (1)
  • EmailRoadmapSubscription (24-106)
components/shared/email-footer.tsx (1)
config/site.ts (1)
  • siteConfig (3-41)
components/app/marketing-roadmap-list.tsx (3)
types/index.d.ts (1)
  • RoadmapItem (61-65)
components/app/marketing-roadmap-item.tsx (1)
  • MarketingRoadmapItem (7-44)
components/shared/icons.tsx (1)
  • Icons (139-262)
schemas/user/roadmap.ts (1)
schemas/user/roadmap-subscription.ts (4)
  • subscribeToRoadmapInputSchema (4-6)
  • SubscribeToRoadmapInput (8-10)
  • subscribeToRoadmapOutputSchema (13-16)
  • SubscribeToRoadmapOutput (18-20)
lib/email/resend-client.ts (1)
env.ts (1)
  • env (4-27)
app/(marketing)/page.tsx (4)
components/app/marketing-hero.tsx (1)
  • MarketingHero (29-98)
components/app/marketing-stats.tsx (1)
  • MarketingStats (7-34)
components/app/marketing-features.tsx (1)
  • MarketingFeatures (9-105)
components/app/marketing-how-it-works.tsx (1)
  • MarketingHowItWorks (1-57)
app/(marketing)/rate-limit-test/page.tsx (2)
orpc/hooks/use-users.ts (4)
  • useUserCount (58-64)
  • useWaitlistCount (48-55)
  • useEncryptedDataCount (67-73)
  • useJoinWaitlist (28-45)
lib/utils/index.ts (1)
  • handleORPCError (199-234)
app/(marketing)/layout.tsx (3)
components/ui/animated-grid-pattern.tsx (1)
  • AnimatedGridPattern (27-157)
components/app/marketing-header-desktop.tsx (1)
  • MarketingHeaderDesktop (12-42)
components/app/marketing-footer.tsx (1)
  • MarketingFooter (5-21)
components/app/marketing-waitlist-form.tsx (1)
lib/utils/index.ts (1)
  • handleORPCError (199-234)
orpc/hooks/use-users.ts (1)
orpc/client/utils.ts (1)
  • orpc (5-7)
orpc/types.ts (1)
types/dashboard.d.ts (1)
  • User (1-9)
middleware/rate-limit.ts (2)
lib/utils/rate-limit.ts (3)
  • RateLimitConfig (14-29)
  • checkRateLimit (159-224)
  • RATE_LIMIT_PRESETS (258-279)
orpc/types.ts (1)
  • PublicContext (35-35)
components/app/email-roadmap-subscription.tsx (2)
config/site.ts (1)
  • siteConfig (3-41)
components/shared/email-footer.tsx (1)
  • EmailFooter (14-42)
orpc/context.ts (1)
orpc/types.ts (1)
  • ORPCContext (14-28)
orpc/routers/user.ts (6)
orpc/types.ts (1)
  • ORPCContext (14-28)
middleware/rate-limit.ts (3)
  • lenientRateLimit (94-99)
  • strictRateLimit (72-77)
  • moderateRateLimit (83-88)
middleware/auth.ts (1)
  • authMiddleware (15-33)
lib/email/send-waitlist-email.ts (1)
  • sendWaitlistEmail (12-34)
schemas/user/roadmap.ts (3)
  • subscribeToRoadmapInputSchema (4-6)
  • subscribeToRoadmapOutputSchema (13-16)
  • SubscribeToRoadmapOutput (18-20)
lib/email/send-roadmap-subscription-email.ts (1)
  • sendRoadmapSubscriptionEmail (11-32)
🪛 dotenv-linter (3.3.0)
.env.example

[warning] 14-14: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 15-15: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 15-15: [UnorderedKey] The LOGO_DEV_TOKEN key should go before the NEXT_PUBLIC_LOGO_DEV_TOKEN key

(UnorderedKey)


[warning] 18-18: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 19-19: [EndingBlankLine] No blank line at the end of the file

(EndingBlankLine)


[warning] 19-19: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 19-19: [UnorderedKey] The MARKETING_SUBSCRIPTION_EMAIL key should go before the RESEND_API_KEY key

(UnorderedKey)

Comment on lines +3 to +20
// Input schema for subscribing to roadmap updates
export const subscribeToRoadmapInputSchema = z.object({
email: z.string().min(1, "Email is required").email("Invalid email address"),
})

export type SubscribeToRoadmapInput = z.infer<
typeof subscribeToRoadmapInputSchema
>

// Output schema for roadmap subscription
export const subscribeToRoadmapOutputSchema = z.object({
success: z.boolean(),
error: z.string().optional(),
})

export type SubscribeToRoadmapOutput = z.infer<
typeof subscribeToRoadmapOutputSchema
>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Possible duplicate schemas with schemas/user/roadmap-subscription.ts — consolidate.

This file appears to duplicate subscribe input/output already defined in schemas/user/roadmap-subscription.ts. Keep a single source of truth (prefer roadmap-subscription.ts), and re-export if you need a different path.


🏁 Script executed:

#!/bin/bash
# List all definitions/usages to confirm duplication
rg -nP 'subscribeToRoadmap(Input|Output)Schema|SubscribeToRoadmap(Input|Output)' -C2

Length of output: 3268


Consolidate duplicate schema definitions — remove roadmap.ts or migrate import to roadmap-subscription.ts.

The duplication is confirmed. Both schemas/user/roadmap.ts and schemas/user/roadmap-subscription.ts define identical subscribeToRoadmapInputSchema, subscribeToRoadmapOutputSchema, and their associated types. The codebase currently imports from roadmap.ts (referenced in orpc/routers/user.ts:9-13).

To maintain a single source of truth, either:

  • Remove the duplicate definitions from roadmap.ts and update orpc/routers/user.ts to import from roadmap-subscription.ts, or
  • Remove roadmap-subscription.ts entirely if roadmap.ts is the preferred location.
🤖 Prompt for AI Agents
In schemas/user/roadmap.ts around lines 3-20, duplicate schema/type definitions
exist that are already defined in schemas/user/roadmap-subscription.ts; remove
the duplicate definitions from roadmap.ts and update any files that currently
import from roadmap.ts (notably orpc/routers/user.ts lines 9-13) to import the
schemas and types from schemas/user/roadmap-subscription.ts instead, ensuring
named exports match and running a quick search/replace across the repo to update
all imports and then run type checks/tests to confirm no broken imports remain.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Please checkout this Remove rate-limit-test related

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Please checkout this Remove rate-limit-test related

@FindMalek FindMalek merged commit 051af51 into main Oct 18, 2025
2 of 3 checks passed
@FindMalek FindMalek deleted the findmalek/fin-49-roadmap-page branch October 18, 2025 23:43
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

♻️ Duplicate comments (6)
orpc/routers/user.ts (4)

107-157: Replace console.error with structured logging in error handlers.

Lines 108, 131, 142, and 152 use console.error for error logging, violating coding guidelines. Error objects may contain sensitive data. Implement structured logging with appropriate redaction.

As per coding guidelines


337-340: Replace console.error with structured logging.

Line 338 uses console.error, violating coding guidelines. Implement structured logging for error tracking.

As per coding guidelines


2-6: Remove unused moderateRateLimit import.

moderateRateLimit is imported on line 4 but never used in any exported procedure. Remove the unused import to avoid dead code.

As per coding guidelines


88-97: Replace console.error with structured logging.

Line 95 uses console.error, which violates coding guidelines for TypeScript files. Error objects may contain PII (email addresses). Implement structured logging with PII redaction.

As per coding guidelines

lib/email/send-waitlist-email.ts (1)

25-28: Replace console.error with structured logging.

Lines 26 and 32 use console.error, which violates coding guidelines for TypeScript files. Additionally, error objects may contain PII (email addresses). Implement structured logging (e.g., pino) and ensure sensitive fields are redacted.

As per coding guidelines

lib/email/send-roadmap-subscription-email.ts (1)

23-26: Replace console.error with structured logging.

Lines 24 and 30 use console.error, violating coding guidelines for TypeScript files. Error objects may expose PII (email addresses). Implement structured logging with PII redaction.

As per coding guidelines

🧹 Nitpick comments (3)
entities/utils/tag/entity.ts (2)

1-2: Use type‑only imports for types.

Both imports appear to be types; mark them with import type to reduce runtime overhead and align with our TS import rules. As per coding guidelines.

-import { TagEntitySimpleDbData } from "@/entities/utils/tag/query"
-import { TagSimpleRo } from "@/schemas/utils/tag"
+import type { TagEntitySimpleDbData } from "@/entities/utils/tag/query"
+import type { TagSimpleRo } from "@/schemas/utils/tag"

5-15: Confirm Simple RO shape and handle potential nullables.

  • Do we intentionally exclude timestamps (createdAt/updatedAt) from Simple RO for tags, or should they be included for consistency across entities? Please confirm the project convention.
  • If any of color, userId, or containerId can be nullable in DB, defensively handle them (optional chaining / defaults) to keep RO stable. Based on learnings.
lib/email/send-roadmap-subscription-email.ts (1)

12-32: Consider extracting common email sending logic.

This function shares nearly identical structure with sendWaitlistEmail in lib/email/send-waitlist-email.ts (try/catch pattern, error checking, logging, rethrow). Consider creating a shared helper function that accepts the email parameters to reduce duplication and improve maintainability.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 99dc5da and 5e9c0f8.

📒 Files selected for processing (20)
  • components/app/marketing-roadmap-item.tsx (1 hunks)
  • components/app/marketing-roadmap-list.tsx (1 hunks)
  • config/converter.tsx (2 hunks)
  • entities/card/card/entity.ts (1 hunks)
  • entities/credential/credential-history/entity.ts (1 hunks)
  • entities/credential/credential-key-value/entity.ts (1 hunks)
  • entities/credential/credential-metadata/entity.ts (1 hunks)
  • entities/credential/credential/entity.ts (1 hunks)
  • entities/encryption/entity.ts (1 hunks)
  • entities/secrets/secret/entity.ts (1 hunks)
  • entities/utils/container/entity.ts (1 hunks)
  • entities/utils/tag/entity.ts (1 hunks)
  • lib/auth/verify.ts (1 hunks)
  • lib/email/send-roadmap-subscription-email.ts (1 hunks)
  • lib/email/send-waitlist-email.ts (1 hunks)
  • lib/utils/index.ts (1 hunks)
  • lib/utils/rate-limit.ts (1 hunks)
  • middleware/rate-limit.ts (1 hunks)
  • orpc/context.ts (1 hunks)
  • orpc/routers/user.ts (5 hunks)
✅ Files skipped from review due to trivial changes (2)
  • entities/card/card/entity.ts
  • entities/credential/credential-history/entity.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • orpc/context.ts
  • middleware/rate-limit.ts
  • lib/utils/index.ts
🧰 Additional context used
📓 Path-based instructions (28)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{js,jsx,ts,tsx}: Don't use consecutive spaces in regular expression literals
Don't use the arguments object
Don't use the comma operator
Don't write functions that exceed a given Cognitive Complexity score
Don't use unnecessary boolean casts
Don't use unnecessary callbacks with flatMap
Use for...of statements instead of Array.forEach
Don't create classes that only have static members
Don't use this and super in static contexts
Don't use unnecessary catch clauses
Don't use unnecessary constructors
Don't use unnecessary continue statements
Don't export empty modules that don't change anything
Don't use unnecessary escape sequences in regular expression literals
Don't use unnecessary labels
Don't use unnecessary nested block statements
Don't rename imports, exports, and destructured assignments to the same name
Don't use unnecessary string or template literal concatenation
Don't use String.raw in template literals when there are no escape sequences
Don't use useless case statements in switch statements
Don't use ternary operators when simpler alternatives exist
Don't use useless this aliasing
Don't initialize variables to undefined
Don't use void operators
Use arrow functions instead of function expressions
Use Date.now() to get milliseconds since the Unix Epoch
Use .flatMap() instead of map().flat() when possible
Use literal property access instead of computed property access
Don't use parseInt() or Number.parseInt() when binary, octal, or hexadecimal literals work
Use concise optional chaining instead of chained logical expressions
Use regular expression literals instead of the RegExp constructor when possible
Don't use number literal object member names that aren't base 10 or use underscore separators
Remove redundant terms from logical expressions
Use while loops instead of for loops when you don't need initializer and update expressions
Don't reassign const variables
Don't use constant expressions in conditions
Don't use Math.min and Math.max to clamp value...

Files:

  • lib/email/send-waitlist-email.ts
  • entities/credential/credential-key-value/entity.ts
  • entities/secrets/secret/entity.ts
  • entities/credential/credential/entity.ts
  • entities/utils/container/entity.ts
  • config/converter.tsx
  • components/app/marketing-roadmap-list.tsx
  • lib/email/send-roadmap-subscription-email.ts
  • entities/encryption/entity.ts
  • orpc/routers/user.ts
  • lib/utils/rate-limit.ts
  • entities/credential/credential-metadata/entity.ts
  • lib/auth/verify.ts
  • components/app/marketing-roadmap-item.tsx
  • entities/utils/tag/entity.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{ts,tsx}: Don't use primitive type aliases or misleading types
Don't use empty type parameters in type aliases and interfaces
Don't use any or unknown as type constraints
Don't return a value from a function that has a 'void' return type
Don't use the TypeScript directive @ts-ignore
Make sure switch-case statements are exhaustive
Don't use TypeScript enums
Don't add type annotations to variables, parameters, and class properties that are initialized with literal expressions
Don't use TypeScript namespaces
Don't use non-null assertions with the ! postfix operator
Don't use parameter properties in class constructors
Don't use user-defined types
Use as const instead of literal types and type annotations
Use either T[] or Array consistently
Use consistent accessibility modifiers on class properties and methods
Put default function parameters and optional function parameters last
Initialize each enum member value explicitly
Use export type for types
Use import type for types
Make sure all enum members are literal values
Use function types instead of object types with call signatures
Don't use void type outside of generic or return types
Don't use TypeScript const enum
Don't declare empty interfaces
Don't let variables evolve into any type through reassignments
Don't use the any type
Don't misuse the non-null assertion operator (!) in TypeScript files
Don't use implicit any type on variable declarations
Don't merge interfaces and classes unsafely
Don't use overload signatures that aren't next to each other
Use the namespace keyword instead of the module keyword to declare TypeScript namespaces

Use type-only imports when possible

**/*.{ts,tsx}: Use camelCase for function and method names
Use UPPER_SNAKE_CASE for constants
Use camelCase for variables
Use PascalCase for classes and types
Use absolute imports for top-level modules (e.g., @/components, @/lib, @/entities) instead of long relative paths
Follow import order: React imports, third-party, internal abso...

Files:

  • lib/email/send-waitlist-email.ts
  • entities/credential/credential-key-value/entity.ts
  • entities/secrets/secret/entity.ts
  • entities/credential/credential/entity.ts
  • entities/utils/container/entity.ts
  • config/converter.tsx
  • components/app/marketing-roadmap-list.tsx
  • lib/email/send-roadmap-subscription-email.ts
  • entities/encryption/entity.ts
  • orpc/routers/user.ts
  • lib/utils/rate-limit.ts
  • entities/credential/credential-metadata/entity.ts
  • lib/auth/verify.ts
  • components/app/marketing-roadmap-item.tsx
  • entities/utils/tag/entity.ts
**/*.{js,ts}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{js,ts}: Don't use __dirname and __filename in the global scope
Use with { type: "json" } for JSON module imports
Don't access namespace imports dynamically
Use node:assert/strict over node:assert
Use the node: protocol for Node.js builtin modules

Files:

  • lib/email/send-waitlist-email.ts
  • entities/credential/credential-key-value/entity.ts
  • entities/secrets/secret/entity.ts
  • entities/credential/credential/entity.ts
  • entities/utils/container/entity.ts
  • lib/email/send-roadmap-subscription-email.ts
  • entities/encryption/entity.ts
  • orpc/routers/user.ts
  • lib/utils/rate-limit.ts
  • entities/credential/credential-metadata/entity.ts
  • lib/auth/verify.ts
  • entities/utils/tag/entity.ts
entities/**/entity.ts

📄 CodeRabbit inference engine (.cursor/rules/entities-folder.mdc)

entities/**/entity.ts: Place all database-to-client transformation logic in entity.ts using an entity class with static methods (e.g., getSimpleRo, getRo, helper converters)
Simple Return Objects (RO) must exclude sensitive data and relations; full RO may include relations but must remain server-only
Implement status conversion helpers (e.g., convertStatusToClient or similar) to map database enums to client enums
Ensure consistent date handling in getSimpleRo (e.g., include createdAt, updatedAt, nullable lastViewed)
Map related entities via their corresponding Entity.getSimpleRo methods; avoid passing raw related entities through
Decrypt sensitive data only on the server and never expose raw encrypted payloads; on decryption failure, return safe defaults
Handle null/optional relations defensively (optional chaining, default empty arrays/values) when building ROs
Use Prisma GetPayload with ReturnType of include helpers to define types: EntitySimpleDbData, EntityIncludeDbData, EntityClientSafeDbData
Log decryption failures in a safe manner and return defaults without leaking sensitive data

Implement Entity Transformation Pattern: convert database entities to client-safe Return Objects (ROs) and exclude sensitive fields

Use client-safe entity transformations before returning data to the client

Files:

  • entities/credential/credential-key-value/entity.ts
  • entities/secrets/secret/entity.ts
  • entities/credential/credential/entity.ts
  • entities/utils/container/entity.ts
  • entities/encryption/entity.ts
  • entities/credential/credential-metadata/entity.ts
  • entities/utils/tag/entity.ts
entities/**/{entity,query,index}.ts

📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)

Entity folders must contain files named entity.ts, query.ts, and an index.ts for barrel exports

Follow the Three-File Entity Pattern: each entity must have entity.ts (transforms), query.ts (DB helpers), and index.ts (barrel)

Files:

  • entities/credential/credential-key-value/entity.ts
  • entities/secrets/secret/entity.ts
  • entities/credential/credential/entity.ts
  • entities/utils/container/entity.ts
  • entities/encryption/entity.ts
  • entities/credential/credential-metadata/entity.ts
  • entities/utils/tag/entity.ts
entities/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/architecture.mdc)

Perform Prisma-to-RO transformations and sensitive data encryption/decryption in entities/

Files:

  • entities/credential/credential-key-value/entity.ts
  • entities/secrets/secret/entity.ts
  • entities/credential/credential/entity.ts
  • entities/utils/container/entity.ts
  • entities/encryption/entity.ts
  • entities/credential/credential-metadata/entity.ts
  • entities/utils/tag/entity.ts
entities/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/database-patterns.mdc)

entities/**/*.{ts,tsx}: Use appropriate include levels to avoid N+1 queries
Select only needed fields in queries for performance
Use client-safe includes for client-facing endpoints
Use offset-based pagination for small datasets
Include total count when needed with paginated results
Use a consistent pagination structure in API responses
Use transactions for multi-step operations that must succeed atomically
Handle rollback on errors within transactions
Keep transactions short to avoid deadlocks
Handle Prisma errors appropriately (e.g., P2002, P2003, P2025)
Provide meaningful error messages for failures
Log errors for debugging while returning safe errors to clients
Convert database entities to client-safe representations (RO)
Exclude sensitive/internal fields (e.g., encryption IDs/keys) from RO outputs
Handle null/optional values gracefully in transformations
Include related entities as needed in RO and transform nested entities consistently
Handle optional relationships safely in transformations
Decrypt sensitive data only on the server and never expose encryption keys
Handle decryption errors gracefully and fall back to safe defaults
Use database-level filtering and limits instead of application-level post-processing
Avoid SELECT * patterns on large tables; select only required fields

Files:

  • entities/credential/credential-key-value/entity.ts
  • entities/secrets/secret/entity.ts
  • entities/credential/credential/entity.ts
  • entities/utils/container/entity.ts
  • entities/encryption/entity.ts
  • entities/credential/credential-metadata/entity.ts
  • entities/utils/tag/entity.ts
entities/**/{entity.ts,query.ts,index.ts}

📄 CodeRabbit inference engine (.cursor/rules/zero-locker-rules.mdc)

entities/**/{entity.ts,query.ts,index.ts}: Entities use entity.ts for transformations, query.ts for DB helpers, and index.ts for barrel exports
Within each entity folder, keep transformation logic in entity.ts, queries in query.ts, and barrel exports in index.ts

Files:

  • entities/credential/credential-key-value/entity.ts
  • entities/secrets/secret/entity.ts
  • entities/credential/credential/entity.ts
  • entities/utils/container/entity.ts
  • entities/encryption/entity.ts
  • entities/credential/credential-metadata/entity.ts
  • entities/utils/tag/entity.ts
**/*.{html,jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{html,jsx,tsx}: Don't use the accessKey attribute on any HTML element
Don't set aria-hidden="true" on focusable elements
Don't add ARIA roles, states, and properties to elements that don't support them
Don't use distracting elements like or
Only use the scope prop on elements
Don't assign non-interactive ARIA roles to interactive HTML elements
Make sure label elements have text content and are associated with an input
Don't assign interactive ARIA roles to non-interactive HTML elements
Don't assign tabIndex to non-interactive HTML elements
Don't use positive integers for the tabIndex property
Don't include "image", "picture", or "photo" in img alt prop
Don't use an explicit role property that's the same as the implicit/default role
Make static elements with click handlers use a valid role attribute
Give all elements requiring alt text meaningful information for screen readers
Make sure anchors have content that's accessible to screen readers
Assign tabIndex to non-interactive HTML elements with aria-activedescendant
Include all required ARIA attributes for elements with ARIA roles
Make sure ARIA properties are valid for the element's supported roles
Always include a type attribute for button elements
Make elements with interactive roles and handlers focusable
Give heading elements content that's accessible to screen readers (not hidden with aria-hidden)
Always include a title attribute for iframe elements
Include caption tracks for audio and video elements
Make sure all anchors are valid and navigable
Ensure all ARIA properties (aria-*) are valid
Use valid, non-abstract ARIA roles for elements with ARIA roles
Use valid ARIA state and property values
Use valid values for the autocomplete attribute on input elements
Use correct ISO language/country codes for the lang attribute
Don't use variables that haven't been declared in the document
Make sure void (self-closing) elements don't have children
Don't use event handlers on non-interactiv...

Files:

  • config/converter.tsx
  • components/app/marketing-roadmap-list.tsx
  • components/app/marketing-roadmap-item.tsx
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{jsx,tsx}: Accompany onClick with at least one of: onKeyUp, onKeyDown, or onKeyPress
Accompany onMouseOver/onMouseOut with onFocus/onBlur
Use semantic elements instead of role attributes in JSX
Don't use unnecessary fragments
Don't pass children as props
Don't use the return value of React.render
Make sure all dependencies are correctly specified in React hooks
Make sure all React hooks are called from the top level of component functions
Don't forget key props in iterators and collection literals
Don't define React components inside other components
Don't assign to React component props
Don't use dangerous JSX props
Don't use both children and dangerouslySetInnerHTML props on the same element
Use <>...</> instead of ...
Don't add extra closing tags for components without children
Don't use Array index in keys
Don't insert comments as text nodes
Don't assign JSX properties multiple times
Watch out for possible "wrong" semicolons inside JSX elements
Don't put multiple components in one file; each file must have one component

Files:

  • config/converter.tsx
  • components/app/marketing-roadmap-list.tsx
  • components/app/marketing-roadmap-item.tsx
**/*.{html,jsx,tsx,css}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

Don't use TailwindCSS class names 'h-NUMBER w-NUMBER'; instead use 'size-NUMBR'

Files:

  • config/converter.tsx
  • components/app/marketing-roadmap-list.tsx
  • components/app/marketing-roadmap-item.tsx
config/**/*

📄 CodeRabbit inference engine (.cursor/rules/config-folder.mdc)

Place application configuration files, constants, and utility configurations under the /config directory

Files:

  • config/converter.tsx
config/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/config-folder.mdc)

config/**/*.{ts,tsx}: Export configurations as named exports
Use TypeScript for all configuration
Define interfaces for complex configurations
Use const assertions for immutable configurations
Use descriptive names for configuration objects

Files:

  • config/converter.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/zero-locker-patterns.mdc)

**/*.tsx: Use Component Composition Pattern: build complex UI by composing smaller, reusable components (e.g., Form, FormField, FormItem)
Handle form errors with React Hook Form and Zod resolver for client-side validation
Avoid direct database access in React components; use hooks/services instead

**/*.tsx: Use PascalCase for React component names
Use functional components only, typed with explicit props interfaces
Optimize components using React.memo for expensive components, useMemo for heavy computations, and useCallback for stable handlers

**/*.tsx: Never use useState for form state; use React Hook Form (useForm) instead
Always use Zod schemas with zodResolver for form validation
Always use shadcn Form components: Form, FormField, FormItem, FormLabel, FormControl, FormMessage
Always use Icons.spinner with animate-spin for loading states
Never use text like "Deleting..." or "Loading..." for loading states
Use size-4 instead of h-4 w-4 for spinner sizing (Tailwind)
Disable buttons during loading: disabled={isLoading}
Show spinner + text inside buttons when loading
Use Button variant="destructive" for delete actions
Add disabled opacity class to buttons: className="disabled:opacity-50"
Avoid manual form validation; rely on Zod + resolver integration

Files:

  • config/converter.tsx
  • components/app/marketing-roadmap-list.tsx
  • components/app/marketing-roadmap-item.tsx
components/app/**

📄 CodeRabbit inference engine (.cursor/rules/components-folder.mdc)

Place application-specific React components under components/app

Files:

  • components/app/marketing-roadmap-list.tsx
  • components/app/marketing-roadmap-item.tsx
components/app/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/components-folder.mdc)

Use naming pattern {feature}-{purpose}-{type}.tsx for app components

Files:

  • components/app/marketing-roadmap-list.tsx
  • components/app/marketing-roadmap-item.tsx
components/app/marketing-*.tsx

📄 CodeRabbit inference engine (.cursor/rules/components-folder.mdc)

Marketing components in components/app must be prefixed with marketing-

Place marketing components under components/app/ with filenames starting marketing-*.tsx

Files:

  • components/app/marketing-roadmap-list.tsx
  • components/app/marketing-roadmap-item.tsx
components/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/components-folder.mdc)

components/**/*.{ts,tsx}: Always define a TypeScript interface for component props
Follow established naming patterns consistently across files
Use strict, explicit TypeScript types for safety

Files:

  • components/app/marketing-roadmap-list.tsx
  • components/app/marketing-roadmap-item.tsx
components/**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/components-folder.mdc)

components/**/*.tsx: Add 'use client' directive for components that use client-side hooks/effects
Use cn() for conditional Tailwind classes
Use semantic Tailwind colors (e.g., text-foreground, bg-background) and consistent spacing (space-y-4, gap-4)
Use responsive Tailwind prefixes (md:, lg:, xl:) for adaptive layouts
Define component variants with cva and defaultVariants when variants are needed
Prefer useState for local state; use useReducer for complex state
Use TanStack Query hooks from /orpc/hooks for server state; prefer server-side data fetching when possible
Implement proper ARIA attributes and keyboard navigation for accessibility
Use React.memo for expensive components
Use useMemo and useCallback for expensive computations and stable callbacks
Lazy-load heavy components via dynamic import
Import only needed icons from lucide-react (no wildcard imports)
Wrap components that might fail in Error Boundaries
Provide loading and error states for async UI
Add JSDoc comments for complex components

components/**/*.tsx: Components must be named in kebab-case.tsx (e.g., dashboard-credential-form.tsx)
Use React Hook Form for form management in UI forms
Use React Hook Form error handling, display validation errors, and handle submission errors gracefully in forms

Files:

  • components/app/marketing-roadmap-list.tsx
  • components/app/marketing-roadmap-item.tsx
components/**/[a-z0-9-]*.tsx

📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)

Name React components in kebab-case with .tsx under the components directory (e.g., dashboard-credential-form.tsx)

Files:

  • components/app/marketing-roadmap-list.tsx
  • components/app/marketing-roadmap-item.tsx
components/{app,layout,shared,ui}/**

📄 CodeRabbit inference engine (.cursor/rules/architecture.mdc)

Organize React components under components/app, components/layout, components/shared, and components/ui

Files:

  • components/app/marketing-roadmap-list.tsx
  • components/app/marketing-roadmap-item.tsx
orpc/routers/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/orpc-folder.mdc)

orpc/routers/**/*.ts: In oRPC routers, build procedures using os.$context(), then compose authProcedure and permissionProcedure via .use(...) middleware chaining
Define routes with .input(zodSchema).output(zodSchema).handler(async (...) => { ... }) to enforce schema-validated inputs/outputs
For list endpoints, implement pagination (page, limit), deterministic orderBy, and compute total/hasMore
Apply authMiddleware to protected routes and requirePermission(feature, action) where feature-gated access is needed
Use ORPCError with standard codes (e.g., UNAUTHORIZED, FORBIDDEN, NOT_FOUND, BAD_REQUEST) for predictable error handling
Map known ORM errors (e.g., Prisma P2002) to meaningful ORPCError codes like CONFLICT and fall back to INTERNAL_SERVER_ERROR
Always validate inputs with Zod schemas and define explicit output schemas; handle validation errors gracefully
Never expose sensitive fields in responses; use client-safe entity transformations and selective include projections
Group related procedures in a single router file and use consistent naming for routes and files
Use include helpers (e.g., EntityQuery.getClientSafeInclude()) to fetch only client-safe relations
Use server-side caching or efficient queries where appropriate; prefer pagination over large result sets
Return deterministic ordering for list endpoints (e.g., orderBy createdAt desc)
Provide meaningful error messages when throwing BAD_REQUEST/CONFLICT while avoiding sensitive details

orpc/routers/**/*.ts: Group routes by feature (e.g., credentialRouter, cardRouter) in dedicated router files
Use descriptive, action-indicative procedure names within routers
Use action-based names: create, getById, list, update, delete
Keep procedure names consistent across all routers
Use camelCase for procedure names
Use Zod schemas for all procedure inputs via .input(schema)
List procedures must return metadata (total, hasMore, page, limit) alongside data
Apply authentication middleware to all protecte...

Files:

  • orpc/routers/user.ts
orpc/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)

Ensure consistent error handling and responses within oRPC routes and client code

orpc/**/*.ts: Use oRPC standard error codes (ORPCError) with meaningful, contextual messages
Handle specific error types (e.g., Prisma codes), log errors, and map to appropriate ORPC error codes
Use FORBIDDEN for permission errors; include feature and action in the message and upgrade info when applicable

Always encrypt passwords before storage in server-side handlers/services

Files:

  • orpc/routers/user.ts
orpc/routers/{credential,card,secret,user}.ts

📄 CodeRabbit inference engine (.cursor/rules/architecture.mdc)

Define oRPC routers in orpc/routers/ with files credential.ts, card.ts, secret.ts, and user.ts

Files:

  • orpc/routers/user.ts
orpc/routers/**/!(*index).ts

📄 CodeRabbit inference engine (.cursor/rules/orpc-patterns.mdc)

Export routers individually from their own files

Files:

  • orpc/routers/user.ts
orpc/routers/*.ts

📄 CodeRabbit inference engine (.cursor/rules/zero-locker-rules.mdc)

Define route handlers in orpc/routers with one file per domain (e.g., credential.ts, card.ts)

Files:

  • orpc/routers/user.ts
lib/utils/**

📄 CodeRabbit inference engine (.cursor/rules/architecture.mdc)

Place general-purpose utilities under lib/utils/

Files:

  • lib/utils/rate-limit.ts
lib/auth/**

📄 CodeRabbit inference engine (.cursor/rules/architecture.mdc)

Implement authentication utilities under lib/auth/

Files:

  • lib/auth/verify.ts
🧠 Learnings (16)
📚 Learning: 2025-10-02T22:16:27.157Z
Learnt from: CR
PR: FindMalek/zero-locker#0
File: .cursor/rules/architecture.mdc:0-0
Timestamp: 2025-10-02T22:16:27.157Z
Learning: Applies to entities/**/*.ts : Perform Prisma-to-RO transformations and sensitive data encryption/decryption in entities/

Applied to files:

  • entities/secrets/secret/entity.ts
  • entities/credential/credential/entity.ts
  • entities/encryption/entity.ts
📚 Learning: 2025-10-02T22:21:11.735Z
Learnt from: CR
PR: FindMalek/zero-locker#0
File: .cursor/rules/zero-locker-rules.mdc:0-0
Timestamp: 2025-10-02T22:21:11.735Z
Learning: Applies to entities/**/{entity.ts,query.ts,index.ts} : Entities use entity.ts for transformations, query.ts for DB helpers, and index.ts for barrel exports

Applied to files:

  • entities/secrets/secret/entity.ts
📚 Learning: 2025-10-02T20:57:51.336Z
Learnt from: CR
PR: FindMalek/zero-locker#0
File: .cursor/rules/entities-folder.mdc:0-0
Timestamp: 2025-10-02T20:57:51.336Z
Learning: Applies to entities/**/index.ts : Barrel export from index.ts using export * from "./entity" and export * from "./query"

Applied to files:

  • entities/secrets/secret/entity.ts
📚 Learning: 2025-10-02T20:57:51.336Z
Learnt from: CR
PR: FindMalek/zero-locker#0
File: .cursor/rules/entities-folder.mdc:0-0
Timestamp: 2025-10-02T20:57:51.336Z
Learning: Applies to entities/**/entity.ts : Place all database-to-client transformation logic in entity.ts using an entity class with static methods (e.g., getSimpleRo, getRo, helper converters)

Applied to files:

  • entities/secrets/secret/entity.ts
  • entities/utils/container/entity.ts
  • entities/encryption/entity.ts
  • entities/utils/tag/entity.ts
📚 Learning: 2025-10-02T20:57:51.336Z
Learnt from: CR
PR: FindMalek/zero-locker#0
File: .cursor/rules/entities-folder.mdc:0-0
Timestamp: 2025-10-02T20:57:51.336Z
Learning: Applies to entities/**/entity.ts : Simple Return Objects (RO) must exclude sensitive data and relations; full RO may include relations but must remain server-only

Applied to files:

  • entities/secrets/secret/entity.ts
📚 Learning: 2025-10-02T20:57:51.336Z
Learnt from: CR
PR: FindMalek/zero-locker#0
File: .cursor/rules/entities-folder.mdc:0-0
Timestamp: 2025-10-02T20:57:51.336Z
Learning: Applies to entities/**/entity.ts : Map related entities via their corresponding Entity.getSimpleRo methods; avoid passing raw related entities through

Applied to files:

  • entities/secrets/secret/entity.ts
  • entities/utils/tag/entity.ts
📚 Learning: 2025-10-02T22:19:32.110Z
Learnt from: CR
PR: FindMalek/zero-locker#0
File: .cursor/rules/zero-locker-patterns.mdc:0-0
Timestamp: 2025-10-02T22:19:32.110Z
Learning: Applies to entities/**/entity.ts : Implement Entity Transformation Pattern: convert database entities to client-safe Return Objects (ROs) and exclude sensitive fields

Applied to files:

  • entities/secrets/secret/entity.ts
📚 Learning: 2025-10-02T22:17:55.478Z
Learnt from: CR
PR: FindMalek/zero-locker#0
File: .cursor/rules/database-patterns.mdc:0-0
Timestamp: 2025-10-02T22:17:55.478Z
Learning: Applies to entities/**/*.{ts,tsx} : Convert database entities to client-safe representations (RO)

Applied to files:

  • entities/secrets/secret/entity.ts
📚 Learning: 2025-10-02T20:57:51.336Z
Learnt from: CR
PR: FindMalek/zero-locker#0
File: .cursor/rules/entities-folder.mdc:0-0
Timestamp: 2025-10-02T20:57:51.336Z
Learning: Applies to entities/**/entity.ts : Decrypt sensitive data only on the server and never expose raw encrypted payloads; on decryption failure, return safe defaults

Applied to files:

  • entities/credential/credential/entity.ts
  • entities/encryption/entity.ts
📚 Learning: 2025-10-02T20:57:51.336Z
Learnt from: CR
PR: FindMalek/zero-locker#0
File: .cursor/rules/entities-folder.mdc:0-0
Timestamp: 2025-10-02T20:57:51.336Z
Learning: Applies to entities/**/entity.ts : Log decryption failures in a safe manner and return defaults without leaking sensitive data

Applied to files:

  • entities/credential/credential/entity.ts
📚 Learning: 2025-10-02T22:17:55.478Z
Learnt from: CR
PR: FindMalek/zero-locker#0
File: .cursor/rules/database-patterns.mdc:0-0
Timestamp: 2025-10-02T22:17:55.478Z
Learning: Applies to prisma/schema.prisma : Separate encryption storage (e.g., EncryptedData) from main entities

Applied to files:

  • entities/encryption/entity.ts
📚 Learning: 2025-10-02T22:17:55.478Z
Learnt from: CR
PR: FindMalek/zero-locker#0
File: .cursor/rules/database-patterns.mdc:0-0
Timestamp: 2025-10-02T22:17:55.478Z
Learning: Applies to prisma/schema.prisma : Use a consistent encryption structure across entities

Applied to files:

  • entities/encryption/entity.ts
📚 Learning: 2025-10-02T21:03:01.338Z
Learnt from: CR
PR: FindMalek/zero-locker#0
File: .cursor/rules/prisma-folder.mdc:0-0
Timestamp: 2025-10-02T21:03:01.338Z
Learning: Applies to prisma/schema/encryption.prisma : Model encrypted values using EncryptedData with fields (encryptedValue, iv, algorithm default AES_256_GCM, encryptionKey) and relations/indexes as shown

Applied to files:

  • entities/encryption/entity.ts
📚 Learning: 2025-10-02T20:57:51.336Z
Learnt from: CR
PR: FindMalek/zero-locker#0
File: .cursor/rules/entities-folder.mdc:0-0
Timestamp: 2025-10-02T20:57:51.336Z
Learning: Applies to entities/**/entity.ts : Use Prisma GetPayload with ReturnType of include helpers to define types: EntitySimpleDbData, EntityIncludeDbData, EntityClientSafeDbData

Applied to files:

  • entities/encryption/entity.ts
📚 Learning: 2025-10-02T20:56:15.975Z
Learnt from: CR
PR: FindMalek/zero-locker#0
File: .cursor/rules/components-folder.mdc:0-0
Timestamp: 2025-10-02T20:56:15.975Z
Learning: Applies to components/**/*.tsx : Use cn() for conditional Tailwind classes

Applied to files:

  • components/app/marketing-roadmap-item.tsx
📚 Learning: 2025-10-02T21:00:01.595Z
Learnt from: CR
PR: FindMalek/zero-locker#0
File: .cursor/rules/lib-folder.mdc:0-0
Timestamp: 2025-10-02T21:00:01.595Z
Learning: Applies to lib/utils/cn.ts : Provide a cn utility in lib/utils/cn.ts that wraps clsx with tailwind-merge: export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)) }

Applied to files:

  • components/app/marketing-roadmap-item.tsx
🧬 Code graph analysis (6)
lib/email/send-waitlist-email.ts (4)
lib/email/resend-client.ts (1)
  • resendClient (5-5)
env.ts (1)
  • env (4-27)
config/site.ts (1)
  • siteConfig (3-41)
components/app/email-waitlist.tsx (1)
  • EmailWaitlist (25-90)
config/converter.tsx (1)
types/index.d.ts (1)
  • RoadmapStatus (59-59)
components/app/marketing-roadmap-list.tsx (3)
types/index.d.ts (1)
  • RoadmapItem (61-65)
components/app/marketing-roadmap-item.tsx (1)
  • MarketingRoadmapItem (6-27)
components/shared/icons.tsx (1)
  • Icons (139-262)
lib/email/send-roadmap-subscription-email.ts (4)
lib/email/resend-client.ts (1)
  • resendClient (5-5)
env.ts (1)
  • env (4-27)
config/site.ts (1)
  • siteConfig (3-41)
components/app/email-roadmap-subscription.tsx (1)
  • EmailRoadmapSubscription (24-106)
orpc/routers/user.ts (6)
orpc/types.ts (1)
  • ORPCContext (14-28)
middleware/rate-limit.ts (2)
  • lenientRateLimit (95-100)
  • strictRateLimit (73-78)
middleware/auth.ts (1)
  • authMiddleware (15-33)
lib/email/send-waitlist-email.ts (1)
  • sendWaitlistEmail (13-35)
schemas/user/roadmap.ts (3)
  • subscribeToRoadmapInputSchema (4-6)
  • subscribeToRoadmapOutputSchema (13-16)
  • SubscribeToRoadmapOutput (18-20)
lib/email/send-roadmap-subscription-email.ts (1)
  • sendRoadmapSubscriptionEmail (12-33)
components/app/marketing-roadmap-item.tsx (2)
types/index.d.ts (1)
  • RoadmapItem (61-65)
config/converter.tsx (1)
  • roadmapStatusConfig (67-86)
🔇 Additional comments (11)
entities/credential/credential-key-value/entity.ts (1)

1-4: LGTM: Import path refactored to absolute alias.

The change from relative to absolute import path is correct and aligns with the project's module resolution pattern.

entities/credential/credential-metadata/entity.ts (1)

1-1: LGTM: Import path refactored to absolute alias.

The change from relative to absolute import path is correct and consistent with the broader refactor.

entities/secrets/secret/entity.ts (1)

1-1: LGTM: Import path refactored to absolute alias.

The change from relative to absolute import path is correct and maintains consistency across entity modules.

lib/auth/verify.ts (1)

5-5: LGTM: Import path refactored to absolute alias.

The change from relative to absolute import path is correct and aligns with the project-wide import standardization.

entities/encryption/entity.ts (1)

1-1: LGTM: Import path refactored to absolute alias.

The change from relative to absolute import path is correct and consistent with the encryption entity module pattern.

entities/credential/credential/entity.ts (1)

1-4: LGTM: Import path refactored to absolute alias.

The change from relative to absolute import path is correct and aligns with the credential entity module pattern. All class methods and logic remain unchanged.

entities/utils/container/entity.ts (1)

1-1: LGTM! Import standardization improves maintainability.

The change from a relative import to an absolute alias import follows the coding guidelines and aligns with the broader refactoring effort to standardize module resolution across the codebase.

entities/utils/tag/entity.ts (1)

1-1: No action required. The Three-File Entity Pattern is correctly implemented.

The entity triad exists: query.ts, index.ts, and entity.ts are all present in entities/utils/tag/. The "@/*" alias is configured in tsconfig.json with proper Next.js path resolution. The code follows the established entity structure guidelines without issues.

Likely an incorrect or invalid review comment.

components/app/marketing-roadmap-item.tsx (1)

1-27: LGTM! Past review concern addressed.

The component now correctly uses the cn() utility for conditional className composition (lines 16, 21) instead of template literals. The implementation is clean, type-safe, and follows component guidelines.

config/converter.tsx (1)

67-86: LGTM! Well-structured status configuration.

The roadmap status configuration is properly typed, uses semantic Tailwind colors (including text-muted-foreground), and provides clear labels for each status. The structure integrates cleanly with the component layer.

lib/utils/rate-limit.ts (1)

1-322: LGTM! All past review concerns addressed.

The implementation has successfully addressed all previous review feedback:

  • Cross-runtime interval typing with ReturnType<typeof setInterval> (line 90)
  • Event loop management with unref() (line 112)
  • Precise expiry boundaries with <= now (lines 119, 129, 230)
  • Exported public interfaces for RateLimitStore and RateLimitStats (lines 69-82)
  • Input validation for maxRequests and windowSeconds (lines 194-205)

The rate limiting utility is well-structured, type-safe, and production-ready.

Comment on lines +41 to +48
{items.map((item, index) => (
<MarketingRoadmapItem
key={`${item.title}-${index}`}
title={item.title}
description={item.description}
status={item.status}
/>
))}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Avoid using array index in key prop.

Line 43 uses array index in the key prop (key={${item.title}-${index}}). Per coding guidelines, avoid using array indices in keys as they can cause issues with React reconciliation if items are reordered or filtered. If a stable unique identifier is available on RoadmapItem, use that instead.

As per coding guidelines

🤖 Prompt for AI Agents
In components/app/marketing-roadmap-list.tsx around lines 41 to 48, the key prop
currently uses the array index (`${item.title}-${index}`) which can break React
reconciliation; replace the index-based key with a stable unique identifier from
the RoadmapItem (e.g., `item.id` or `item.slug`) — if the model lacks such a
field, add a stable unique ID to each item at the source (or compute a stable
slug from the title) and update the prop to use that unique value as the key.

Comment on lines +52 to +56
<div
className={`from-background via-background/50 pointer-events-none absolute bottom-0 left-0 right-0 h-32 rounded-b-lg bg-gradient-to-t to-transparent transition-opacity duration-500 ${
showScrollIndicator ? "opacity-100" : "opacity-0"
}`}
/>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Use cn() utility for conditional className composition.

Lines 53-55 compose className using template literals. Per coding guidelines and retrieved learnings, use the cn() utility for conditional Tailwind classes to ensure proper class merging and deduplication.

Apply this diff:

+import { cn } from "@/lib/utils"
+
 interface MarketingRoadmapListProps {
   items: RoadmapItem[]
 }
       {/* Bottom blur gradient */}
       <div
-        className={`from-background via-background/50 pointer-events-none absolute bottom-0 left-0 right-0 h-32 rounded-b-lg bg-gradient-to-t to-transparent transition-opacity duration-500 ${
-          showScrollIndicator ? "opacity-100" : "opacity-0"
-        }`}
+        className={cn(
+          "from-background via-background/50 pointer-events-none absolute bottom-0 left-0 right-0 h-32 rounded-b-lg bg-gradient-to-t to-transparent transition-opacity duration-500",
+          showScrollIndicator ? "opacity-100" : "opacity-0"
+        )}
       />

As per coding guidelines

Based on learnings

🤖 Prompt for AI Agents
In components/app/marketing-roadmap-list.tsx around lines 52 to 56, replace the
template-literal className with the cn() utility: pass the static Tailwind
classes as string arguments and the conditional opacity class as an object or
conditional argument (e.g., { "opacity-100": showScrollIndicator, "opacity-0":
!showScrollIndicator }) so classes are merged/deduped correctly; also ensure cn
is imported from your utilities at the top of the file if not already.

Comment on lines +59 to +65
<div
className={`pointer-events-none absolute bottom-4 left-1/2 -translate-x-1/2 animate-bounce transition-opacity duration-500 ${
showScrollIndicator ? "opacity-100" : "opacity-0"
}`}
>
<Icons.down className="text-muted-foreground size-4" />
</div>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Use cn() utility for conditional className composition.

Lines 60-62 compose className using template literals. Use the cn() utility for conditional Tailwind classes.

Apply this diff:

       {/* Bouncing scroll indicator */}
       <div
-        className={`pointer-events-none absolute bottom-4 left-1/2 -translate-x-1/2 animate-bounce transition-opacity duration-500 ${
-          showScrollIndicator ? "opacity-100" : "opacity-0"
-        }`}
+        className={cn(
+          "pointer-events-none absolute bottom-4 left-1/2 -translate-x-1/2 animate-bounce transition-opacity duration-500",
+          showScrollIndicator ? "opacity-100" : "opacity-0"
+        )}
       >

As per coding guidelines

Based on learnings

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div
className={`pointer-events-none absolute bottom-4 left-1/2 -translate-x-1/2 animate-bounce transition-opacity duration-500 ${
showScrollIndicator ? "opacity-100" : "opacity-0"
}`}
>
<Icons.down className="text-muted-foreground size-4" />
</div>
<div
className={cn(
"pointer-events-none absolute bottom-4 left-1/2 -translate-x-1/2 animate-bounce transition-opacity duration-500",
showScrollIndicator ? "opacity-100" : "opacity-0"
)}
>
<Icons.down className="text-muted-foreground size-4" />
</div>
🤖 Prompt for AI Agents
components/app/marketing-roadmap-list.tsx lines 59-65: the className is built
via a template literal; replace it with the cn() utility so Tailwind conditional
classes are composed consistently. Import cn if it's not already imported, then
call cn("pointer-events-none absolute bottom-4 left-1/2 -translate-x-1/2
animate-bounce transition-opacity duration-500", showScrollIndicator ?
"opacity-100" : "opacity-0") to preserve all static classes and the conditional
opacity class.

Comment on lines +237 to +306
// Send subscription confirmation email
try {
await sendRoadmapSubscriptionEmail({
to: input.email,
})
} catch (emailError) {
console.error("Failed to send subscription email:", emailError)
// Don't fail the request if email fails
}

return { success: true }
} catch (error) {
// Re-throw ORPC errors to let ORPC handle them
if (error instanceof ORPCError) {
throw error
}

// Handle Prisma-specific errors
if (error instanceof Prisma.PrismaClientKnownRequestError) {
console.error("Database constraint error subscribing to roadmap:", {
code: error.code,
message: error.message,
meta: error.meta,
})

// Handle unique constraint violations
if (error.code === "P2002") {
return {
success: false,
error: "Email is already subscribed",
}
}

// Handle other known Prisma errors
return {
success: false,
error: "Database constraint violation occurred",
}
}

// Handle Prisma client errors (connection issues, etc.)
if (error instanceof Prisma.PrismaClientUnknownRequestError) {
console.error("Unknown Prisma error subscribing to roadmap:", {
message: error.message,
})
return {
success: false,
error: "Database connection issue occurred",
}
}

// Handle Prisma validation errors
if (error instanceof Prisma.PrismaClientValidationError) {
console.error("Prisma validation error subscribing to roadmap:", {
message: error.message,
})
return {
success: false,
error: "Invalid data provided",
}
}

// Handle unexpected errors
console.error("Unexpected error subscribing to roadmap:", error)
return {
success: false,
error: "An unexpected error occurred. Please try again later.",
}
}
})
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Replace console.error with structured logging.

Lines 243, 256, 279, 290, and 300 use console.error for logging, violating coding guidelines for TypeScript files. Error contexts may expose PII (email addresses). Implement structured logging with PII redaction throughout this handler.

As per coding guidelines

This was referenced Oct 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant