RuleStack

Configs

Stacks

Compare

Diff

RuleStack

Configs

Stacks

Compare

Diff

Read API

RuleStack

Configs

Stacks

Compare

Diff

Read API

Diff/sportiz91-vibe-template-cursor-rules-backend ↔ sportiz91-vibe-template-cursorrules

Comparison

A · Cursor rules · sportiz91/vibe-templateB · .cursorrules · sportiz91/vibe-template
What each file covers, counted
DimensionSharedOnly in AOnly in BOverlap
Sections10244%
Commands000—
Section tags10420%

What each file covers

Sections

1 shared · 0 only in A · 24 only in B
  • + Project Instructions
  • + Overview
  • + Tech Stack
  • + Project Structure
  • + Rules
  • + General Rules
  • + Frontend Rules
  • + Auth Rules
  • + Payments Rules
  • + Analytics Rules
  • + Storage Rules
  • + Organization
  • + Buckets
  • + File Structure
  • + Actions
  • + File Handling
  • + Upload Rules
  • + Download Rules
  • + Delete Rules
  • + Security
  • + Bucket Policies
  • + Access Control
  • + Error Handling
  • + Optimization
  •   Backend Rules

Commands

neither file has any

Section tags

1 shared · 0 only in A · 4 only in B
  • + code-style
  • + architecture
  • + security
  • + agent-behaviour
  •   do-not

Line diff

+403 added−31 removed257 unchanged38.9% identical
sportiz91/vibe-template · .cursor/rules/backend.mdc
@@ −1 @@
1---
2description: Follow these rules when working on the backend.
3globs:
4alwaysApply: false
5---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6### Backend Rules
7 
8Follow these rules when working on the backend.
@@ −11 @@
11 
12#### General Rules
13 
14- Never generate migrations. You do not have to do anything in the `db/migrations` folder including migrations and metadata. Ignore it.
15 
16#### Organization
17 
@@ −251 @@
251}
252```
253 
254#### Services
255 
256- When importing services, use `@/lib/services`
257- Name files like `example-service.ts`
258- All services should go in the `lib/services` folder
259- Services handle complex business logic that would otherwise make server actions too large
260- Services should be pure functions that take inputs and return outputs
261- Services should not directly handle HTTP requests or database operations
262- Use services for external API integrations, complex calculations, and domain-specific logic
263- Follow the data flow: Components → Actions → Services
264- Export functions using named exports
265 
266Example of a service:
267 
268`lib/services/grammar-correction.ts`
269 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
270```ts
271import OpenAI from "openai"
272import { getCompletion } from "@/lib/services/open-ai"
273 
274const SYSTEM_MESSAGE: string = `You are a grammar correction assistant...`
 
275 
276export const getPunchyText = async (
277 userMessage: string
278): Promise<string | undefined> => {
279 const completion: OpenAI.Chat.Completions.ChatCompletion =
280 await getCompletion(userMessage, {
281 systemMessage: SYSTEM_MESSAGE,
282 maxTokens: 280,
283 temperature: 0.7
284 })
285 
286 return completion?.choices?.[0]?.message?.content?.trim()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
287}
288```
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
sportiz91/vibe-template · .cursorrules
@@ +1 @@
1# Project Instructions
2 
3Use specification and guidelines as you build the app.
4 
5Write the complete code for every step. Do not get lazy.
6 
7Your goal is to completely finish whatever I ask for.
8 
9You will see <ai_context> tags in the code. These are context tags that you should use to help you understand the codebase.
10 
11## Overview
12 
13This is a web app template.
14 
15## Tech Stack
16 
17- Frontend: Next.js, Tailwind, Shadcn, Framer Motion
18- Backend: Postgres, Supabase, Drizzle ORM, Server Actions
19- Auth: Clerk
20- Payments: Stripe
21- Analytics: PostHog
22- Deployment: Vercel
23 
24## Project Structure
25 
26- `actions` - Server actions
27 - `db` - Database related actions
28 - Other actions
29- `app` - Next.js app router
30 - `api` - API routes
31 - `route` - An example route
32 - `_components` - One-off components for the route
33 - `layout.tsx` - Layout for the route
34 - `page.tsx` - Page for the route
35- `components` - Shared components
36 - `ui` - UI components
37 - `utilities` - Utility components
38- `db` - Database
39 - `schema` - Database schemas
40- `lib` - Library code
41 - `hooks` - Custom hooks
42 - `services` - Business logic services
43- `prompts` - Prompt files
44- `public` - Static assets
45- `types` - Type definitions
46 
47## Rules
48 
49Follow these rules when building the app.
50 
51### General Rules
52 
53- Use `@` to import anything from the app unless otherwise specified
54- Use kebab case for all files and folders unless otherwise specified
55- Don't update shadcn components unless otherwise specified
56 
57#### Env Rules
58 
59- If you update environment variables, update the `.env.example` file
60- All environment variables should go in `.env.local`
61- Do not expose environment variables to the frontend
62- Use `NEXT_PUBLIC_` prefix for environment variables that need to be accessed from the frontend
63- Always access environment variables via the centralized config module (`serverConfig` and `publicEnv` from `@/lib/config`). Do not use `process.env` directly in application code.
64 
65#### Type Rules
66 
67Follow these rules when working with types.
68 
69- 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 aliases
74- If referring to db types, use `@/db/schema` such as `SelectTodo` from `todos-schema.ts`
75 
76An example of a type:
77 
78`types/actions-types.ts`
79 
80```ts
81export type ActionState<T> =
82 | { isSuccess: true; message: string; data: T }
83 | { isSuccess: false; message: string; data?: never }
84```
85 
86And exporting it:
87 
88`types/index.ts`
89 
90```ts
91export * from "./actions-types"
92```
93 
94### Frontend Rules
95 
96Follow these rules when working on the frontend.
97 
98It uses Next.js, Tailwind, Shadcn, and Framer Motion.
99 
100#### General Rules
101 
102- Use `lucide-react` for icons
103- useSidebar must be used within a SidebarProvider
104 
105#### Components
106 
107- Use divs instead of other html tags unless otherwise specified
108- Separate the main parts of a component's html with an extra blank line for visual spacing
109- Always tag a component with either `use server` or `use client` at the top, including layouts and pages
110 
111##### Organization
112 
113- All components be named using kebab case like `example-component.tsx` unless otherwise specified
114- Put components in `/_components` in the route if one-off components
115- Put components in `/components` from the root if shared components
116 
117##### Data Fetching
118 
119- Fetch data in server components and pass the data down as props to client components.
120- Use server actions from `/actions` to mutate data.
121 
122##### Server Components
123 
124- 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" prop
129- params in server pages should be awaited such as `const { courseId } = await params` where the type is `params: Promise<{ courseId: string }>`
130 
131Example of a server layout:
132 
133```tsx
134"use server"
135 
136export default async function ExampleServerLayout({
137 children
138}: {
139 children: React.ReactNode
140}) {
141 return children
142}
143```
144 
145Example of a server page (with async logic):
146 
147```tsx
148"use server"
149 
150import { Suspense } from "react"
151import { SomeAction } from "@/actions/some-actions"
152import SomeComponent from "./_components/some-component"
153import SomeSkeleton from "./_components/some-skeleton"
154 
155export default async function ExampleServerPage() {
156 return (
157 <Suspense fallback={<SomeSkeleton className="some-class" />}>
158 <SomeComponentFetcher />
159 </Suspense>
160 )
161}
162 
163async function SomeComponentFetcher() {
164 const { data } = await SomeAction()
165 return <SomeComponent className="some-class" initialData={data || []} />
166}
167```
168 
169Example of a server page (no async logic required):
170 
171```tsx
172"use server"
173 
174import SomeClientComponent from "./_components/some-client-component"
175 
176// 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```
181 
182Example of a server component:
183 
184```tsx
185"use server"
186 
187interface ExampleServerComponentProps {
188 // Your props here
189}
190 
191export async function ExampleServerComponent({
192 props
193}: ExampleServerComponentProps) {
194 // Your code here
195}
196```
197 
198##### Client Components
199 
200- Use `"use client"` at the top of the file
201- 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`
203 
204Example of a client page:
205 
206```tsx
207"use client"
208 
209export default function ExampleClientPage() {
210 // Your code here
211}
212```
213 
214Example of a client component:
215 
216```tsx
217"use client"
218 
219interface ExampleClientComponentProps {
220 initialData: any[]
221}
222 
223export default function ExampleClientComponent({
224 initialData
225}: ExampleClientComponentProps) {
226 // Client-side logic here
227 return <div>{initialData.length} items</div>
228}
229```
230 
231### Backend Rules
232 
233Follow these rules when working on the backend.
@@ +236 @@
236 
237#### General Rules
238 
239- Never generate migrations. You do not have to do anything in the `db/migrations` folder inluding migrations and metadata. Ignore it.
240 
241#### Organization
242 
@@ +476 @@
476}
477```
478 
479### Auth Rules
480 
481Follow these rules when working on auth.
 
 
 
 
 
 
 
 
482 
483It uses Clerk for authentication.
484 
485#### General Rules
486 
487- Import the auth helper with `import { auth } from "@clerk/nextjs/server"` in server components
488- await the auth helper in server actions
489 
490### Payments Rules
491 
492Follow these rules when working on payments.
493 
494It uses Stripe for payments.
495 
496### Analytics Rules
497 
498Follow these rules when working on analytics.
499 
500It uses PostHog for analytics.
501 
502# Storage Rules
503 
504Follow these rules when working with Supabase Storage.
505 
506It uses Supabase Storage for file uploads, downloads, and management.
507 
508## General Rules
509 
510- Always use environment variables for bucket names to maintain consistency across environments
511- Never hardcode bucket names in the application code
512- Always handle file size limits and allowed file types at the application level
513- Use the `upsert` method instead of `upload` when you want to replace existing files
514- Always implement proper error handling for storage operations
515- Use content-type headers when uploading files to ensure proper file handling
516 
517## Organization
518 
519### Buckets
520 
521- 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 location
524- Set appropriate bucket policies (public/private) based on access requirements
525- Implement RLS (Row Level Security) policies for buckets that need user-specific access
526- 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 editor
527 
528### File Structure
529 
530- Organize files in folders based on their purpose and ownership
531- Use predictable, collision-resistant naming patterns
532- Structure: `{bucket}/{userId}/{purpose}/{filename}`
533- Example: `profile-images/123e4567-e89b/avatar/profile.jpg`
534- Include timestamps in filenames when version history is important
535- Example: `documents/123e4567-e89b/contracts/2024-02-13-contract.pdf`
536 
537## Actions
538 
539- 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 actions
543 
544Example of a storage action:
545 
546```ts
547"use server"
 
548 
549import { createClientComponentClient } from "@supabase/auth-helpers-nextjs"
550import { ActionState } from "@/types"
551 
552export async function uploadFileStorage(
553 bucket: string,
554 path: string,
555 file: File
556): Promise<ActionState<{ path: string }>> {
557 try {
558 const supabase = createClientComponentClient()
 
 
559 
560 const { data, error } = await supabase.storage
561 .from(bucket)
562 .upload(path, file, {
563 upsert: false,
564 contentType: file.type
565 })
566 
567 if (error) throw error
568 
569 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```
580 
581## File Handling
582 
583### Upload Rules
584 
585- Always validate file size before upload
586- Implement file type validation using both extension and MIME type
587- Generate unique filenames to prevent collisions
588- Set appropriate content-type headers
589- Handle existing files appropriately (error or upsert)
590 
591Example validation:
592 
593```ts
594const MAX_FILE_SIZE = 10 * 1024 * 1024 // 10MB
595const ALLOWED_TYPES = ["image/jpeg", "image/png", "image/webp"]
596 
597function validateFile(file: File): boolean {
598 if (file.size > MAX_FILE_SIZE) {
599 throw new Error("File size exceeds limit")
600 }
601 
602 if (!ALLOWED_TYPES.includes(file.type)) {
603 throw new Error("File type not allowed")
604 }
605 
606 return true
607}
608```
609 
610### Download Rules
611 
612- Always handle missing files gracefully
613- Implement proper error handling for failed downloads
614- Use signed URLs for private files
615 
616### Delete Rules
617 
618- Implement soft deletes when appropriate
619- Clean up related database records when deleting files
620- Handle bulk deletions carefully
621- Verify ownership before deletion
622- Always delete all versions/transforms of a file
623 
624## Security
625 
626### Bucket Policies
627 
628- Make buckets private by default
629- Only make buckets public when absolutely necessary
630- Use RLS policies to restrict access to authorized users
631- Example RLS policy:
632 
633```sql
634CREATE POLICY "Users can only access their own files"
635ON storage.objects
636FOR ALL
637USING (auth.uid()::text = (storage.foldername(name))[1]);
638```
639 
640### Access Control
641 
642- Generate short-lived signed URLs for private files
643- Implement proper CORS policies
644- Use separate buckets for public and private files
645- Never expose internal file paths
646- Validate user permissions before any operation
647 
648## Error Handling
649 
650- Implement specific error types for common storage issues
651- Always provide meaningful error messages
652- Implement retry logic for transient failures
653- Log storage errors separately for monitoring
654 
655## Optimization
656 
657- Implement progressive upload for large files
658- Clean up temporary files and failed uploads
659- Use batch operations when handling multiple files
660 
@@ −1 +1 @@
1−---
2−description: Follow these rules when working on the backend.
3−globs:
4−alwaysApply: false
5−---
1+# Project Instructions
2+ 
3+Use specification and guidelines as you build the app.
4+ 
5+Write the complete code for every step. Do not get lazy.
6+ 
7+Your goal is to completely finish whatever I ask for.
8+ 
9+You will see <ai_context> tags in the code. These are context tags that you should use to help you understand the codebase.
10+ 
11+## Overview
12+ 
13+This is a web app template.
14+ 
15+## Tech Stack
16+ 
17+- Frontend: Next.js, Tailwind, Shadcn, Framer Motion
18+- Backend: Postgres, Supabase, Drizzle ORM, Server Actions
19+- Auth: Clerk
20+- Payments: Stripe
21+- Analytics: PostHog
22+- Deployment: Vercel
23+ 
24+## Project Structure
25+ 
26+- `actions` - Server actions
27+ - `db` - Database related actions
28+ - Other actions
29+- `app` - Next.js app router
30+ - `api` - API routes
31+ - `route` - An example route
32+ - `_components` - One-off components for the route
33+ - `layout.tsx` - Layout for the route
34+ - `page.tsx` - Page for the route
35+- `components` - Shared components
36+ - `ui` - UI components
37+ - `utilities` - Utility components
38+- `db` - Database
39+ - `schema` - Database schemas
40+- `lib` - Library code
41+ - `hooks` - Custom hooks
42+ - `services` - Business logic services
43+- `prompts` - Prompt files
44+- `public` - Static assets
45+- `types` - Type definitions
46+ 
47+## Rules
48+ 
49+Follow these rules when building the app.
50+ 
51+### General Rules
52+ 
53+- Use `@` to import anything from the app unless otherwise specified
54+- Use kebab case for all files and folders unless otherwise specified
55+- Don't update shadcn components unless otherwise specified
56+ 
57+#### Env Rules
58+ 
59+- If you update environment variables, update the `.env.example` file
60+- All environment variables should go in `.env.local`
61+- Do not expose environment variables to the frontend
62+- Use `NEXT_PUBLIC_` prefix for environment variables that need to be accessed from the frontend
63+- Always access environment variables via the centralized config module (`serverConfig` and `publicEnv` from `@/lib/config`). Do not use `process.env` directly in application code.
64+ 
65+#### Type Rules
66+ 
67+Follow these rules when working with types.
68+ 
69+- 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 aliases
74+- If referring to db types, use `@/db/schema` such as `SelectTodo` from `todos-schema.ts`
75+ 
76+An example of a type:
77+ 
78+`types/actions-types.ts`
79+ 
80+```ts
81+export type ActionState<T> =
82+ | { isSuccess: true; message: string; data: T }
83+ | { isSuccess: false; message: string; data?: never }
84+```
85+ 
86+And exporting it:
87+ 
88+`types/index.ts`
89+ 
90+```ts
91+export * from "./actions-types"
92+```
93+ 
94+### Frontend Rules
95+ 
96+Follow these rules when working on the frontend.
97+ 
98+It uses Next.js, Tailwind, Shadcn, and Framer Motion.
99+ 
100+#### General Rules
101+ 
102+- Use `lucide-react` for icons
103+- useSidebar must be used within a SidebarProvider
104+ 
105+#### Components
106+ 
107+- Use divs instead of other html tags unless otherwise specified
108+- Separate the main parts of a component's html with an extra blank line for visual spacing
109+- Always tag a component with either `use server` or `use client` at the top, including layouts and pages
110+ 
111+##### Organization
112+ 
113+- All components be named using kebab case like `example-component.tsx` unless otherwise specified
114+- Put components in `/_components` in the route if one-off components
115+- Put components in `/components` from the root if shared components
116+ 
117+##### Data Fetching
118+ 
119+- Fetch data in server components and pass the data down as props to client components.
120+- Use server actions from `/actions` to mutate data.
121+ 
122+##### Server Components
123+ 
124+- 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" prop
129+- params in server pages should be awaited such as `const { courseId } = await params` where the type is `params: Promise<{ courseId: string }>`
130+ 
131+Example of a server layout:
132+ 
133+```tsx
134+"use server"
135+ 
136+export default async function ExampleServerLayout({
137+ children
138+}: {
139+ children: React.ReactNode
140+}) {
141+ return children
142+}
143+```
144+ 
145+Example of a server page (with async logic):
146+ 
147+```tsx
148+"use server"
149+ 
150+import { Suspense } from "react"
151+import { SomeAction } from "@/actions/some-actions"
152+import SomeComponent from "./_components/some-component"
153+import SomeSkeleton from "./_components/some-skeleton"
154+ 
155+export default async function ExampleServerPage() {
156+ return (
157+ <Suspense fallback={<SomeSkeleton className="some-class" />}>
158+ <SomeComponentFetcher />
159+ </Suspense>
160+ )
161+}
162+ 
163+async function SomeComponentFetcher() {
164+ const { data } = await SomeAction()
165+ return <SomeComponent className="some-class" initialData={data || []} />
166+}
167+```
168+ 
169+Example of a server page (no async logic required):
170+ 
171+```tsx
172+"use server"
173+ 
174+import SomeClientComponent from "./_components/some-client-component"
175+ 
176+// In this case, no asynchronous work is being done, so no Suspense or fallback is required.
177+export default async function ExampleServerPage() {
178+ return <SomeClientComponent initialData={[]} />
179+}
180+```
181+ 
182+Example of a server component:
183+ 
184+```tsx
185+"use server"
186+ 
187+interface ExampleServerComponentProps {
188+ // Your props here
189+}
190+ 
191+export async function ExampleServerComponent({
192+ props
193+}: ExampleServerComponentProps) {
194+ // Your code here
195+}
196+```
197+ 
198+##### Client Components
199+ 
200+- Use `"use client"` at the top of the file
201+- 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`
203+ 
204+Example of a client page:
205+ 
206+```tsx
207+"use client"
208+ 
209+export default function ExampleClientPage() {
210+ // Your code here
211+}
212+```
213+ 
214+Example of a client component:
215+ 
216+```tsx
217+"use client"
218+ 
219+interface ExampleClientComponentProps {
220+ initialData: any[]
221+}
222+ 
223+export default function ExampleClientComponent({
224+ initialData
225+}: ExampleClientComponentProps) {
226+ // Client-side logic here
227+ return <div>{initialData.length} items</div>
228+}
229+```
230+ 
6231 ### Backend Rules
7232  
8233 Follow these rules when working on the backend.
@@ −11 +236 @@
11236  
12237 #### General Rules
13238  
14−- Never generate migrations. You do not have to do anything in the `db/migrations` folder including migrations and metadata. Ignore it.
239+- Never generate migrations. You do not have to do anything in the `db/migrations` folder inluding migrations and metadata. Ignore it.
15240  
16241 #### Organization
17242  
@@ −251 +476 @@
251476 }
252477 ```
253478  
254−#### Services
479+### Auth Rules
255480  
256−- When importing services, use `@/lib/services`
257−- Name files like `example-service.ts`
258−- All services should go in the `lib/services` folder
259−- Services handle complex business logic that would otherwise make server actions too large
260−- Services should be pure functions that take inputs and return outputs
261−- Services should not directly handle HTTP requests or database operations
262−- Use services for external API integrations, complex calculations, and domain-specific logic
263−- Follow the data flow: Components → Actions → Services
264−- Export functions using named exports
481+Follow these rules when working on auth.
265482  
266−Example of a service:
483+It uses Clerk for authentication.
267484  
268−`lib/services/grammar-correction.ts`
485+#### General Rules
269486  
487+- Import the auth helper with `import { auth } from "@clerk/nextjs/server"` in server components
488+- await the auth helper in server actions
489+ 
490+### Payments Rules
491+ 
492+Follow these rules when working on payments.
493+ 
494+It uses Stripe for payments.
495+ 
496+### Analytics Rules
497+ 
498+Follow these rules when working on analytics.
499+ 
500+It uses PostHog for analytics.
501+ 
502+# Storage Rules
503+ 
504+Follow these rules when working with Supabase Storage.
505+ 
506+It uses Supabase Storage for file uploads, downloads, and management.
507+ 
508+## General Rules
509+ 
510+- Always use environment variables for bucket names to maintain consistency across environments
511+- Never hardcode bucket names in the application code
512+- Always handle file size limits and allowed file types at the application level
513+- Use the `upsert` method instead of `upload` when you want to replace existing files
514+- Always implement proper error handling for storage operations
515+- Use content-type headers when uploading files to ensure proper file handling
516+ 
517+## Organization
518+ 
519+### Buckets
520+ 
521+- 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 location
524+- Set appropriate bucket policies (public/private) based on access requirements
525+- Implement RLS (Row Level Security) policies for buckets that need user-specific access
526+- 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 editor
527+ 
528+### File Structure
529+ 
530+- Organize files in folders based on their purpose and ownership
531+- Use predictable, collision-resistant naming patterns
532+- Structure: `{bucket}/{userId}/{purpose}/{filename}`
533+- Example: `profile-images/123e4567-e89b/avatar/profile.jpg`
534+- Include timestamps in filenames when version history is important
535+- Example: `documents/123e4567-e89b/contracts/2024-02-13-contract.pdf`
536+ 
537+## Actions
538+ 
539+- 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 actions
543+ 
544+Example of a storage action:
545+ 
270546 ```ts
271−import OpenAI from "openai"
272−import { getCompletion } from "@/lib/services/open-ai"
547+"use server"
273548  
274−const SYSTEM_MESSAGE: string = `You are a grammar correction assistant...`
549+import { createClientComponentClient } from "@supabase/auth-helpers-nextjs"
550+import { ActionState } from "@/types"
275551  
276−export const getPunchyText = async (
277− userMessage: string
278−): Promise<string | undefined> => {
279− const completion: OpenAI.Chat.Completions.ChatCompletion =
280− await getCompletion(userMessage, {
281− systemMessage: SYSTEM_MESSAGE,
282− maxTokens: 280,
283− temperature: 0.7
284− })
552+export async function uploadFileStorage(
553+ bucket: string,
554+ path: string,
555+ file: File
556+): Promise<ActionState<{ path: string }>> {
557+ try {
558+ const supabase = createClientComponentClient()
285559  
286− return completion?.choices?.[0]?.message?.content?.trim()
560+ const { data, error } = await supabase.storage
561+ .from(bucket)
562+ .upload(path, file, {
563+ upsert: false,
564+ contentType: file.type
565+ })
566+ 
567+ if (error) throw error
568+ 
569+ 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+ }
287578 }
288579 ```
580+ 
581+## File Handling
582+ 
583+### Upload Rules
584+ 
585+- Always validate file size before upload
586+- Implement file type validation using both extension and MIME type
587+- Generate unique filenames to prevent collisions
588+- Set appropriate content-type headers
589+- Handle existing files appropriately (error or upsert)
590+ 
591+Example validation:
592+ 
593+```ts
594+const MAX_FILE_SIZE = 10 * 1024 * 1024 // 10MB
595+const ALLOWED_TYPES = ["image/jpeg", "image/png", "image/webp"]
596+ 
597+function validateFile(file: File): boolean {
598+ if (file.size > MAX_FILE_SIZE) {
599+ throw new Error("File size exceeds limit")
600+ }
601+ 
602+ if (!ALLOWED_TYPES.includes(file.type)) {
603+ throw new Error("File type not allowed")
604+ }
605+ 
606+ return true
607+}
608+```
609+ 
610+### Download Rules
611+ 
612+- Always handle missing files gracefully
613+- Implement proper error handling for failed downloads
614+- Use signed URLs for private files
615+ 
616+### Delete Rules
617+ 
618+- Implement soft deletes when appropriate
619+- Clean up related database records when deleting files
620+- Handle bulk deletions carefully
621+- Verify ownership before deletion
622+- Always delete all versions/transforms of a file
623+ 
624+## Security
625+ 
626+### Bucket Policies
627+ 
628+- Make buckets private by default
629+- Only make buckets public when absolutely necessary
630+- Use RLS policies to restrict access to authorized users
631+- Example RLS policy:
632+ 
633+```sql
634+CREATE POLICY "Users can only access their own files"
635+ON storage.objects
636+FOR ALL
637+USING (auth.uid()::text = (storage.foldername(name))[1]);
638+```
639+ 
640+### Access Control
641+ 
642+- Generate short-lived signed URLs for private files
643+- Implement proper CORS policies
644+- Use separate buckets for public and private files
645+- Never expose internal file paths
646+- Validate user permissions before any operation
647+ 
648+## Error Handling
649+ 
650+- Implement specific error types for common storage issues
651+- Always provide meaningful error messages
652+- Implement retry logic for transient failures
653+- Log storage errors separately for monitoring
654+ 
655+## Optimization
656+ 
657+- Implement progressive upload for large files
658+- Clean up temporary files and failed uploads
659+- Use batch operations when handling multiple files
660+ 
RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack

RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack

RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack