Skip to content

Add Survivor Forge cursor rules collection#186

Closed
survivorforge wants to merge 3 commits intoPatrickJS:mainfrom
survivorforge:add-survivorforge-rules
Closed

Add Survivor Forge cursor rules collection#186
survivorforge wants to merge 3 commits intoPatrickJS:mainfrom
survivorforge:add-survivorforge-rules

Conversation

@survivorforge
Copy link

@survivorforge survivorforge commented Mar 4, 2026

Adding cursor rules for multiple frameworks and languages from the Survivor Forge collection.

Includes rules for: React, Next.js, Python, Go, Rust, SvelteKit, Django, and more.

Each rule file follows best practices for code style, architecture, testing, and error handling.

Summary by CodeRabbit

  • Documentation
    • Added comprehensive Cursor Rules guides covering Clean Code & Refactoring, MERN stack, T3 stack, and Security Best Practices.
    • Each guide provides conventions, examples, patterns, error‑handling and testing guidance, and common pitfalls to improve code quality and security.
    • README updated to index and surface these new developer resources.

Added four new .cursorrules files covering commonly requested configurations:

- T3 Stack (Next.js, tRPC, Prisma, Tailwind) - Backend and Full-Stack
- MERN Stack (MongoDB, Express, React, Node.js) - Backend and Full-Stack
- Clean Code Principles (SOLID, naming, refactoring) - Other
- Security Best Practices (OWASP top 10, input validation) - Other

Also added Survivor Forge Cursor Rules collection to Directories section
(35+ rules for 16 frameworks/languages).
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 4, 2026

📝 Walkthrough

Walkthrough

This PR adds README entries and four new Cursor Rules documentation files (Clean Code, MERN Stack, T3 Stack, Security Best Practices). No executable code or public API signatures were changed.

Changes

Cohort / File(s) Summary
Documentation Index
README.md
Updated README to include entries for MERN Stack, T3 Stack, Clean Code Principles, Security Best Practices, and Survivor Forge Cursor Rules.
Clean Code & Refactoring
rules/clean-code-principles-cursorrules-prompt-file/.cursorrules
New comprehensive guidelines covering naming, functions, conditionals, error handling, comments, code smells, refactoring techniques, file organization, and common pitfalls with TypeScript examples.
MERN Stack Guidelines
rules/mern-stack-cursorrules-prompt-file/.cursorrules
New MERN-focused guidance including project structure, MongoDB/Mongoose patterns, Express API conventions, React patterns, error handling, security, testing, performance, and example snippets.
Security Best Practices
rules/security-best-practices-cursorrules-prompt-file/.cursorrules
New security guidance covering input validation, injection/XSS prevention, CSP, auth (passwords/JWT/sessions), authorization, sensitive data handling, HTTP headers, rate limiting, logging/monitoring, and dependency security.
T3 Stack Guidelines
rules/t3-stack-cursorrules-prompt-file/.cursorrules
New T3 Stack document with tRPC patterns, Prisma usage, authentication strategies, error mapping, testing, performance tips, and server/client example code.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • PatrickJS

Poem

🐰 I hopped through docs both near and far,
Wrote rules for stacks and kept them tidy as a jar,
MERN, T3, and safety in sight,
Clean code by day and secure by night,
A carrot for you — these docs feel just right! 🥕✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding cursor rules files for multiple frameworks (MERN Stack, T3 Stack, Clean Code Principles, Security Best Practices) to the collection.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

❤️ Share

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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

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

142-157: ⚠️ Potential issue | 🟡 Minor

Reorder T3 Stack to keep Backend/Full-Stack alphabetized.

Line 157 is out of order in the category list (T3 Stack should be placed before TypeScript ... and TYPO3 ... entries).

Suggested reorder
 - [Salesforce (Apex)](./rules/salesforce-apex-cursorrules-prompt-file/.cursorrules.txt) - Cursor rules for Salesforce development with Apex integration.
+- [T3 Stack (Next.js, tRPC, Prisma, Tailwind)](./rules/t3-stack-cursorrules-prompt-file/.cursorrules) - Cursor rules for T3 Stack development with Next.js, tRPC, Prisma, and Tailwind CSS integration.
 - [TypeScript (NestJS Best Practices)](./rules/typescript-nestjs-best-practices-cursorrules-promp/.cursorrules) - Cursor rules for TypeScript development with NestJS best practices.
 - [TYPO3 CMS Extension](./rules/typo3cms-extension-cursorrules-prompt-file/.cursorrules) - Cursor rules for TYPO3 CMS development with extension integration.
-- [T3 Stack (Next.js, tRPC, Prisma, Tailwind)](./rules/t3-stack-cursorrules-prompt-file/.cursorrules) - Cursor rules for T3 Stack development with Next.js, tRPC, Prisma, and Tailwind CSS integration.
As per coding guidelines, "Maintain alphabetical order within each category in the README.md file".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@README.md` around lines 142 - 157, The "T3 Stack (Next.js, tRPC, Prisma,
Tailwind)" list item is out of alphabetical order in the README category; move
the line for "T3 Stack (Next.js, tRPC, Prisma, Tailwind)" so it appears before
the "TypeScript (NestJS Best Practices)" and "TYPO3 CMS Extension" entries to
restore alphabetical ordering; update only the ordering of the lines referencing
"T3 Stack (Next.js, tRPC, Prisma, Tailwind)", "TypeScript (NestJS Best
Practices)", and "TYPO3 CMS Extension" in the list.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@rules/t3-stack-cursorrules-prompt-file/.cursorrules`:
- Around line 177-179: The example calls api.post.getById from PostPage but the
router shown earlier doesn't define a getById procedure; either add a matching
procedure named getById to the post router (e.g., a public procedure that
accepts { id: string } and returns the post) or change the client call to the
existing router procedure name (for example api.post.get or api.post.byId) to
match the router; update the PostPage component or the router so the procedure
name and parameter shape (id: string) are consistent with the router method you
choose.
- Around line 124-139: Import ZodError from "zod" and change the tRPC context
generic to the resolved context type: add `ZodError` to the imports, and replace
initTRPC.context<typeof createTRPCContext>() with
initTRPC.context<Awaited<ReturnType<typeof createTRPCContext>>>() so the context
typing matches the async createTRPCContext return type; keep the existing
errorFormatter using ZodError to check error.cause.

---

Outside diff comments:
In `@README.md`:
- Around line 142-157: The "T3 Stack (Next.js, tRPC, Prisma, Tailwind)" list
item is out of alphabetical order in the README category; move the line for "T3
Stack (Next.js, tRPC, Prisma, Tailwind)" so it appears before the "TypeScript
(NestJS Best Practices)" and "TYPO3 CMS Extension" entries to restore
alphabetical ordering; update only the ordering of the lines referencing "T3
Stack (Next.js, tRPC, Prisma, Tailwind)", "TypeScript (NestJS Best Practices)",
and "TYPO3 CMS Extension" in the list.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 658f27f6-3ea2-4c05-be6c-2f01bb9ce721

📥 Commits

Reviewing files that changed from the base of the PR and between fc2ce04 and 3aaa86b.

📒 Files selected for processing (5)
  • README.md
  • rules/clean-code-principles-cursorrules-prompt-file/.cursorrules
  • rules/mern-stack-cursorrules-prompt-file/.cursorrules
  • rules/security-best-practices-cursorrules-prompt-file/.cursorrules
  • rules/t3-stack-cursorrules-prompt-file/.cursorrules

survivorforge and others added 2 commits March 4, 2026 16:19
- Fix alphabetical ordering of T3 Stack entry in README.md
- Add missing ZodError import and fix tRPC context typing
- Add missing getById procedure to match server-side usage example

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@rules/t3-stack-cursorrules-prompt-file/.cursorrules`:
- Around line 77-84: The postRouter contains two duplicate getById entries in
the createTRPCRouter object; remove the earlier simpler getById definition (the
one that only queries ctx.db.post.findUnique and throws NOT_FOUND) so only the
later, more complete getById (which includes author data) remains; update the
createTRPCRouter block to have a single getById procedure and ensure there are
no remaining duplicate keys.
- Around line 92-96: The cursor pagination in ctx.db.post.findMany is producing
duplicate/unstable pages because cursor rows are included again and ordering
uses non-unique createdAt; update the query to add skip: 1 when input.cursor is
present and make the orderBy deterministic by adding id as a tie-breaker (e.g.,
orderBy: [{ createdAt: "desc" }, { id: "desc" }]) so posts (and the take:
input.limit + 1 logic) returns stable, non-duplicated pages.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: afacc29d-a177-4e3c-9b26-defcf3af7ef9

📥 Commits

Reviewing files that changed from the base of the PR and between 9b2b2fd and 3b57b17.

📒 Files selected for processing (1)
  • rules/t3-stack-cursorrules-prompt-file/.cursorrules

Comment on lines +77 to +84
export const postRouter = createTRPCRouter({
getById: publicProcedure
.input(z.object({ id: z.string() }))
.query(async ({ ctx, input }) => {
const post = await ctx.db.post.findUnique({ where: { id: input.id } });
if (!post) throw new TRPCError({ code: "NOT_FOUND" });
return post;
}),
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Read the cursorrules file to verify the duplicate getById issue
wc -l "rules/t3-stack-cursorrules-prompt-file/.cursorrules"

Repository: PatrickJS/awesome-cursorrules

Length of output: 128


🏁 Script executed:

#!/bin/bash
# Check lines 77 and 116 to confirm both have getById
echo "=== Lines 70-90 (context around line 77) ==="
sed -n '70,90p' "rules/t3-stack-cursorrules-prompt-file/.cursorrules"
echo ""
echo "=== Lines 110-130 (context around line 116) ==="
sed -n '110,130p' "rules/t3-stack-cursorrules-prompt-file/.cursorrules"

Repository: PatrickJS/awesome-cursorrules

Length of output: 1542


🏁 Script executed:

#!/bin/bash
# Count occurrences of getById in the postRouter definition
python3 <<'PYSCRIPT'
import re

with open("rules/t3-stack-cursorrules-prompt-file/.cursorrules", 'r') as f:
    content = f.read()

# Find the postRouter block
match = re.search(r'export const postRouter = createTRPCRouter\(\{(.*?)\n\}\);', content, re.DOTALL)
if match:
    router_content = match.group(1)
    # Find all procedure definitions (keys followed by colon)
    procedures = re.findall(r'^\s{2}([a-zA-Z_][a-zA-Z0-9_]*)\s*:', router_content, re.MULTILINE)
    print("Procedures found:", procedures)
    print("Unique procedures:", set(procedures))
    
    # Count duplicates
    from collections import Counter
    counts = Counter(procedures)
    duplicates = {k: v for k, v in counts.items() if v > 1}
    if duplicates:
        print("DUPLICATES FOUND:", duplicates)
    else:
        print("No duplicates found")
else:
    print("postRouter block not found")
PYSCRIPT

Repository: PatrickJS/awesome-cursorrules

Length of output: 237


Remove the duplicate getById procedure from the router example.

Lines 77 and 116 both define getById inside the same createTRPCRouter({...}) object. In JavaScript/TypeScript object literals, duplicate keys cause the second to overwrite the first, making this example invalid. The second definition (lines 116–125) is more complete with author data inclusion, so remove the first occurrence.

Proposed fix
 export const postRouter = createTRPCRouter({
-  getById: publicProcedure
-    .input(z.object({ id: z.string() }))
-    .query(async ({ ctx, input }) => {
-      const post = await ctx.db.post.findUnique({ where: { id: input.id } });
-      if (!post) throw new TRPCError({ code: "NOT_FOUND" });
-      return post;
-    }),
-
   getAll: publicProcedure
     .input(z.object({
       limit: z.number().min(1).max(100).default(20),
       cursor: z.string().nullish(),
     }))
📝 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
export const postRouter = createTRPCRouter({
getById: publicProcedure
.input(z.object({ id: z.string() }))
.query(async ({ ctx, input }) => {
const post = await ctx.db.post.findUnique({ where: { id: input.id } });
if (!post) throw new TRPCError({ code: "NOT_FOUND" });
return post;
}),
export const postRouter = createTRPCRouter({
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@rules/t3-stack-cursorrules-prompt-file/.cursorrules` around lines 77 - 84,
The postRouter contains two duplicate getById entries in the createTRPCRouter
object; remove the earlier simpler getById definition (the one that only queries
ctx.db.post.findUnique and throws NOT_FOUND) so only the later, more complete
getById (which includes author data) remains; update the createTRPCRouter block
to have a single getById procedure and ensure there are no remaining duplicate
keys.

Comment on lines +92 to +96
const posts = await ctx.db.post.findMany({
take: input.limit + 1,
cursor: input.cursor ? { id: input.cursor } : undefined,
orderBy: { createdAt: "desc" },
include: { author: { select: { name: true, image: true } } },
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

find . -name ".cursorrules" -type f

Repository: PatrickJS/awesome-cursorrules

Length of output: 11978


🌐 Web query:

Prisma cursor pagination best practices skip 1 with cursor

💡 Result:

Prisma cursor pagination: best practices (and why skip: 1)

1) Always use a deterministic orderBy (and keep it consistent across pages).
Cursor pagination only makes sense with a stable sort. Prisma recommends ordering by a unique, sequential column (e.g., id or a timestamp you can treat as sequential). If the ordering can change between requests, you’ll see duplicates/missing rows. [1]

2) Use skip: 1 when your cursor is the last item from the previous page.
In Prisma, a cursor query starts “at” the cursor row, so without skip: 1, the cursor row can be included again in the next page (duplicate across pages). Using skip: 1 removes that cursor row from the results. Prisma explicitly calls this out and says you can choose depending on the UX you want. [1]

// page 2: pass the last item from page 1 as the cursor
const page2 = await prisma.post.findMany({
  take: 20,
  skip: 1,                 // prevents including the cursor row again
  cursor: { id: lastId },
  orderBy: { id: "asc" },  // must match across pages
  where: { /* same filters */ },
})

Rule of thumb:

  • If your API returns a nextCursor = lastItem.id, then the next request should typically use cursor: {id: nextCursor}, skip: 1 to avoid duplication. [1]

3) Add a tie-breaker for non-unique sort fields (use a compound order/cursor pattern).
If you sort by something like createdAt, multiple rows can share the same value. Best practice is to order by createdAt then id, and cursor with both (or otherwise ensure uniqueness) to prevent skipping/duplicating rows when timestamps collide. (Common recommendation; also reflected in cursor-pagination best-practice guidance.) [1][4]

4) Keep filters identical between pages.
Changing where conditions mid-pagination can make cursors “jump” unpredictably or cause gaps/duplicates because you’re effectively paginating a different result set. Prisma’s examples show applying the same filter on each page. [1]

5) Prefer cursor pagination over large offsets; verify SQL/indexing for your case.
Prisma documents cursor pagination as more scalable than offset pagination because it avoids deep OFFSET traversal. [1] That said, there have been cases/versions/DB patterns where generated SQL didn’t behave as expected performance-wise in real workloads—so for high-scale tables, inspect query plans and ensure proper indexes on the orderBy columns. [2]

6) Backwards pagination: use negative take (and still skip: 1).
Prisma supports paging backwards by using a negative take and excluding the cursor row with skip: 1. [1]


Primary answer to “skip 1 with cursor”: use skip: 1 when you don’t want the cursor row included again (typical “infinite scroll” / “next page after last item” behavior). Prisma’s docs confirm this and explain the duplicate otherwise. [1]

Sources

[1] Prisma Docs – Pagination (cursor pagination + skip: 1 FAQ) (docs.prisma.io)
[2] prisma/prisma GitHub issue discussing cursor pagination SQL/perf characteristics (github.com)
[4] Explanation of skip: 1 meaning in Prisma cursor pagination (example-focused) (blog.jsontapose.com)

Citations:


🌐 Web query:

Prisma findMany cursor pagination duplicate rows boundary

💡 Result:

Duplicate rows at the page boundary with findMany({ cursor, take }) usually come from one (or both) of these:

  1. You didn’t skip the cursor row, so the last row of page N is returned again as the first row of page N+1. Prisma’s recommended pattern is skip: 1 when you pass cursor. [1]

  2. Your orderBy is not a stable unique ordering, so rows that share the same sort value (e.g., many rows with the same createdAt) can be re-ordered between requests and show up as duplicates/missing across pages. This is a known footgun and has been reported specifically with orderBy: { createdAt: 'asc' } producing duplicates across cursor pages. [2] Prisma’s docs also state the cursor must be a unique column (and you effectively need a deterministic order for pagination). [1]

What to do

  • Always do:

    findMany({
      take: pageSize,
      cursor: { id: lastId },
      skip: 1,              // prevents repeating the cursor row
      orderBy: { id: 'asc'} // stable unique order
    })

    [1]

  • If you need to sort by a non-unique column like createdAt, make the ordering deterministic with a unique tie-breaker (e.g., createdAt then id), and use a compound unique cursor so Prisma can cursor on it:

    • add a compound unique in your schema (example): @@unique([createdAt, id])
    • paginate with orderBy: [{ createdAt: 'asc' }, { id: 'asc' }] and cursor: { createdAt_id: { createdAt, id } } (compound unique input name varies by model)

This “(createdAt, id)” approach is the standard way to prevent boundary duplicates when many rows share the same timestamp. [3]

Sources: Prisma pagination docs (cursor + skip: 1) [1], Prisma issue report about duplicates when sorting by createdAt [2], Prisma discussion/issue guidance on using a compound cursor/tie-breaker for stable pagination [3].

[1] (docs.prisma.io)
[2] (github.com)
[3] (github.com)

Citations:


🏁 Script executed:

cat -n ./rules/t3-stack-cursorrules-prompt-file/.cursorrules | sed -n '90,105p'

Repository: PatrickJS/awesome-cursorrules

Length of output: 698


🏁 Script executed:

cat -n ./rules/t3-stack-cursorrules-prompt-file/.cursorrules | grep -A 6 "findMany"

Repository: PatrickJS/awesome-cursorrules

Length of output: 428


🏁 Script executed:

rg "findMany" ./rules/t3-stack-cursorrules-prompt-file/.cursorrules -A 5 -B 2

Repository: PatrickJS/awesome-cursorrules

Length of output: 384


Fix cursor pagination to prevent duplicate records across pages.

The code at lines 92-96 uses cursor pagination without skip: 1 and non-deterministic ordering, both of which cause boundary row duplication. When cursor is set without skip: 1, Prisma includes the cursor row again in the next page. Additionally, sorting only by createdAt (a non-unique field) can reorder rows between requests when timestamps collide, causing records to appear twice or disappear. Add skip: 1 and include id as a tie-breaker in the orderBy for stable, duplicate-free pagination.

Proposed fix
       const posts = await ctx.db.post.findMany({
         take: input.limit + 1,
+        skip: input.cursor ? 1 : 0,
         cursor: input.cursor ? { id: input.cursor } : undefined,
-        orderBy: { createdAt: "desc" },
+        orderBy: [{ createdAt: "desc" }, { id: "desc" }],
         include: { author: { select: { name: true, image: true } } },
       });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@rules/t3-stack-cursorrules-prompt-file/.cursorrules` around lines 92 - 96,
The cursor pagination in ctx.db.post.findMany is producing duplicate/unstable
pages because cursor rows are included again and ordering uses non-unique
createdAt; update the query to add skip: 1 when input.cursor is present and make
the orderBy deterministic by adding id as a tie-breaker (e.g., orderBy: [{
createdAt: "desc" }, { id: "desc" }]) so posts (and the take: input.limit + 1
logic) returns stable, non-duplicated pages.

@survivorforge
Copy link
Author

Closing this in favor of a simpler, more focused PR. The generated cursorrules files had some issues, so I'll submit just the directory listing instead.

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