Add Survivor Forge cursor rules collection#186
Add Survivor Forge cursor rules collection#186survivorforge wants to merge 3 commits intoPatrickJS:mainfrom
Conversation
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).
📝 WalkthroughWalkthroughThis 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
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
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 | 🟡 MinorReorder
T3 Stackto keep Backend/Full-Stack alphabetized.Line 157 is out of order in the category list (
T3 Stackshould be placed beforeTypeScript ...andTYPO3 ...entries).As per coding guidelines, "Maintain alphabetical order within each category in the README.md file".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.🤖 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
📒 Files selected for processing (5)
README.mdrules/clean-code-principles-cursorrules-prompt-file/.cursorrulesrules/mern-stack-cursorrules-prompt-file/.cursorrulesrules/security-best-practices-cursorrules-prompt-file/.cursorrulesrules/t3-stack-cursorrules-prompt-file/.cursorrules
- 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>
There was a problem hiding this comment.
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
📒 Files selected for processing (1)
rules/t3-stack-cursorrules-prompt-file/.cursorrules
| 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; | ||
| }), |
There was a problem hiding this comment.
🧩 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")
PYSCRIPTRepository: 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.
| 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.
| 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 } } }, |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find . -name ".cursorrules" -type fRepository: 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 usecursor: {id: nextCursor}, skip: 1to 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:
- 1: https://docs.prisma.io/docs/v6/orm/prisma-client/queries/pagination?utm_source=openai
- 2: Prisma is not using
LIMITfor cursor based pagination. prisma/prisma#15710 - 3: https://blog.jsontapose.com/posts/prisma-cursor-pagination-and-skip-1-a14080/?utm_source=openai
🌐 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:
-
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: 1when you passcursor. [1] -
Your
orderByis not a stable unique ordering, so rows that share the same sort value (e.g., many rows with the samecreatedAt) can be re-ordered between requests and show up as duplicates/missing across pages. This is a known footgun and has been reported specifically withorderBy: { 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.,createdAtthenid), 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' }]andcursor: { createdAt_id: { createdAt, id } }(compound unique input name varies by model)
- add a compound unique in your schema (example):
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:
- 1: https://docs.prisma.io/docs/v6/orm/prisma-client/queries/pagination?utm_source=openai
- 2: Pagination issue with cursor and sorting by createdAt prisma/prisma#16991
- 3: Improve cursor pagination to tolerate hard deletes and avoid looking up the row at the cursor prisma/prisma#19159
🏁 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 2Repository: 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.
|
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. |
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