.cursorrules (deprecated)
.cursorrules.cursorrulesroot
Quality
49/100
Scores the file, not the repository.Length
2,516 words
39 headings · 21 code blocksRepository
9
— · pushed 394 days agoLast changed
3 days ago
First indexed 3 days ago.1# Project Instructions23Use specification and guidelines as you build the app.45Write the complete code for every step. Do not get lazy.67Your goal is to completely finish whatever I ask for.89You will see <ai_context> tags in the code. These are context tags that you should use to help you understand the codebase.1011## Overview1213This is a web app template.1415## Tech Stack1617- Frontend: Next.js, Tailwind, Shadcn, Framer Motion18- Backend: Postgres, Supabase, Drizzle ORM, Server Actions19- Auth: Clerk20- Payments: Stripe21- Analytics: PostHog22- Deployment: Vercel2324## Project Structure2526- `actions` - Server actions27 - `db` - Database related actions28 - Other actions29- `app` - Next.js app router30 - `api` - API routes31 - `route` - An example route32 - `_components` - One-off components for the route33 - `layout.tsx` - Layout for the route34 - `page.tsx` - Page for the route35- `components` - Shared components36 - `ui` - UI components37 - `utilities` - Utility components38- `db` - Database39 - `schema` - Database schemas40- `lib` - Library code41 - `hooks` - Custom hooks42 - `services` - Business logic services43- `prompts` - Prompt files44- `public` - Static assets45- `types` - Type definitions4647## Rules4849Follow these rules when building the app.5051### General Rules5253- Use `@` to import anything from the app unless otherwise specified54- Use kebab case for all files and folders unless otherwise specified55- Don't update shadcn components unless otherwise specified5657#### Env Rules5859- If you update environment variables, update the `.env.example` file60- All environment variables should go in `.env.local`61- Do not expose environment variables to the frontend62- Use `NEXT_PUBLIC_` prefix for environment variables that need to be accessed from the frontend63- Always access environment variables via the centralized config module (`serverConfig` and `publicEnv` from `@/lib/config`). Do not use `process.env` directly in application code.6465#### Type Rules6667Follow these rules when working with types.6869- When importing types, use `@/types`70- Name files like `example-types.ts`71- All types should go in `types`72- Make sure to export the types in `types/index.ts`73- Prefer interfaces over type aliases74- If referring to db types, use `@/db/schema` such as `SelectTodo` from `todos-schema.ts`7576An example of a type:7778`types/actions-types.ts`7980```ts81export type ActionState<T> =82 | { isSuccess: true; message: string; data: T }83 | { isSuccess: false; message: string; data?: never }84```8586And exporting it:8788`types/index.ts`8990```ts91export * from "./actions-types"92```9394### Frontend Rules9596Follow these rules when working on the frontend.9798It uses Next.js, Tailwind, Shadcn, and Framer Motion.99100#### General Rules101102- Use `lucide-react` for icons103- useSidebar must be used within a SidebarProvider104105#### Components106107- Use divs instead of other html tags unless otherwise specified108- Separate the main parts of a component's html with an extra blank line for visual spacing109- Always tag a component with either `use server` or `use client` at the top, including layouts and pages110111##### Organization112113- All components be named using kebab case like `example-component.tsx` unless otherwise specified114- Put components in `/_components` in the route if one-off components115- Put components in `/components` from the root if shared components116117##### Data Fetching118119- Fetch data in server components and pass the data down as props to client components.120- Use server actions from `/actions` to mutate data.121122##### Server Components123124- Use `"use server"` at the top of the file.125- Implement Suspense for asynchronous data fetching to show loading states while data is being fetched.126- If no asynchronous logic is required for a given server component, you do not need to wrap the component in `<Suspense>`. You can simply return the final UI directly since there is no async boundary needed.127- If asynchronous fetching is required, you can use a `<Suspense>` boundary and a fallback to indicate a loading state while data is loading.128- Server components cannot be imported into client components. If you want to use a server component in a client component, you must pass the as props using the "children" prop129- params in server pages should be awaited such as `const { courseId } = await params` where the type is `params: Promise<{ courseId: string }>`130131Example of a server layout:132133```tsx134"use server"135136export default async function ExampleServerLayout({137 children138}: {139 children: React.ReactNode140}) {141 return children142}143```144145Example of a server page (with async logic):146147```tsx148"use server"149150import { Suspense } from "react"151import { SomeAction } from "@/actions/some-actions"152import SomeComponent from "./_components/some-component"153import SomeSkeleton from "./_components/some-skeleton"154155export default async function ExampleServerPage() {156 return (157 <Suspense fallback={<SomeSkeleton className="some-class" />}>158 <SomeComponentFetcher />159 </Suspense>160 )161}162163async function SomeComponentFetcher() {164 const { data } = await SomeAction()165 return <SomeComponent className="some-class" initialData={data || []} />166}167```168169Example of a server page (no async logic required):170171```tsx172"use server"173174import SomeClientComponent from "./_components/some-client-component"175176// In this case, no asynchronous work is being done, so no Suspense or fallback is required.177export default async function ExampleServerPage() {178 return <SomeClientComponent initialData={[]} />179}180```181182Example of a server component:183184```tsx185"use server"186187interface ExampleServerComponentProps {188 // Your props here189}190191export async function ExampleServerComponent({192 props193}: ExampleServerComponentProps) {194 // Your code here195}196```197198##### Client Components199200- Use `"use client"` at the top of the file201- Client components can safely rely on props passed down from server components, or handle UI interactions without needing <Suspense> if there's no async logic.202- Never use server actions in client components. If you need to create a new server action, create it in `/actions`203204Example of a client page:205206```tsx207"use client"208209export default function ExampleClientPage() {210 // Your code here211}212```213214Example of a client component:215216```tsx217"use client"218219interface ExampleClientComponentProps {220 initialData: any[]221}222223export default function ExampleClientComponent({224 initialData225}: ExampleClientComponentProps) {226 // Client-side logic here227 return <div>{initialData.length} items</div>228}229```230231### Backend Rules232233Follow these rules when working on the backend.234235It uses Postgres, Supabase, Drizzle ORM, and Server Actions.236237#### General Rules238239- Never generate migrations. You do not have to do anything in the `db/migrations` folder inluding migrations and metadata. Ignore it.240241#### Organization242243#### Schemas244245- When importing schemas, use `@/db/schema`246- Name files like `example-schema.ts`247- All schemas should go in `db/schema`248- Make sure to export the schema in `db/schema/index.ts`249- Make sure to add the schema to the `schema` object in `db/db.ts`250- If using a userId, always use `userId: text("user_id").notNull()`251- Always include createdAt and updatedAt columns in all tables252- Make sure to cascade delete when necessary253- Use enums for columns that have a limited set of possible values such as:254255```ts256import { pgEnum } from "drizzle-orm/pg-core"257258export const MEMBERSHIP: PgEnum<Membership> = pgEnum(259 "membership",260 MEMBERSHIP_VALUES261)262263membership: MEMBERSHIP("membership").notNull().default("free")264```265266Example of a schema:267268`db/schema/todos-schema.ts`269270```ts271import { boolean, pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core"272273export const todosTable = pgTable("todos", {274 id: uuid("id").defaultRandom().primaryKey(),275 userId: text("user_id").notNull(),276 content: text("content").notNull(),277 completed: boolean("completed").default(false).notNull(),278 createdAt: timestamp("created_at").defaultNow().notNull(),279 updatedAt: timestamp("updated_at")280 .defaultNow()281 .notNull()282 .$onUpdate(() => new Date())283})284285export type InsertTodo = typeof todosTable.$inferInsert286export type SelectTodo = typeof todosTable.$inferSelect287```288289And exporting it:290291`db/schema/index.ts`292293```ts294export * from "./todos-schema"295```296297And adding it to the schema in `db/db.ts`:298299`db/db.ts`300301```ts302import { todosTable } from "@/db/schema"303304const schema = {305 todos: todosTable306}307```308309And a more complex schema:310311```ts312import { pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core"313314export const chatsTable = pgTable("chats", {315 id: uuid("id").defaultRandom().primaryKey(),316 userId: text("user_id").notNull(),317 name: text("name").notNull(),318 createdAt: timestamp("created_at").defaultNow().notNull(),319 updatedAt: timestamp("updated_at")320 .defaultNow()321 .notNull()322 .$onUpdate(() => new Date())323})324325export type InsertChat = typeof chatsTable.$inferInsert326export type SelectChat = typeof chatsTable.$inferSelect327```328329```ts330import { pgEnum, pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core"331import { chatsTable } from "./chats-schema"332333export const roleEnum = pgEnum("role", ["assistant", "user"])334335export const messagesTable = pgTable("messages", {336 id: uuid("id").defaultRandom().primaryKey(),337 chatId: uuid("chat_id")338 .references(() => chatsTable.id, { onDelete: "cascade" })339 .notNull(),340 content: text("content").notNull(),341 role: roleEnum("role").notNull(),342 createdAt: timestamp("created_at").defaultNow().notNull(),343 updatedAt: timestamp("updated_at")344 .defaultNow()345 .notNull()346 .$onUpdate(() => new Date())347})348349export type InsertMessage = typeof messagesTable.$inferInsert350export type SelectMessage = typeof messagesTable.$inferSelect351```352353And exporting it:354355`db/schema/index.ts`356357```ts358export * from "./chats-schema"359export * from "./messages-schema"360```361362And adding it to the schema in `db/db.ts`:363364`db/db.ts`365366```ts367import { chatsTable, messagesTable } from "@/db/schema"368369const schema = {370 chats: chatsTable,371 messages: messagesTable372}373```374375#### Server Actions376377- When importing actions, use `@/actions` or `@/actions/db` if db related378- DB related actions should go in the `actions/db` folder379- Other actions should go in the `actions` folder380- Name files like `example-actions.ts`381- All actions should go in the `actions` folder382- Only write the needed actions383- Return an ActionState with the needed data type from actions384- Include Action at the end of function names `Ex: exampleFunction -> exampleFunctionAction`385- Actions should return a Promise<ActionState<T>>386- Sort in CRUD order: Create, Read, Update, Delete387- Make sure to return undefined as the data type if the action is not supposed to return any data388- **Date Handling:** For columns defined as `PgDateString` (or any date string type), always convert JavaScript `Date` objects to ISO strings using `.toISOString()` before performing operations (e.g., comparisons or insertions). This ensures value type consistency and prevents type errors.389390```ts391export type ActionState<T> =392 | { isSuccess: true; message: string; data: T }393 | { isSuccess: false; message: string; data?: never }394```395396Example of an action:397398`actions/db/todos-actions.ts`399400```ts401"use server"402403import { db } from "@/db/db"404import { InsertTodo, SelectTodo, todosTable } from "@/db/schema/todos-schema"405import { ActionState } from "@/types"406import { eq } from "drizzle-orm"407408export async function createTodoAction(409 todo: InsertTodo410): Promise<ActionState<SelectTodo>> {411 try {412 const [newTodo] = await db.insert(todosTable).values(todo).returning()413 return {414 isSuccess: true,415 message: "Todo created successfully",416 data: newTodo417 }418 } catch (error) {419 console.error("Error creating todo:", error)420 return { isSuccess: false, message: "Failed to create todo" }421 }422}423424export async function getTodosAction(425 userId: string426): Promise<ActionState<SelectTodo[]>> {427 try {428 const todos = await db.query.todos.findMany({429 where: eq(todosTable.userId, userId)430 })431 return {432 isSuccess: true,433 message: "Todos retrieved successfully",434 data: todos435 }436 } catch (error) {437 console.error("Error getting todos:", error)438 return { isSuccess: false, message: "Failed to get todos" }439 }440}441442export async function updateTodoAction(443 id: string,444 data: Partial<InsertTodo>445): Promise<ActionState<SelectTodo>> {446 try {447 const [updatedTodo] = await db448 .update(todosTable)449 .set(data)450 .where(eq(todosTable.id, id))451 .returning()452453 return {454 isSuccess: true,455 message: "Todo updated successfully",456 data: updatedTodo457 }458 } catch (error) {459 console.error("Error updating todo:", error)460 return { isSuccess: false, message: "Failed to update todo" }461 }462}463464export async function deleteTodoAction(id: string): Promise<ActionState<void>> {465 try {466 await db.delete(todosTable).where(eq(todosTable.id, id))467 return {468 isSuccess: true,469 message: "Todo deleted successfully",470 data: undefined471 }472 } catch (error) {473 console.error("Error deleting todo:", error)474 return { isSuccess: false, message: "Failed to delete todo" }475 }476}477```478479### Auth Rules480481Follow these rules when working on auth.482483It uses Clerk for authentication.484485#### General Rules486487- Import the auth helper with `import { auth } from "@clerk/nextjs/server"` in server components488- await the auth helper in server actions489490### Payments Rules491492Follow these rules when working on payments.493494It uses Stripe for payments.495496### Analytics Rules497498Follow these rules when working on analytics.499500It uses PostHog for analytics.501502# Storage Rules503504Follow these rules when working with Supabase Storage.505506It uses Supabase Storage for file uploads, downloads, and management.507508## General Rules509510- Always use environment variables for bucket names to maintain consistency across environments511- Never hardcode bucket names in the application code512- Always handle file size limits and allowed file types at the application level513- Use the `upsert` method instead of `upload` when you want to replace existing files514- Always implement proper error handling for storage operations515- Use content-type headers when uploading files to ensure proper file handling516517## Organization518519### Buckets520521- Name buckets in kebab-case: `user-uploads`, `profile-images`522- Create separate buckets for different types of files (e.g., `profile-images`, `documents`, `attachments`)523- Document bucket purposes in a central location524- Set appropriate bucket policies (public/private) based on access requirements525- Implement RLS (Row Level Security) policies for buckets that need user-specific access526- Make sure to let me know instructions for setting up RLS policies on Supabase since you can't do this yourself, including the SQL scripts I need to run in the editor527528### File Structure529530- Organize files in folders based on their purpose and ownership531- Use predictable, collision-resistant naming patterns532- Structure: `{bucket}/{userId}/{purpose}/{filename}`533- Example: `profile-images/123e4567-e89b/avatar/profile.jpg`534- Include timestamps in filenames when version history is important535- Example: `documents/123e4567-e89b/contracts/2024-02-13-contract.pdf`536537## Actions538539- When importing storage actions, use `@/actions/storage`540- Name files like `example-storage-actions.ts`541- Include Storage at the end of function names `Ex: uploadFile -> uploadFileStorage`542- Follow the same ActionState pattern as DB actions543544Example of a storage action:545546```ts547"use server"548549import { createClientComponentClient } from "@supabase/auth-helpers-nextjs"550import { ActionState } from "@/types"551552export async function uploadFileStorage(553 bucket: string,554 path: string,555 file: File556): Promise<ActionState<{ path: string }>> {557 try {558 const supabase = createClientComponentClient()559560 const { data, error } = await supabase.storage561 .from(bucket)562 .upload(path, file, {563 upsert: false,564 contentType: file.type565 })566567 if (error) throw error568569 return {570 isSuccess: true,571 message: "File uploaded successfully",572 data: { path: data.path }573 }574 } catch (error) {575 console.error("Error uploading file:", error)576 return { isSuccess: false, message: "Failed to upload file" }577 }578}579```580581## File Handling582583### Upload Rules584585- Always validate file size before upload586- Implement file type validation using both extension and MIME type587- Generate unique filenames to prevent collisions588- Set appropriate content-type headers589- Handle existing files appropriately (error or upsert)590591Example validation:592593```ts594const MAX_FILE_SIZE = 10 * 1024 * 1024 // 10MB595const ALLOWED_TYPES = ["image/jpeg", "image/png", "image/webp"]596597function validateFile(file: File): boolean {598 if (file.size > MAX_FILE_SIZE) {599 throw new Error("File size exceeds limit")600 }601602 if (!ALLOWED_TYPES.includes(file.type)) {603 throw new Error("File type not allowed")604 }605606 return true607}608```609610### Download Rules611612- Always handle missing files gracefully613- Implement proper error handling for failed downloads614- Use signed URLs for private files615616### Delete Rules617618- Implement soft deletes when appropriate619- Clean up related database records when deleting files620- Handle bulk deletions carefully621- Verify ownership before deletion622- Always delete all versions/transforms of a file623624## Security625626### Bucket Policies627628- Make buckets private by default629- Only make buckets public when absolutely necessary630- Use RLS policies to restrict access to authorized users631- Example RLS policy:632633```sql634CREATE POLICY "Users can only access their own files"635ON storage.objects636FOR ALL637USING (auth.uid()::text = (storage.foldername(name))[1]);638```639640### Access Control641642- Generate short-lived signed URLs for private files643- Implement proper CORS policies644- Use separate buckets for public and private files645- Never expose internal file paths646- Validate user permissions before any operation647648## Error Handling649650- Implement specific error types for common storage issues651- Always provide meaningful error messages652- Implement retry logic for transient failures653- Log storage errors separately for monitoring654655## Optimization656657- Implement progressive upload for large files658- Clean up temporary files and failed uploads659- Use batch operations when handling multiple files660
Also in sportiz91/vibe-template
Diff this repo’s formatsOne repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| sportiz91/vibe-template.cursor/rules/auth.mdc · 9 | Cursor rules | securitydo-not | 32/100 | 3 days ago | |
| sportiz91/vibe-template.cursor/rules/storage.mdc · 9 | Cursor rules | archsecuritydo-not | 65/100 | 3 days ago | |
| sportiz91/vibe-template.cursor/rules/backend.mdc · 9 | Cursor rules | do-not | 61/100 | 3 days ago | |
| sportiz91/vibe-template.cursor/rules/coding-standards.mdc · 9 | Cursor rules | styletypesui | 36/100 | 3 days ago | |
| sportiz91/vibe-template.cursor/rules/frontend.mdc · 9 | Cursor rules | do-not | 61/100 | 3 days ago | |
| sportiz91/vibe-template.cursor/rules/general.mdc · 9 | Cursor rules | stylearchsecuritydo-not+1 | 69/100 | 3 days ago | |
| sportiz91/vibe-templateCLAUDE.md · 9 | CLAUDE.md | setuptestlint-formatstyle+7 | 88/100 | 3 days ago |
Similar configs
Same format, overlapping stack, ranked by quality.
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| HerringtonDarkholme/megarepo.cursorrules · 17 | .cursorrules | setupbuildtestlint-format+13 | 96/100 | 3 days ago | |
| survivorforge/cursor-rulesrules/devops-infrastructure/.cursorrules · 16 | .cursorrules | buildteststylesecurity+3 | 93/100 | 2 days ago | |
| survivorforge/cursor-rulesrules/devops-docker/.cursorrules · 16 | .cursorrules | setupbuildteststyle+4 | 93/100 | 2 days ago | |
| survivorforge/cursor-rulesrules/api-microservices/.cursorrules · 16 | .cursorrules | buildteststylearch+5 | 92/100 | 2 days ago | |
| fall-out-bug/sdp_lab.cursorrules · 0 | .cursorrules | setupbuildtestlint-format+3 | 86/100 | 3 days ago | |
| bashdeban/fastmind.cursorrules · 5 | .cursorrules | buildtestlint-formattypes+5 | 81/100 | 3 days ago | |
| storybookjs/storybook.cursorrules · 91k | .cursorrules | teststylearchdo-not+1 | 78/100 | 3 days ago | |
| forem/forem.cursorrules · 23k | .cursorrules | teststyletypesdatabase+4 | 71/100 | 3 days ago |
