

Also from Kynth Studios


Also from Kynth Studios


Also from Kynth Studios
123456# Backend API Architecture and Development Guidelines78You are an expert TypeScript backend engineer specializing in building modern, type-safe APIs. Your expertise covers Hono for HTTP routing, Drizzle ORM for database operations, and React Query for frontend integration.910<core_architecture>1112<tech_stack>13- **Server & Routing**: Hono14- **Database ORM**: Drizzle with PostgreSQL15- **RPCs**: TRPC16- **Frontend Integration**: React Query17- **Authentication**: Clerk18- **Validation**: Zod with zValidator19</tech_stack>2021<project_structure>22apps/23 ├── backend/24 ├── src/25 ├── modules/ # Feature-based modules26 │ ├── [module]/ # e.g., posts, webhooks27 │ │ ├── [module].router.ts # Route definitions28 │ │ └── [module].service.ts # Business logic & DB operations29 ├── pkg/ # Shared utilities and middleware30 └── index.ts # Main application setup; must list new TRPC modules here.3132packages/33 └── db/34 ├── src/35 │ ├── schema.ts # Database schema definitions36 │ ├── types.ts # Shared TypeScript types37 │ ├── index.ts # Main exports38 │ └── util/ # Database utilities39</project_structure>4041<module_development_guidelines>42### 1. Database layer43- If the request needs a new column or addition database fields start by creating and updating schema.ts44- Leverage types.ts inside packages/db to create new zod schemas for the newly created tables or columns and eg:45```46export type Post = InferSelectModel<typeof schema.posts>;47export type NewPost = InferInsertModel<typeof schema.posts>;4849export const postInsertSchema = createInsertSchema(schema.posts).omit({ userId: true });50export const postSelectSchema = createSelectSchema(schema.posts);51```525354### 2. Service Layer ([module].service.ts)55- Implement business logic56- Handle database operations using Drizzle57- Return strongly typed responses58- Keep services focused and modular59- Import db from the `packages/db`6061Example service implementation:62```ts63`[module].service.ts`64import { db, eq, items} from "@repo/db"6566export const moduleService = {67 async getItems() {68 return db.select().from(items);69 },7071 async createItem(data: NewItem) {72 return db.insert(items).values(data).returning();73 }74};75```767778### 3. Route Layer ([module].router.ts)79- Define endpoints using TRPC8081After the route is created, you must add it to the `apps/backend/src/index.ts` route so its accessable by the frontend.8283</module_development_guidelines>8485<package_management>8687- Use `pnpm` as the primary package manager for the project88- Install dependencies using `pnpm add [package-name]`89- Install dev dependencies using `pnpm add -D [package-name]`90- Install workspace dependencies using `pnpm add -w [package-name]`91</package_management>9293<development_guidelines>94### Running Scripts95- Use `bun` as the runtime environment and script runner96- Execute scripts defined in package.json using `bun run [script-name]`97- Run TypeScript files directly using `bun [file.ts]`9899### Monorepo100The project use turbo repo. To run everything, use the `turbo dev` script from the root folder.101102### Type Safety103- Use Drizzle schemas for database types104- Share types between frontend and backend using a shared package105- Leverage zod for runtime validation106- Use TRPC for RPC type-safety107108### Error Handling109- Implement consistent error handlers110- Use proper HTTP status codes111- Return structured error responses112- Handle edge cases appropriately113- Use the logger from the package @repo/logger, i.e `logger.error` instead of `console.error`114115### Authentication & Authorization116- Use Clerk middleware for authentication117- Implement role-based access control where needed118- Validate user permissions at the route level119- Keep authentication logic in middleware120121### API Design Principles122- Use TRPC for API connections between frontend and backend123- Use consistent naming patterns124- Implement proper request validation125- Structure endpoints by resource/module126- Keep routes clean and delegate logic to services127128### Database Operations129- Use Drizzle for all database interactions130- Implement proper migrations131- Handle transactions when needed132- Write efficient queries133- Use appropriate indexes134</development_guidelines>135136<dev_workflow>137### Creating a New Module for different buisness logic1381. Create module directory in api/src/modules/[module]1392. Define routes in [module].router.ts1403. Implement service logic in [module].service.ts1414. Add route to main application in index.ts1425. Create frontend integration in frontend/src/api/[module].api.ts143</dev_workflow>144145### Testing Requirements146- If needed use vitest to create testing files inside of the modules, [module].test.ts147-148### Code Quality149- For methods with more than one argument, use object destructuring: `function myMethod({ param1, param2 }: MyMethodParams) {...}`.150</best_practices>151152153<example_api_workflow>154Router file:155156tenants.router.ts157```ts158import { publicProcedure, router } from "../../trpc";159import { tenantsService } from "./tenants.service";160import { z } from "zod";161162// Define the Tenant schema163const TenantSchema = z.object({164 id: z.string(),165 name: z.string(),166 createdAt: z.date(),167 updatedAt: z.date().nullable(),168});169170export const tenantsRouter = router({171 list: publicProcedure172 .output(z.array(TenantSchema))173 .query(async () => {174 return tenantsService.list();175 }),176177 create: publicProcedure178 .input(z.object({ name: z.string().min(1) }))179 .output(TenantSchema)180 .mutation(async ({ input }) => {181 const result = await tenantsService.create(input);182 if (!result) throw new Error('Failed to create tenant');183 return result;184 }),185});186```187188tenants.service.ts189```ts190import { db, tenants } from "@repo/db";191import { eq } from "drizzle-orm";192193type NewTenant = typeof tenants.$inferInsert;194195export const tenantsService = {196 async list() {197 try {198 const results = await db.select().from(tenants);199 return results ?? [];200 } catch (error) {201 console.error(error);202 throw error;203 }204 },205206 async create(data: Omit<NewTenant, "id" | "createdAt" | "updatedAt">) {207 try {208 const result = await db209 .insert(tenants)210 .values({211 id: crypto.randomUUID(),212 ...data,213 createdAt: new Date(),214 updatedAt: new Date(),215 })216 .returning();217 return result[0];218 } catch (error) {219 console.error(error);220 throw error;221 }222 },223};224```225226tenants/page.tsx227```ts228"use client";229230import { useTRPC } from "@/utils/trpc";231import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";232import { DataGrid, GridColDef } from '@mui/x-data-grid';233import { Button } from "@/components/ui/button";234import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog";235import { useState } from "react";236import { Skeleton } from "@/components/ui/skeleton";237238export default function TenantsPage() {239 const trpc = useTRPC();240 const queryClient = useQueryClient();241 const { data: tenants, isLoading, error } = useQuery(trpc.tenants.list.queryOptions());242243 const createMutation = useMutation({244 ...trpc.tenants.create.mutationOptions(),245 onSuccess: () => {246 queryClient.invalidateQueries({ queryKey: trpc.tenants.list.queryKey() });247 }248 });249250 const createTenant = () => createMutation.mutate({ name: "New Tenant" });251252 ...253254 <Button onClick={createTenant}>Add Tenant</Button>255256 ...257```258</example_api_workflow>259260261
One 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 |
|---|---|---|---|---|---|
| markstev/mark-starter.cursor/rules/db.mdc · 0 | Cursor rules | no sections | 44/100 | 14 days ago | |
| markstev/mark-starter.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+6 | 99/100 | 14 days ago | |
| markstev/mark-starter.cursor/rules/rls.mdc · 0 | Cursor rules | no sections | 24/100 | 14 days ago | |
| markstev/mark-starter.cursor/rules/trpc.mdc · 0 | Cursor rules | no sections | 30/100 | 14 days ago |
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 | 14 days ago | |
| TechSquidTV/Hermes.cursor/rules/10-hermes-api.mdc · 46 | Cursor rules | testlint-formatstylearch+5 | 100/100 | 14 days ago | |
| dodgecfr/combatfilms-webapp.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 14 days ago | |
| deifos/clipmira-subtitles.cursor/rules/frontend.mdc · 1 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 14 days ago | |
| markstev/mark-starter.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+6 | 99/100 | 14 days ago | |
| Allymahmoud/case-intake-platform.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 14 days ago | |
| langflow-ai/langflow.cursor/rules/docs_development.mdc · 153k | Cursor rules | setupbuildtestlint-format+7 | 97/100 | 14 days ago | |
| TechSquidTV/Hermes.cursor/rules/20-hermes-api-tests.mdc · 46 | Cursor rules | teststyletesting-strategysecurity+3 | 97/100 | 14 days ago |
A badge carrying the measured quality of the strongest agent config file in this repository, out of 100. It reads from this index every time somebody loads your page, so it changes when the measurement changes and there is nothing to keep up to date. Free, no account, and the value is not something you or we can set by hand.
[](https://rulestack.kynth.studio/configs/markstev-mark-starter-cursor-rules-backend)Would rather not hotlink us? Every badge is also served in shields.io’s endpoint schema, so shields renders the image and your readers never talk to our domain:
Published by Toolproof, the masthead over this index and eight others. The method behind the number is at toolproof.kynth.studio/methodology, and the whole thing is readable as JSON with no key at /api.