Cursor rule
.cursor/rules/backend.mdcFollow these rules when working on the backend.
Cursor rules
Quality
61/100
Scores the file, not the repository.Length
949 words
6 headings · 11 code blocksRepository
9
— · pushed 394 days agoLast changed
3 days ago
First indexed 3 days ago.123456### Backend Rules78Follow these rules when working on the backend.910It uses Postgres, Supabase, Drizzle ORM, and Server Actions.1112#### General Rules1314- Never generate migrations. You do not have to do anything in the `db/migrations` folder including migrations and metadata. Ignore it.1516#### Organization1718#### Schemas1920- When importing schemas, use `@/db/schema`21- Name files like `example-schema.ts`22- All schemas should go in `db/schema`23- Make sure to export the schema in `db/schema/index.ts`24- Make sure to add the schema to the `schema` object in `db/db.ts`25- If using a userId, always use `userId: text("user_id").notNull()`26- Always include createdAt and updatedAt columns in all tables27- Make sure to cascade delete when necessary28- Use enums for columns that have a limited set of possible values such as:2930```ts31import { pgEnum } from "drizzle-orm/pg-core"3233export const MEMBERSHIP: PgEnum<Membership> = pgEnum(34 "membership",35 MEMBERSHIP_VALUES36)3738membership: MEMBERSHIP("membership").notNull().default("free")39```4041Example of a schema:4243`db/schema/todos-schema.ts`4445```ts46import { boolean, pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core"4748export const todosTable = pgTable("todos", {49 id: uuid("id").defaultRandom().primaryKey(),50 userId: text("user_id").notNull(),51 content: text("content").notNull(),52 completed: boolean("completed").default(false).notNull(),53 createdAt: timestamp("created_at").defaultNow().notNull(),54 updatedAt: timestamp("updated_at")55 .defaultNow()56 .notNull()57 .$onUpdate(() => new Date())58})5960export type InsertTodo = typeof todosTable.$inferInsert61export type SelectTodo = typeof todosTable.$inferSelect62```6364And exporting it:6566`db/schema/index.ts`6768```ts69export * from "./todos-schema"70```7172And adding it to the schema in `db/db.ts`:7374`db/db.ts`7576```ts77import { todosTable } from "@/db/schema"7879const schema = {80 todos: todosTable81}82```8384And a more complex schema:8586```ts87import { pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core"8889export const chatsTable = pgTable("chats", {90 id: uuid("id").defaultRandom().primaryKey(),91 userId: text("user_id").notNull(),92 name: text("name").notNull(),93 createdAt: timestamp("created_at").defaultNow().notNull(),94 updatedAt: timestamp("updated_at")95 .defaultNow()96 .notNull()97 .$onUpdate(() => new Date())98})99100export type InsertChat = typeof chatsTable.$inferInsert101export type SelectChat = typeof chatsTable.$inferSelect102```103104```ts105import { pgEnum, pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core"106import { chatsTable } from "./chats-schema"107108export const roleEnum = pgEnum("role", ["assistant", "user"])109110export const messagesTable = pgTable("messages", {111 id: uuid("id").defaultRandom().primaryKey(),112 chatId: uuid("chat_id")113 .references(() => chatsTable.id, { onDelete: "cascade" })114 .notNull(),115 content: text("content").notNull(),116 role: roleEnum("role").notNull(),117 createdAt: timestamp("created_at").defaultNow().notNull(),118 updatedAt: timestamp("updated_at")119 .defaultNow()120 .notNull()121 .$onUpdate(() => new Date())122})123124export type InsertMessage = typeof messagesTable.$inferInsert125export type SelectMessage = typeof messagesTable.$inferSelect126```127128And exporting it:129130`db/schema/index.ts`131132```ts133export * from "./chats-schema"134export * from "./messages-schema"135```136137And adding it to the schema in `db/db.ts`:138139`db/db.ts`140141```ts142import { chatsTable, messagesTable } from "@/db/schema"143144const schema = {145 chats: chatsTable,146 messages: messagesTable147}148```149150#### Server Actions151152- When importing actions, use `@/actions` or `@/actions/db` if db related153- DB related actions should go in the `actions/db` folder154- Other actions should go in the `actions` folder155- Name files like `example-actions.ts`156- All actions should go in the `actions` folder157- Only write the needed actions158- Return an ActionState with the needed data type from actions159- Include Action at the end of function names `Ex: exampleFunction -> exampleFunctionAction`160- Actions should return a Promise<ActionState<T>>161- Sort in CRUD order: Create, Read, Update, Delete162- Make sure to return undefined as the data type if the action is not supposed to return any data163- **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.164165```ts166export type ActionState<T> =167 | { isSuccess: true; message: string; data: T }168 | { isSuccess: false; message: string; data?: never }169```170171Example of an action:172173`actions/db/todos-actions.ts`174175```ts176"use server"177178import { db } from "@/db/db"179import { InsertTodo, SelectTodo, todosTable } from "@/db/schema/todos-schema"180import { ActionState } from "@/types"181import { eq } from "drizzle-orm"182183export async function createTodoAction(184 todo: InsertTodo185): Promise<ActionState<SelectTodo>> {186 try {187 const [newTodo] = await db.insert(todosTable).values(todo).returning()188 return {189 isSuccess: true,190 message: "Todo created successfully",191 data: newTodo192 }193 } catch (error) {194 console.error("Error creating todo:", error)195 return { isSuccess: false, message: "Failed to create todo" }196 }197}198199export async function getTodosAction(200 userId: string201): Promise<ActionState<SelectTodo[]>> {202 try {203 const todos = await db.query.todos.findMany({204 where: eq(todosTable.userId, userId)205 })206 return {207 isSuccess: true,208 message: "Todos retrieved successfully",209 data: todos210 }211 } catch (error) {212 console.error("Error getting todos:", error)213 return { isSuccess: false, message: "Failed to get todos" }214 }215}216217export async function updateTodoAction(218 id: string,219 data: Partial<InsertTodo>220): Promise<ActionState<SelectTodo>> {221 try {222 const [updatedTodo] = await db223 .update(todosTable)224 .set(data)225 .where(eq(todosTable.id, id))226 .returning()227228 return {229 isSuccess: true,230 message: "Todo updated successfully",231 data: updatedTodo232 }233 } catch (error) {234 console.error("Error updating todo:", error)235 return { isSuccess: false, message: "Failed to update todo" }236 }237}238239export async function deleteTodoAction(id: string): Promise<ActionState<void>> {240 try {241 await db.delete(todosTable).where(eq(todosTable.id, id))242 return {243 isSuccess: true,244 message: "Todo deleted successfully",245 data: undefined246 }247 } catch (error) {248 console.error("Error deleting todo:", error)249 return { isSuccess: false, message: "Failed to delete todo" }250 }251}252```253254#### Services255256- When importing services, use `@/lib/services`257- Name files like `example-service.ts`258- All services should go in the `lib/services` folder259- Services handle complex business logic that would otherwise make server actions too large260- Services should be pure functions that take inputs and return outputs261- Services should not directly handle HTTP requests or database operations262- Use services for external API integrations, complex calculations, and domain-specific logic263- Follow the data flow: Components → Actions → Services264- Export functions using named exports265266Example of a service:267268`lib/services/grammar-correction.ts`269270```ts271import OpenAI from "openai"272import { getCompletion } from "@/lib/services/open-ai"273274const SYSTEM_MESSAGE: string = `You are a grammar correction assistant...`275276export const getPunchyText = async (277 userMessage: string278): Promise<string | undefined> => {279 const completion: OpenAI.Chat.Completions.ChatCompletion =280 await getCompletion(userMessage, {281 systemMessage: SYSTEM_MESSAGE,282 maxTokens: 280,283 temperature: 0.7284 })285286 return completion?.choices?.[0]?.message?.content?.trim()287}288```
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/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-template.cursorrules · 9 | .cursorrules | stylearchsecuritydo-not+1 | 49/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 |
|---|---|---|---|---|---|
| hiromaily/go-crypto-wallet.cursor/rules/typescript.mdc · 126 | Cursor rules | setupbuildtestlint-format+6 | 100/100 | 3 days ago | |
| TechSquidTV/Hermes.cursor/rules/10-hermes-api.mdc · 45 | Cursor rules | testlint-formatstylearch+5 | 100/100 | 3 days ago | |
| markstev/mark-starter.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+6 | 99/100 | 3 days ago | |
| Allymahmoud/case-intake-platform.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 3 days ago | |
| dodgecfr/combatfilms-webapp.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 3 days ago | |
| deifos/clipmira-subtitles.cursor/rules/frontend.mdc · 1 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 3 days ago | |
| langflow-ai/langflow.cursor/rules/docs_development.mdc · 153k | Cursor rules | setupbuildtestlint-format+7 | 97/100 | 3 days ago | |
| TechSquidTV/Hermes.cursor/rules/20-hermes-api-tests.mdc · 45 | Cursor rules | teststyletesting-strategysecurity+3 | 97/100 | 3 days ago |
