├── .cursor
└── rules
│ ├── community-projects.mdc
│ ├── conventional-commits.mdc
│ ├── conversation-style.mdc
│ ├── cursor-rules-location.mdc
│ ├── file-organization.mdc
│ ├── git-commit-workflow.mdc
│ ├── naming-conventions.mdc
│ └── solid-principles.mdc
├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── conversation-style.mdc
├── git-commit-workflow.mdc
├── nextjs
├── async-params.mdc
├── code-review.mdc
├── data-access.mdc
├── naming-conventions.mdc
├── nextjs-15.mdc
├── server-actions.mdc
├── shadcn.mdc
├── solid-principles.mdc
└── tailwindcss-4.mdc
├── open-source
├── community-projects.mdc
└── conventional-commits.mdc
├── supabase
├── drizzle-migrations.mdc
├── drizzle-queries.mdc
├── supabase-bootstrap-with-auth.mdc
├── supabase-create-functions.mdc
├── supabase-create-migration.mdc
├── supabase-drizzle-bootstrap.mdc
├── supabase-postgres-style-guide.mdc
├── supabase-rls-policies.mdc
└── supabase-writing-edge-functions.mdc
└── task-master
├── cursor_rules.mdc
├── dev_workflow.mdc
└── self_improve.mdc
/.cursor/rules/community-projects.mdc:
--------------------------------------------------------------------------------
1 | ---
2 | description: Ensures proper setup of community project files and
3 | globs:
4 | ---
5 | # Community Projects Rule
6 | Standards for initializing and maintaining community-focused open source projects.
7 |
8 |
9 | name: community_projects
10 | description: Ensures proper setup of community project files and documentation
11 | filters:
12 | - type: event
13 | pattern: "project_init|project_validate"
14 | - type: directory
15 | pattern: ".*"
16 |
17 | actions:
18 | - type: validate
19 | description: "Validate required community files"
20 | requirements:
21 | - name: "README.md"
22 | required: true
23 | content:
24 | - "Project title and description"
25 | - "Installation instructions"
26 | - "Usage examples"
27 | - "Contributing guidelines reference"
28 | - "License reference"
29 | - name: "CONTRIBUTING.md"
30 | required: true
31 | content:
32 | - "How to contribute"
33 | - "Development setup"
34 | - "Pull request process"
35 | - "Code style guidelines"
36 | - "Testing requirements"
37 | - name: "LICENSE"
38 | required: true
39 | content:
40 | - "Valid open source license text"
41 | - "Current year"
42 | - "Copyright holder information"
43 | - name: "CODE_OF_CONDUCT.md"
44 | required: true
45 | content:
46 | - "Expected behavior"
47 | - "Unacceptable behavior"
48 | - "Reporting process"
49 | - "Enforcement guidelines"
50 | - "Contact information"
51 |
52 | - type: suggest
53 | message: |
54 | When setting up a community project, ensure:
55 |
56 | 1. README.md contains:
57 | ```markdown
58 | # Project Name
59 |
60 | Brief description of the project.
61 |
62 | ## Installation
63 |
64 | Step-by-step installation instructions.
65 |
66 | ## Usage
67 |
68 | Basic usage examples.
69 |
70 | ## Contributing
71 |
72 | Please read [CONTRIBUTING.md](mdc:CONTRIBUTING.md) for details on our code of conduct and the process for submitting pull requests.
73 |
74 | ## License
75 |
76 | This project is licensed under the [LICENSE_NAME] - see the [LICENSE](mdc:LICENSE) file for details.
77 | ```
78 |
79 | 2. CONTRIBUTING.md contains:
80 | ```markdown
81 | # Contributing Guidelines
82 |
83 | ## Development Setup
84 | [Development environment setup instructions]
85 |
86 | ## Pull Request Process
87 | 1. Update documentation
88 | 2. Update tests
89 | 3. Follow code style
90 | 4. Get reviews
91 |
92 | ## Code Style
93 | [Code style guidelines]
94 |
95 | ## Testing
96 | [Testing requirements and instructions]
97 | ```
98 |
99 | 3. LICENSE file:
100 | - Choose appropriate license (MIT, Apache 2.0, etc.)
101 | - Include current year
102 | - Include copyright holder
103 |
104 | 4. CODE_OF_CONDUCT.md:
105 | - Based on Contributor Covenant
106 | - Include contact information
107 | - Clear enforcement guidelines
108 |
109 | examples:
110 | - input: |
111 | # Bad: Missing required files
112 | my-project/
113 | ├── src/
114 | └── README.md
115 |
116 | # Good: Complete community project setup
117 | my-project/
118 | ├── src/
119 | ├── README.md
120 | ├── CONTRIBUTING.md
121 | ├── LICENSE
122 | └── CODE_OF_CONDUCT.md
123 | output: "Properly configured community project"
124 |
125 | metadata:
126 | priority: high
127 | version: 1.0
128 | tags:
129 | - community
130 | - documentation
131 | - open-source
132 |
133 |
--------------------------------------------------------------------------------
/.cursor/rules/conventional-commits.mdc:
--------------------------------------------------------------------------------
1 | ---
2 | description: Automatically commit changes using conventional commits format
3 | globs:
4 | ---
5 | # Conventional Commits Rule
6 |
7 | ## Description
8 | This rule defines the format and structure for commit messages following the Conventional Commits 1.0.0 specification. It ensures consistent, semantic, and machine-readable commit messages.
9 |
10 | ## Rule Type
11 | workflow
12 |
13 | ## Rule Format
14 | ```json
15 | {
16 | "type": "workflow",
17 | "name": "conventional_commits",
18 | "description": "Enforces Conventional Commits 1.0.0 specification",
19 | "filters": [
20 | {
21 | "type": "event",
22 | "pattern": "pre_commit"
23 | }
24 | ],
25 | "steps": [
26 | {
27 | "action": "validate",
28 | "description": "Validate commit message format",
29 | "requirements": [
30 | "Message MUST be prefixed with a type",
31 | "Type MUST be one of: feat, fix, docs, style, refactor, perf, test, build, ci, chore",
32 | "Scope is OPTIONAL and MUST be in parentheses",
33 | "Description MUST immediately follow the colon and space",
34 | "Description MUST use imperative mood ('add' not 'added')",
35 | "Description MUST be less than 100 characters",
36 | "Breaking changes MUST be indicated by '!' or 'BREAKING CHANGE:' footer",
37 | "Body MUST be separated from description by one blank line",
38 | "Footer MUST be separated from body by one blank line"
39 | ]
40 | },
41 | {
42 | "action": "execute",
43 | "description": "Format and create commit",
44 | "script": {
45 | "detect_type": {
46 | "feat": ["add", "create", "implement", "introduce"],
47 | "fix": ["fix", "correct", "resolve", "patch"],
48 | "docs": ["document", "comment", "update.*docs"],
49 | "style": ["style", "format", "lint"],
50 | "refactor": ["refactor", "restructure", "reorganize"],
51 | "perf": ["optimize", "performance", "improve.*speed"],
52 | "test": ["test", "spec", "coverage"],
53 | "build": ["build", "dependency", "package"],
54 | "ci": ["ci", "pipeline", "workflow"],
55 | "chore": ["chore", "misc", "task"]
56 | },
57 | "format_message": {
58 | "template": "${type}${scope}: ${description}\n\n${body}\n\n${footer}",
59 | "variables": {
60 | "type": "Detected from changes or user input",
61 | "scope": "Optional, derived from file paths",
62 | "description": "First line of commit message",
63 | "body": "Detailed explanation of changes",
64 | "footer": "Optional references or breaking changes"
65 | }
66 | },
67 | "command": [
68 | "# Extract type from changes or prompt user",
69 | "TYPE=$(detect_change_type \"$CHANGES\" || prompt_user \"Enter commit type:\")",
70 | "",
71 | "# Extract scope from file paths",
72 | "SCOPE=$(get_common_path \"$CHANGED_FILES\")",
73 | "",
74 | "# Format the commit message",
75 | "printf \"%s\\n\\n%s\\n\\n%s\" \"$TYPE${SCOPE:+($SCOPE)}: $DESCRIPTION\" \"$BODY\" \"$FOOTER\" > \"$COMMIT_MSG_FILE\""
76 | ]
77 | }
78 | }
79 | ]
80 | }
81 | ```
82 |
83 | ## Manual Commit Syntax
84 | When creating commits manually, always use the printf syntax to properly handle newlines and formatting:
85 |
86 | ```bash
87 | printf "type(scope): description\n\nbody of the commit explaining the changes in detail\n\nfooter information" | git commit -F -
88 | ```
89 |
90 | For example:
91 | ```bash
92 | printf "feat(auth): add OAuth2 support\n\nAdd Google and GitHub provider integration\nImplement token refresh handling\nAdd user profile synchronization\n\nCloses #123" | git commit -F -
93 | ```
94 |
95 | This ensures proper formatting and newline handling in the commit message.
96 |
97 | ## Examples
98 |
99 | ### Feature with Scope
100 | ```
101 | feat(auth): implement OAuth2 support
102 |
103 | - Add Google and GitHub provider integration
104 | - Implement token refresh handling
105 | - Add user profile synchronization
106 |
107 | Closes #123
108 | ```
109 |
110 | ### Bug Fix with Breaking Change
111 | ```
112 | fix(api): update user serialization
113 |
114 | - Modify user data structure for better consistency
115 | - Add validation for new fields
116 |
117 | BREAKING CHANGE: user.fullName split into firstName and lastName
118 | ```
119 |
120 | ### Documentation Update
121 | ```
122 | docs(readme): add modern package manager instructions
123 |
124 | - Add yarn and pnpm installation methods
125 | - Update minimum Node.js version requirement
126 | ```
127 |
128 | ### Performance Improvement
129 | ```
130 | perf(core): optimize database queries
131 |
132 | - Add query result caching
133 | - Implement proper indexing
134 | - Reduce unnecessary joins
135 |
136 | Closes #456
137 | ```
138 |
139 | ## Integration
140 | This rule should be used in conjunction with the git-commit-workflow rule to ensure changes are properly reviewed before creating the commit message. The workflow should be:
141 |
142 | 1. Review changes (git-commit-workflow)
143 | 2. Format commit message (conventional-commits)
144 | 3. Validate commit message (conventional-commits)
145 | 4. Commit changes
146 |
--------------------------------------------------------------------------------
/.cursor/rules/conversation-style.mdc:
--------------------------------------------------------------------------------
1 | ---
2 | description: Enforces consistent conversation patterns and style
3 | globs:
4 | ---
5 | # Conversation Style
6 | Guidelines for maintaining a consistent and engaging conversation style.
7 |
8 |
9 | name: conversation_style
10 | description: Enforces consistent conversation patterns and style
11 | filters:
12 | - type: event
13 | pattern: "conversation_start|message_response"
14 |
15 | actions:
16 | - type: suggest
17 | message: |
18 | When engaging in conversations, follow these rules:
19 |
20 | 1. Unicorn Greeting:
21 | - Start every conversation and response with "🦄"
22 | - Place the emoji at the very beginning of the message
23 | - Add a space after emoji if followed by a sentence
24 | Example:
25 | ```
26 | // Bad: Missing unicorn or wrong placement
27 | Hello! How can I help you today?
28 | Hi 🦄 there!
29 |
30 | // Good: Proper unicorn placement
31 | 🦄 Hello! How can I help you today?
32 | 🦄 Hi there!
33 | 🦄 I'll help you with that request.
34 | ```
35 |
36 | 2. Response Structure:
37 | - Emoji followed by greeting (if appropriate)
38 | - Then context or acknowledgment
39 | - Finally, the main response
40 | Example:
41 | ```
42 | // Bad: Incorrect structure
43 | Let me help you with that.
44 | 🦄 [No context or acknowledgment]
45 |
46 | // Good: Proper structure
47 | 🦄 I understand you want to modify the configuration.
48 | I'll help you make those changes safely.
49 | ```
50 |
51 | 3. Consistency:
52 | - Use the unicorn emoji consistently
53 | - Don't substitute with other emojis
54 | - Don't skip the emoji even in short responses
55 | Example:
56 | ```
57 | // Bad: Inconsistent usage
58 | 🌟 Hello there!
59 | Sure, I can help.
60 |
61 | // Good: Consistent usage
62 | 🦄 Hello there!
63 | 🦄 Sure, I can help.
64 | ```
65 |
66 | examples:
67 | - input: |
68 | User: Can you help me with this code?
69 | Assistant: Let me take a look at that for you.
70 |
71 | User: Thanks!
72 | Assistant: You're welcome!
73 | output: |
74 | User: Can you help me with this code?
75 | Assistant: 🦄 Let me take a look at that for you.
76 |
77 | User: Thanks!
78 | Assistant: 🦄 You're welcome!
79 |
80 | metadata:
81 | priority: medium
82 | version: 1.0
83 | tags:
84 | - conversation
85 | - style
86 | - user-interaction
87 |
--------------------------------------------------------------------------------
/.cursor/rules/cursor-rules-location.mdc:
--------------------------------------------------------------------------------
1 | ---
2 | description: Standards for placing Cursor rule files in the correct directory
3 | globs: *.mdc
4 | ---
5 | # Cursor Rules Location
6 | Rules for placing and organizing Cursor rule files in the repository.
7 |
8 | name: cursor_rules_location
9 | description: Standards for placing Cursor rule files in the correct directory
10 | filters:
11 | # Match any .mdc files
12 | - type: file_extension
13 | pattern: "\\.mdc$"
14 | # Match files that look like Cursor rules
15 | - type: content
16 | pattern: "(?s).*?"
17 | # Match file creation events
18 | - type: event
19 | pattern: "file_create"
20 |
21 | actions:
22 | - type: reject
23 | conditions:
24 | - pattern: "^(?!\\.\\/\\.cursor\\/rules\\/.*\\.mdc$)"
25 | message: "Cursor rule files (.mdc) must be placed in the .cursor/rules directory"
26 |
27 | - type: suggest
28 | message: |
29 | When creating Cursor rules:
30 |
31 | 1. Always place rule files in PROJECT_ROOT/.cursor/rules/:
32 | ```
33 | .cursor/rules/
34 | ├── your-rule-name.mdc
35 | ├── another-rule.mdc
36 | └── ...
37 | ```
38 |
39 | 2. Follow the naming convention:
40 | - Use kebab-case for filenames
41 | - Always use .mdc extension
42 | - Make names descriptive of the rule's purpose
43 |
44 | 3. Directory structure:
45 | ```
46 | PROJECT_ROOT/
47 | ├── .cursor/
48 | │ └── rules/
49 | │ ├── your-rule-name.mdc
50 | │ └── ...
51 | └── ...
52 | ```
53 |
54 | 4. Never place rule files:
55 | - In the project root
56 | - In subdirectories outside .cursor/rules
57 | - In any other location
58 |
59 | examples:
60 | - input: |
61 | # Bad: Rule file in wrong location
62 | rules/my-rule.mdc
63 | my-rule.mdc
64 | .rules/my-rule.mdc
65 |
66 | # Good: Rule file in correct location
67 | .cursor/rules/my-rule.mdc
68 | output: "Correctly placed Cursor rule file"
69 |
70 | metadata:
71 | priority: high
72 | version: 1.0
73 |
--------------------------------------------------------------------------------
/.cursor/rules/file-organization.mdc:
--------------------------------------------------------------------------------
1 | # File Organization
2 | Guidelines for organizing code into files following single responsibility principle.
3 |
4 |
5 | name: file_organization
6 | description: Enforces file-level organization and separation of concerns
7 | filters:
8 | - type: file_extension
9 | pattern: "\\.ts$|\\.js$"
10 | - type: content
11 | pattern: "(?s)(class|interface|type|function).*?\\{"
12 |
13 | actions:
14 | - type: suggest
15 | message: |
16 | When organizing code into files, follow these rules:
17 |
18 | 1. Single Definition Per File:
19 | - Each class should be in its own file
20 | - Each standalone function should be in its own file
21 | - Each complex type/interface (more than one line) should be in its own file
22 | Example:
23 | ```typescript
24 | // Bad: Multiple definitions in one file
25 | // user-types.ts
26 | interface UserCredentials {
27 | username: string;
28 | password: string;
29 | }
30 | interface UserProfile {
31 | id: string;
32 | name: string;
33 | email: string;
34 | }
35 | class UserService {
36 | // ...
37 | }
38 |
39 | // Good: Separate files for each definition
40 | // user-credentials.ts
41 | interface UserCredentials {
42 | username: string;
43 | password: string;
44 | }
45 |
46 | // user-profile.ts
47 | interface UserProfile {
48 | id: string;
49 | name: string;
50 | email: string;
51 | }
52 |
53 | // user-service.ts
54 | class UserService {
55 | // ...
56 | }
57 | ```
58 |
59 | 2. File Naming Conventions:
60 | - Use kebab-case for filenames
61 | - Name files after their primary export
62 | - Use suffixes to indicate type: `.interface.ts`, `.type.ts`, `.service.ts`, etc.
63 | Example:
64 | ```typescript
65 | // Good file names:
66 | user-credentials.interface.ts
67 | user-profile.interface.ts
68 | user-service.ts
69 | create-user.function.ts
70 | ```
71 |
72 | 3. Simple Type Exceptions:
73 | - Single-line type aliases and interfaces can be co-located if they're tightly coupled
74 | Example:
75 | ```typescript
76 | // Acceptable in the same file:
77 | type UserId = string;
78 | type UserRole = 'admin' | 'user';
79 | interface BasicUser { id: string; role: UserRole; }
80 | ```
81 |
82 | 4. Barrel File Usage:
83 | - Use index.ts files to re-export related components
84 | - Keep barrel files simple - export only, no implementations
85 | Example:
86 | ```typescript
87 | // users/index.ts
88 | export * from './user-credentials.interface';
89 | export * from './user-profile.interface';
90 | export * from './user-service';
91 | ```
92 |
93 | 5. Directory Structure:
94 | - Group related files in directories
95 | - Use feature-based organization
96 | Example:
97 | ```
98 | src/
99 | ├── users/
100 | │ ├── interfaces/
101 | │ │ ├── user-credentials.interface.ts
102 | │ │ └── user-profile.interface.ts
103 | │ ├── services/
104 | │ │ └── user-service.ts
105 | │ └── index.ts
106 | └── ...
107 | ```
108 |
109 | 6. Import Organization:
110 | - Keep imports organized by type (external, internal, relative)
111 | - Use explicit imports over namespace imports
112 | Example:
113 | ```typescript
114 | // External imports
115 | import { Injectable } from '@nestjs/common';
116 | import { v4 as uuid } from 'uuid';
117 |
118 | // Internal imports (from your app)
119 | import { UserProfile } from '@/users/interfaces';
120 | import { DatabaseService } from '@/database';
121 |
122 | // Relative imports (same feature)
123 | import { UserCredentials } from './user-credentials.interface';
124 | ```
125 |
126 | examples:
127 | - input: |
128 | // Bad: Multiple concerns in one file
129 | interface UserData {
130 | id: string;
131 | name: string;
132 | }
133 |
134 | class UserService {
135 | getUser(id: string) { }
136 | }
137 |
138 | function validateUser(user: UserData) { }
139 | output: |
140 | // user-data.interface.ts
141 | interface UserData {
142 | id: string;
143 | name: string;
144 | }
145 |
146 | // user.service.ts
147 | class UserService {
148 | getUser(id: string) { }
149 | }
150 |
151 | // validate-user.function.ts
152 | function validateUser(user: UserData) { }
153 |
154 | metadata:
155 | priority: high
156 | version: 1.0
157 | tags:
158 | - code-organization
159 | - best-practices
160 | - file-structure
161 |
162 |
--------------------------------------------------------------------------------
/.cursor/rules/git-commit-workflow.mdc:
--------------------------------------------------------------------------------
1 | ---
2 | description: Workflow for testing, validating, and committing changes using conventional commits
3 | globs:
4 | ---
5 | # Git Commit Workflow Rule
6 |
7 | ## Description
8 | This rule defines the complete workflow for validating changes, running tests, and creating commits. It ensures that all changes are properly tested and validated before being committed using the conventional commits format.
9 |
10 | ## Rule Type
11 | workflow
12 |
13 | ## Rule Format
14 | ```json
15 | {
16 | "type": "workflow",
17 | "name": "git_commit_workflow",
18 | "description": "Validates changes and creates conventional commits",
19 | "filters": [
20 | {
21 | "type": "event",
22 | "pattern": "pre_commit"
23 | }
24 | ],
25 | "steps": [
26 | {
27 | "action": "validate",
28 | "description": "Run tests and type checks",
29 | "requirements": [
30 | "All tests MUST pass",
31 | "TypeScript compilation MUST succeed",
32 | "Build process MUST complete successfully"
33 | ]
34 | },
35 | {
36 | "action": "execute",
37 | "description": "Validate and commit changes",
38 | "script": {
39 | "steps": [
40 | {
41 | "name": "run_tests",
42 | "command": "npm test",
43 | "on_failure": "abort"
44 | },
45 | {
46 | "name": "type_check",
47 | "command": "npm run type-check",
48 | "on_failure": "abort"
49 | },
50 | {
51 | "name": "build",
52 | "command": "npm run build",
53 | "on_failure": "abort"
54 | },
55 | {
56 | "name": "check_changes",
57 | "command": "git status --porcelain",
58 | "store_output": "CHANGED_FILES"
59 | },
60 | {
61 | "name": "stage_changes",
62 | "command": "git add ."
63 | },
64 | {
65 | "name": "create_commit",
66 | "use_rule": "conventional-commits"
67 | }
68 | ]
69 | }
70 | }
71 | ]
72 | }
73 | ```
74 |
75 | ## Workflow Steps
76 |
77 | 1. **Run Tests**
78 | - Execute the test suite using `npm test`
79 | - Abort if any tests fail
80 | - Ensure all new features have corresponding tests
81 |
82 | 2. **Type Checking**
83 | - Run TypeScript type checking
84 | - Verify no type errors exist
85 | - Abort if type checking fails
86 |
87 | 3. **Build Process**
88 | - Run the build process
89 | - Ensure the project builds successfully
90 | - Abort if build fails
91 |
92 | 4. **Check Changes**
93 | - Use `git status` to identify modified files
94 | - Review changes before staging
95 | - Ensure no unintended files are included
96 |
97 | 5. **Stage Changes**
98 | - Stage all relevant files using `git add`
99 | - Review staged changes if needed
100 |
101 | 6. **Create Commit**
102 | - Use conventional-commits rule to format commit message
103 | - Follow proper commit message structure
104 | - Include appropriate type, scope, and description
105 |
106 | ## Integration with Conventional Commits
107 | This workflow automatically integrates with the conventional-commits rule to ensure proper commit message formatting. The workflow will:
108 |
109 | 1. Detect the appropriate commit type based on changes
110 | 2. Generate a properly formatted commit message
111 | 3. Include relevant scope based on changed files
112 | 4. Add detailed body explaining changes
113 | 5. Include footer with issue references if applicable
114 |
115 | ## Examples
116 |
117 | ### Feature Development
118 | ```bash
119 | # 1. Run tests
120 | npm test
121 |
122 | # 2. Type check
123 | npm run type-check
124 |
125 | # 3. Build
126 | npm run build
127 |
128 | # 4. Check changes
129 | git status
130 |
131 | # 5. Stage changes
132 | git add .
133 |
134 | # 6. Create commit (using conventional-commits rule)
135 | printf "feat(auth): implement OAuth2 support\n\nAdd Google and GitHub provider integration\nImplement token refresh handling\n\nCloses #123" | git commit -F -
136 | ```
137 |
138 | ### Bug Fix
139 | ```bash
140 | # Follow the same workflow
141 | npm test && npm run type-check && npm run build
142 | git status
143 | git add .
144 | printf "fix(api): resolve user data serialization issue\n\nFix incorrect handling of nested user properties\n\nCloses #456" | git commit -F -
145 | ```
146 |
147 | ## Error Handling
148 | - If any validation step fails, the workflow will abort
149 | - Test failures must be resolved before proceeding
150 | - Type errors must be fixed before commit
151 | - Build errors must be addressed
152 | - Proper error messages will be displayed for each failure
153 |
154 | ## Notes
155 | - Always run this workflow before creating commits
156 | - Ensure all tests are up to date
157 | - Keep commits focused and atomic
158 | - Follow the conventional commits format
159 | - Use meaningful commit messages
160 |
--------------------------------------------------------------------------------
/.cursor/rules/naming-conventions.mdc:
--------------------------------------------------------------------------------
1 | ---
2 | description: Enforces consistent naming patterns for files, types, and functions
3 | globs: *.ts, *.js, *.tsx
4 | ---
5 | # Naming Conventions
6 | Standards for naming TypeScript and JavaScript files, types, and functions.
7 |
8 |
9 | name: naming_conventions
10 | description: Enforces consistent naming patterns for files, types, and functions
11 | filters:
12 | # Match TypeScript and JavaScript files
13 | - type: file_extension
14 | pattern: "\\.(ts|js)$"
15 | # Match file creation and modification events
16 | - type: event
17 | pattern: "(file_create|file_modify)"
18 |
19 | actions:
20 | - type: reject
21 | conditions:
22 | # Reject files not in kebab-case
23 | - pattern: "^(?!.*[A-Z])(?!.*\\s)(?!.*_)[a-z0-9-]+\\.(ts|js)$"
24 | message: "File names must be in kebab-case (e.g., my-file-name.ts)"
25 |
26 | - type: suggest
27 | message: |
28 | Follow these naming conventions:
29 |
30 | 1. Files:
31 | - Use kebab-case for all TypeScript and JavaScript files
32 | - Examples:
33 | ✅ user-service.ts
34 | ✅ api-client.js
35 | ❌ UserService.ts
36 | ❌ apiClient.js
37 |
38 | 2. Types (interfaces, types, classes):
39 | - Use PascalCase
40 | - Examples:
41 | ✅ interface UserProfile
42 | ✅ type ApiResponse
43 | ✅ class HttpClient
44 | ❌ interface userProfile
45 | ❌ type api_response
46 |
47 | 3. Functions:
48 | - Use camelCase
49 | - Examples:
50 | ✅ function getUserData()
51 | ✅ const fetchApiResponse = () => {}
52 | ❌ function GetUserData()
53 | ❌ const fetch_api_response = () => {}
54 |
55 | examples:
56 | - input: |
57 | // Bad: Incorrect naming
58 | UserService.ts
59 | API_client.js
60 |
61 | interface user_profile {}
62 | function FetchData() {}
63 |
64 | // Good: Correct naming
65 | user-service.ts
66 | api-client.js
67 |
68 | interface UserProfile {}
69 | function fetchData() {}
70 | output: "Correctly named files, types, and functions"
71 |
72 | metadata:
73 | priority: high
74 | version: 1.0
75 |
76 |
--------------------------------------------------------------------------------
/.cursor/rules/solid-principles.mdc:
--------------------------------------------------------------------------------
1 | # SOLID Principles
2 | Guidelines for implementing SOLID principles in the codebase.
3 |
4 |
5 | name: solid_principles
6 | description: Enforces SOLID principles in code design and implementation
7 | filters:
8 | - type: file_extension
9 | pattern: "\\.ts$|\\.js$"
10 | - type: content
11 | pattern: "(?s)class.*?\\{|interface.*?\\{|function.*?\\{"
12 |
13 | actions:
14 | - type: suggest
15 | message: |
16 | When writing code, follow these SOLID principles:
17 |
18 | 1. Single Responsibility Principle (SRP):
19 | - Each class/module should have only one reason to change
20 | - Keep classes focused and cohesive
21 | - Extract separate concerns into their own classes
22 | Example:
23 | ```typescript
24 | // Good: Single responsibility
25 | class UserAuthentication {
26 | authenticate(credentials: Credentials): boolean { ... }
27 | }
28 | class UserProfile {
29 | updateProfile(data: ProfileData): void { ... }
30 | }
31 |
32 | // Bad: Multiple responsibilities
33 | class User {
34 | authenticate(credentials: Credentials): boolean { ... }
35 | updateProfile(data: ProfileData): void { ... }
36 | sendEmail(message: string): void { ... }
37 | }
38 | ```
39 |
40 | 2. Open/Closed Principle (OCP):
41 | - Classes should be open for extension but closed for modification
42 | - Use interfaces and abstract classes
43 | - Implement new functionality through inheritance/composition
44 | Example:
45 | ```typescript
46 | // Good: Open for extension
47 | interface PaymentProcessor {
48 | process(payment: Payment): void;
49 | }
50 | class CreditCardProcessor implements PaymentProcessor { ... }
51 | class PayPalProcessor implements PaymentProcessor { ... }
52 |
53 | // Bad: Closed for extension
54 | class PaymentProcessor {
55 | process(payment: Payment, type: string): void {
56 | if (type === 'credit') { ... }
57 | else if (type === 'paypal') { ... }
58 | }
59 | }
60 | ```
61 |
62 | 3. Liskov Substitution Principle (LSP):
63 | - Derived classes must be substitutable for their base classes
64 | - Maintain expected behavior when using inheritance
65 | - Don't violate base class contracts
66 | Example:
67 | ```typescript
68 | // Good: Derived class maintains base contract
69 | class Bird {
70 | fly(): void { ... }
71 | }
72 | class Sparrow extends Bird {
73 | fly(): void { ... } // Implements flying behavior
74 | }
75 |
76 | // Bad: Violates base contract
77 | class Penguin extends Bird {
78 | fly(): void {
79 | throw new Error("Can't fly!"); // Violates base class contract
80 | }
81 | }
82 | ```
83 |
84 | 4. Interface Segregation Principle (ISP):
85 | - Don't force clients to depend on interfaces they don't use
86 | - Keep interfaces small and focused
87 | - Split large interfaces into smaller ones
88 | Example:
89 | ```typescript
90 | // Good: Segregated interfaces
91 | interface Readable {
92 | read(): void;
93 | }
94 | interface Writable {
95 | write(data: string): void;
96 | }
97 |
98 | // Bad: Fat interface
99 | interface FileSystem {
100 | read(): void;
101 | write(data: string): void;
102 | delete(): void;
103 | create(): void;
104 | modify(): void;
105 | }
106 | ```
107 |
108 | 5. Dependency Inversion Principle (DIP):
109 | - High-level modules shouldn't depend on low-level modules
110 | - Both should depend on abstractions
111 | - Use dependency injection
112 | Example:
113 | ```typescript
114 | // Good: Depends on abstraction
115 | interface Logger {
116 | log(message: string): void;
117 | }
118 | class UserService {
119 | constructor(private logger: Logger) {}
120 | }
121 |
122 | // Bad: Depends on concrete implementation
123 | class UserService {
124 | private logger = new FileLogger();
125 | }
126 | ```
127 |
128 | Additional Guidelines:
129 | - Use interfaces to define contracts
130 | - Implement dependency injection
131 | - Keep classes small and focused
132 | - Use composition over inheritance when possible
133 | - Write unit tests to verify SOLID compliance
134 |
135 | examples:
136 | - input: |
137 | // Bad example - violates SRP and OCP
138 | class OrderProcessor {
139 | processOrder(order: Order) {
140 | // Handles validation
141 | // Handles payment
142 | // Handles shipping
143 | // Handles notification
144 | }
145 | }
146 | output: |
147 | // Good example - follows SOLID principles
148 | interface OrderValidator {
149 | validate(order: Order): boolean;
150 | }
151 | interface PaymentProcessor {
152 | process(order: Order): void;
153 | }
154 | interface ShippingService {
155 | ship(order: Order): void;
156 | }
157 | interface NotificationService {
158 | notify(order: Order): void;
159 | }
160 |
161 | class OrderProcessor {
162 | constructor(
163 | private validator: OrderValidator,
164 | private paymentProcessor: PaymentProcessor,
165 | private shippingService: ShippingService,
166 | private notificationService: NotificationService
167 | ) {}
168 |
169 | processOrder(order: Order) {
170 | if (this.validator.validate(order)) {
171 | this.paymentProcessor.process(order);
172 | this.shippingService.ship(order);
173 | this.notificationService.notify(order);
174 | }
175 | }
176 | }
177 |
178 | metadata:
179 | priority: high
180 | version: 1.0
181 | tags:
182 | - code-quality
183 | - design-patterns
184 | - best-practices
185 |
186 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Dependencies
2 | node_modules/
3 | .pnpm-store/
4 | yarn.lock
5 | package-lock.json
6 | pnpm-lock.yaml
7 |
8 | # Build outputs
9 | dist/
10 | build/
11 | out/
12 | .next/
13 | *.tsbuildinfo
14 |
15 | # IDE and editor files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | !.vscode/settings.json
19 | .idea/
20 | *.swp
21 | *.swo
22 | .DS_Store
23 | Thumbs.db
24 |
25 | # Environment variables
26 | .env
27 | .env.local
28 | .env.*.local
29 | .env.development
30 | .env.test
31 | .env.production
32 |
33 | # Debug logs
34 | npm-debug.log*
35 | yarn-debug.log*
36 | yarn-error.log*
37 | debug.log
38 | *.log
39 |
40 | # Test coverage
41 | coverage/
42 | .nyc_output/
43 |
44 | # Cursor IDE specific
45 | .cursor/temp/
46 | .cursor/logs/
47 | !.cursor/rules/
48 |
49 | # Misc
50 | .cache/
51 | .temp/
52 | *.bak
53 | *.tmp
54 | *~
55 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to Cursor Rules
2 |
3 | We love your input! We want to make contributing to Cursor Rules as easy and transparent as possible, whether it's:
4 |
5 | - Reporting a bug
6 | - Discussing the current state of the rules
7 | - Submitting a fix
8 | - Proposing new rules
9 | - Improving documentation
10 |
11 | ## Development Process
12 |
13 | We use GitHub to host code, to track issues and feature requests, as well as accept pull requests.
14 |
15 | 1. Fork the repo and create your branch from `main`
16 | 2. If you've added new rules, make sure they follow our existing format
17 | 3. Update documentation if needed
18 | 4. Issue that pull request!
19 |
20 | ## Rule File Standards
21 |
22 | When creating or modifying rule files:
23 |
24 | 1. Place all rule files in `.cursor/rules/` directory
25 | 2. Use kebab-case for filenames with `.mdc` extension
26 | 3. Follow the standard rule format:
27 | ```markdown
28 | # Rule Name
29 | Description of the rule
30 |
31 |
32 | name: rule_name
33 | description: Detailed description
34 | filters:
35 | # ... filters ...
36 | actions:
37 | # ... actions ...
38 |
39 | ```
40 |
41 | ## Commit Messages
42 |
43 | We follow the Conventional Commits specification. Each commit message should be structured as follows:
44 |
45 | ```
46 | type(scope): description
47 |
48 | [optional body]
49 |
50 | [optional footer]
51 | ```
52 |
53 | Types:
54 | - feat: New feature or rule
55 | - fix: Bug fix
56 | - docs: Documentation changes
57 | - style: Formatting changes
58 | - refactor: Code refactoring
59 | - test: Adding/modifying tests
60 | - chore: Maintenance tasks
61 |
62 | ## Pull Request Process
63 |
64 | 1. Update the README.md with details of changes if needed
65 | 2. Follow the pull request template
66 | 3. You may merge the Pull Request once you have the sign-off of at least one other developer
67 |
68 | ## Any Contributions You Make Will Be Under the MIT Software License
69 |
70 | In short, when you submit code changes, your submissions are understood to be under the same [MIT License](LICENSE) that covers the project. Feel free to contact the maintainers if that's a concern.
71 |
72 | ## Report Bugs Using GitHub's [Issue Tracker](../../issues)
73 |
74 | Report a bug by [opening a new issue](../../issues/new); it's that easy!
75 |
76 | ## Write Bug Reports With Detail, Background, and Sample Code
77 |
78 | **Great Bug Reports** tend to have:
79 |
80 | - A quick summary and/or background
81 | - Steps to reproduce
82 | - Be specific!
83 | - Give sample code if you can
84 | - What you expected would happen
85 | - What actually happens
86 | - Notes (possibly including why you think this might be happening, or stuff you tried that didn't work)
87 |
88 | ## License
89 |
90 | By contributing, you agree that your contributions will be licensed under its MIT License.
91 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Squirrel Software
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Cursor Rules
2 |
3 | A collection of standardized rules and guidelines for maintaining high-quality code using Cursor IDE.
4 |
5 | ## Overview
6 |
7 | This repository contains a set of rules that help maintain consistency and quality in codebases using Cursor IDE. These rules cover various aspects of development including:
8 |
9 | - Code organization and file structure
10 | - Naming conventions
11 | - Git commit standards
12 | - SOLID principles implementation
13 | - Conversation style guidelines
14 | - And more...
15 |
16 | ## Rules
17 |
18 | 1. **Conventional Commits** - Standards for commit message formatting
19 | 2. **Community Projects** - Standards for initializing and maintaining community-focused open source projects
20 | 3. **Conversation Style** - Guidelines for AI-human interaction in Cursor
21 | 4. **Cursor Rules Location** - Standards for rule file placement
22 | 5. **File Organization** - Guidelines for code organization
23 | 6. **Git Commit Workflow** - Process for validating and committing changes
24 | 7. **Naming Conventions** - Standards for naming files and code elements
25 | 8. **SOLID Principles** - Implementation of SOLID design principles
26 |
27 | ## Installation
28 |
29 | 1. Create a `.cursor/rules` directory in your project root:
30 | ```bash
31 | mkdir -p .cursor/rules
32 | ```
33 |
34 | 2. Copy the desired rule files into the `.cursor/rules` directory:
35 | ```bash
36 | cp path/to/rules/*.mdc .cursor/rules/
37 | ```
38 |
39 | ## Usage
40 | In the event that the rules do not load automatically, I have found that the best way to load them is to open the agent composer and say:
41 | ```
42 | For the remainder of this session, remember the following @rules
43 | ```
44 |
45 | It will then respond with:
46 | ```
47 | 🦄 Let me fetch the rules
48 |
49 | 🦄 I understand and will follow all the provided rules for our session. Here's a summary of how I'll incorporate them:
50 |
51 | 1. Conversation Style: I'll start each message with 🦄 and maintain a structured response format.
52 |
53 | 2. Naming Conventions: I'll ensure all files, types, and functions follow the specified patterns:
54 | - Files in kebab-case
55 | - Types in PascalCase
56 | - Functions in camelCase
57 |
58 | 3. SOLID Principles: Follow:
59 | - Single Responsibility: One reason to change
60 | - Open/Closed: Open for extension, closed for modification
61 | - Liskov Substitution: Derived classes must be substitutable
62 | - Interface Segregation: Keep interfaces focused
63 | - Dependency Inversion: Depend on abstractions
64 |
65 | 4. Conventional Commits: Format commits as `type(scope): description` with proper body and footer. Types include feat, fix, docs, style, refactor, perf, test, build, ci, chore.
66 |
67 | 5. Cursor Rules Location: Place all `.mdc` rule files in `.cursor/rules/` directory using kebab-case naming.
68 |
69 | 6. File Organization: One definition per file, use kebab-case filenames with appropriate suffixes (`.interface.ts`, `.service.ts`), group related files in feature-based directories, organize imports (external/internal/relative).
70 |
71 | 7. Git Commit Workflow: Run tests, type checks, and build before committing. Follow sequence: validate → test → type-check → build → check changes → stage → commit.
72 |
73 | 8. Community Projects: I'll ensure any project work follows the community standards with proper README.md, CONTRIBUTING.md, LICENSE, and CODE_OF_CONDUCT.md files.
74 |
75 | ```
76 | Once installed, these rules will be automatically applied when using Cursor IDE. The rules provide guidance for:
77 |
78 | - File naming and organization
79 | - Code structure and design
80 | - Git commit messages
81 | - Development workflows
82 | - And more...
83 |
84 | ## Contributing
85 |
86 | We welcome contributions! Please see our [Contributing Guidelines](CONTRIBUTING.md) for details.
87 |
88 | ## Code of Conduct
89 |
90 | This project follows a [Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code.
91 |
92 | ## License
93 |
94 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
95 |
--------------------------------------------------------------------------------
/conversation-style.mdc:
--------------------------------------------------------------------------------
1 | ---
2 | description: Enforces consistent conversation patterns and style
3 | globs:
4 | ---
5 | # Conversation Style
6 | Guidelines for maintaining a consistent and engaging conversation style.
7 |
8 |
9 | name: conversation_style
10 | description: Enforces consistent conversation patterns and style
11 | filters:
12 | - type: event
13 | pattern: "conversation_start|message_response"
14 |
15 | actions:
16 | - type: suggest
17 | message: |
18 | When engaging in conversations, follow these rules:
19 |
20 | 1. Unicorn Greeting:
21 | - Start every conversation and response with "🦄"
22 | - Place the emoji at the very beginning of the message
23 | - Add a space after emoji if followed by a sentence
24 | Example:
25 | ```
26 | // Bad: Missing unicorn or wrong placement
27 | Hello! How can I help you today?
28 | Hi 🦄 there!
29 |
30 | // Good: Proper unicorn placement
31 | 🦄 Hello! How can I help you today?
32 | 🦄 Hi there!
33 | 🦄 I'll help you with that request.
34 | ```
35 |
36 | 2. Response Structure:
37 | - Emoji followed by greeting (if appropriate)
38 | - Then context or acknowledgment
39 | - Finally, the main response
40 | Example:
41 | ```
42 | // Bad: Incorrect structure
43 | Let me help you with that.
44 | 🦄 [No context or acknowledgment]
45 |
46 | // Good: Proper structure
47 | 🦄 I understand you want to modify the configuration.
48 | I'll help you make those changes safely.
49 | ```
50 |
51 | 3. Consistency:
52 | - Use the unicorn emoji consistently
53 | - Don't substitute with other emojis
54 | - Don't skip the emoji even in short responses
55 | Example:
56 | ```
57 | // Bad: Inconsistent usage
58 | 🌟 Hello there!
59 | Sure, I can help.
60 |
61 | // Good: Consistent usage
62 | 🦄 Hello there!
63 | 🦄 Sure, I can help.
64 | ```
65 |
66 | examples:
67 | - input: |
68 | User: Can you help me with this code?
69 | Assistant: Let me take a look at that for you.
70 |
71 | User: Thanks!
72 | Assistant: You're welcome!
73 | output: |
74 | User: Can you help me with this code?
75 | Assistant: 🦄 Let me take a look at that for you.
76 |
77 | User: Thanks!
78 | Assistant: 🦄 You're welcome!
79 |
80 | metadata:
81 | priority: medium
82 | version: 1.0
83 | tags:
84 | - conversation
85 | - style
86 | - user-interaction
87 |
--------------------------------------------------------------------------------
/git-commit-workflow.mdc:
--------------------------------------------------------------------------------
1 | ---
2 | description: Workflow for testing, validating, and committing changes using conventional commits
3 | globs:
4 | ---
5 | # Git Commit Workflow Rule
6 |
7 | ## Description
8 | This rule defines the complete workflow for validating changes, running tests, and creating commits. It ensures that all changes are properly tested and validated before being committed using the conventional commits format.
9 |
10 | ## Rule Type
11 | workflow
12 |
13 | ## Rule Format
14 | ```json
15 | {
16 | "type": "workflow",
17 | "name": "git_commit_workflow",
18 | "description": "Validates changes and creates conventional commits",
19 | "filters": [
20 | {
21 | "type": "event",
22 | "pattern": "pre_commit"
23 | }
24 | ],
25 | "steps": [
26 | {
27 | "action": "validate",
28 | "description": "Run tests and type checks",
29 | "requirements": [
30 | "All tests MUST pass",
31 | "TypeScript compilation MUST succeed",
32 | "Build process MUST complete successfully"
33 | ]
34 | },
35 | {
36 | "action": "execute",
37 | "description": "Validate and commit changes",
38 | "script": {
39 | "steps": [
40 | {
41 | "name": "run_tests",
42 | "command": "npm test",
43 | "on_failure": "abort"
44 | },
45 | {
46 | "name": "type_check",
47 | "command": "npm run type-check",
48 | "on_failure": "abort"
49 | },
50 | {
51 | "name": "build",
52 | "command": "npm run build",
53 | "on_failure": "abort"
54 | },
55 | {
56 | "name": "check_changes",
57 | "command": "git status --porcelain",
58 | "store_output": "CHANGED_FILES"
59 | },
60 | {
61 | "name": "stage_changes",
62 | "command": "git add ."
63 | },
64 | {
65 | "name": "create_commit",
66 | "use_rule": "conventional-commits"
67 | }
68 | ]
69 | }
70 | }
71 | ]
72 | }
73 | ```
74 |
75 | ## Workflow Steps
76 |
77 | 1. **Run Tests**
78 | - Execute the test suite using `npm test`
79 | - Abort if any tests fail
80 | - Ensure all new features have corresponding tests
81 |
82 | 2. **Type Checking**
83 | - Run TypeScript type checking
84 | - Verify no type errors exist
85 | - Abort if type checking fails
86 |
87 | 3. **Build Process**
88 | - Run the build process
89 | - Ensure the project builds successfully
90 | - Abort if build fails
91 |
92 | 4. **Check Changes**
93 | - Use `git status` to identify modified files
94 | - Review changes before staging
95 | - Ensure no unintended files are included
96 |
97 | 5. **Stage Changes**
98 | - Stage all relevant files using `git add`
99 | - Review staged changes if needed
100 |
101 | 6. **Create Commit**
102 | - Use conventional-commits rule to format commit message
103 | - Follow proper commit message structure
104 | - Include appropriate type, scope, and description
105 |
106 | ## Integration with Conventional Commits
107 | This workflow automatically integrates with the conventional-commits rule to ensure proper commit message formatting. The workflow will:
108 |
109 | 1. Detect the appropriate commit type based on changes
110 | 2. Generate a properly formatted commit message
111 | 3. Include relevant scope based on changed files
112 | 4. Add detailed body explaining changes
113 | 5. Include footer with issue references if applicable
114 |
115 | ## Examples
116 |
117 | ### Feature Development
118 | ```bash
119 | # 1. Run tests
120 | npm test
121 |
122 | # 2. Type check
123 | npm run type-check
124 |
125 | # 3. Build
126 | npm run build
127 |
128 | # 4. Check changes
129 | git status
130 |
131 | # 5. Stage changes
132 | git add .
133 |
134 | # 6. Create commit (using conventional-commits rule)
135 | printf "feat(auth): implement OAuth2 support\n\nAdd Google and GitHub provider integration\nImplement token refresh handling\n\nCloses #123" | git commit -F -
136 | ```
137 |
138 | ### Bug Fix
139 | ```bash
140 | # Follow the same workflow
141 | npm test && npm run type-check && npm run build
142 | git status
143 | git add .
144 | printf "fix(api): resolve user data serialization issue\n\nFix incorrect handling of nested user properties\n\nCloses #456" | git commit -F -
145 | ```
146 |
147 | ## Error Handling
148 | - If any validation step fails, the workflow will abort
149 | - Test failures must be resolved before proceeding
150 | - Type errors must be fixed before commit
151 | - Build errors must be addressed
152 | - Proper error messages will be displayed for each failure
153 |
154 | ## Notes
155 | - Always run this workflow before creating commits
156 | - Ensure all tests are up to date
157 | - Keep commits focused and atomic
158 | - Follow the conventional commits format
159 | - Use meaningful commit messages
160 |
--------------------------------------------------------------------------------
/nextjs/async-params.mdc:
--------------------------------------------------------------------------------
1 | ---
2 | description:
3 | globs:
4 | alwaysApply: false
5 | ---
6 | # Async Params and SearchParams in Next.js 15
7 |
8 | name: async_params
9 | description: Guidelines for handling async params and searchParams in Next.js 15 page components
10 | filters:
11 | - type: file_extension
12 | pattern: ".tsx?$"
13 | - type: path
14 | pattern: "app/.*page.tsx$"
15 |
16 | actions:
17 | - type: reject
18 | conditions:
19 | - pattern: "params\\s*:\\s*\\{\\s*[a-zA-Z_][a-zA-Z0-9_]*\\s*:\\s*string\\s*\\}"
20 | message: "Page params must be typed as a Promise and awaited"
21 |
22 | - pattern: "searchParams\\s*:\\s*\\{[^}]*\\}"
23 | message: "Page searchParams must be typed as a Promise and awaited"
24 |
25 | - pattern: "const\\s+\\{\\s*[a-zA-Z_][a-zA-Z0-9_]*\\s*\\}\\s*=\\s*params"
26 | message: "Page params must be awaited before destructuring"
27 |
28 | - pattern: "const\\s+\\{\\s*[a-zA-Z_][a-zA-Z0-9_]*\\s*\\}\\s*=\\s*searchParams"
29 | message: "Page searchParams must be awaited before destructuring"
30 |
31 | - type: suggest
32 | message: |
33 | # Async Params and SearchParams
34 |
35 | In Next.js 15, page components that use `params` or `searchParams` must:
36 | 1. Be async functions
37 | 2. Type params/searchParams as Promises
38 | 3. Await the params/searchParams before use
39 |
40 | ## Params Example
41 | ```typescript
42 | // ✅ DO: Properly type and await params
43 | interface PageProps {
44 | params: Promise<{ slug: string }>
45 | }
46 |
47 | export default async function Page({ params }: PageProps) {
48 | const { slug } = await params
49 | return Post: {slug}
50 | }
51 |
52 | // ❌ DON'T: Use params without Promise type and await
53 | interface PageProps {
54 | params: { slug: string } // Wrong! Should be Promise
55 | }
56 |
57 | export default function Page({ params }: PageProps) {
58 | const { slug } = params // Wrong! Should await params
59 | return Post: {slug}
60 | }
61 | ```
62 |
63 | ## SearchParams Example
64 | ```typescript
65 | // ✅ DO: Properly type and await searchParams
66 | interface PageProps {
67 | searchParams: Promise<{ q?: string }>
68 | }
69 |
70 | export default async function Page({ searchParams }: PageProps) {
71 | const { q } = await searchParams
72 | return Search: {q}
73 | }
74 |
75 | // ❌ DON'T: Use searchParams without Promise type and await
76 | interface PageProps {
77 | searchParams: { q?: string } // Wrong! Should be Promise
78 | }
79 |
80 | export default function Page({ searchParams }: PageProps) {
81 | const { q } = searchParams // Wrong! Should await searchParams
82 | return Search: {q}
83 | }
84 | ```
85 |
86 | ## Best Practices
87 | 1. Always make page components async when using params/searchParams
88 | 2. Always type params/searchParams as Promises
89 | 3. Always await params/searchParams before destructuring
90 | 4. Consider handling loading states while params are being resolved
91 | 5. Use TypeScript for better type safety
92 |
93 | ## Common Patterns
94 | ```typescript
95 | // Multiple params
96 | interface PageProps {
97 | params: Promise<{
98 | slug: string
99 | id: string
100 | }>
101 | }
102 |
103 | // Both params and searchParams
104 | interface PageProps {
105 | params: Promise<{ slug: string }>
106 | searchParams: Promise<{ page?: string }>
107 | }
108 |
109 | // With error handling
110 | export default async function Page({ params }: PageProps) {
111 | try {
112 | const { slug } = await params
113 | // Use slug
114 | } catch (error) {
115 | notFound()
116 | }
117 | }
118 | ```
119 |
120 | metadata:
121 | priority: high
122 | version: 1.0
123 | framework: next.js
124 | frameworkVersion: "15.0.0"
125 |
126 |
--------------------------------------------------------------------------------
/nextjs/code-review.mdc:
--------------------------------------------------------------------------------
1 | ---
2 | description: Comprehensive checklist and guidelines for conducting code reviews
3 | globs: ["**/*"]
4 | alwaysApply: true
5 | ---
6 |
7 | # Code Review Guidelines
8 |
9 | ## Review Process
10 | - **Before Starting Review:**
11 | - Check task requirements and acceptance criteria
12 | - Review related tasks and dependencies
13 | - Understand the context of the changes
14 |
15 | - **During Review:**
16 | - Follow checklist systematically
17 | - Document findings clearly
18 | - Provide constructive feedback
19 | - Reference specific rules when applicable
20 |
21 | - **After Review:**
22 | - Verify fixes address all comments
23 | - Check if changes require task updates
24 | - Update documentation if needed
25 |
26 | ## Review Checklist
27 |
28 | ### Architecture & Structure
29 | ```typescript
30 | // ✅ DO: Proper server action structure
31 | // app/actions/organization/create.ts
32 | 'use server'
33 | import { createOrganization } from '@/lib/data/mutations/organizations'
34 |
35 | // ❌ DON'T: Mix concerns
36 | 'use server'
37 | import { db } from '@/db'
38 | // Direct database operations in server action
39 | ```
40 |
41 | - [ ] Next.js 15 app directory structure
42 | - [ ] Server actions in `app/actions/`
43 | - [ ] Database operations in `lib/data/{queries,mutations}/`
44 | - [ ] shadcn/ui component patterns
45 | - [ ] SOLID principles adherence
46 | - [ ] Clean data access patterns
47 |
48 | ### Database & Data Layer
49 | ```typescript
50 | // ✅ DO: Use Drizzle migrations
51 | // db/migrations/0001_initial.ts
52 | import { sql } from 'drizzle-orm'
53 |
54 | // ❌ DON'T: Manual SQL files
55 | // migrations/manual.sql
56 | CREATE TABLE users...
57 | ```
58 |
59 | - [ ] Generated Drizzle migrations
60 | - [ ] Proper RLS policies
61 | - [ ] Edge function security
62 | - [ ] PostgreSQL style compliance
63 | - [ ] Type-safe database operations
64 | - [ ] Query optimization
65 |
66 | ### Server Actions & API
67 | ```typescript
68 | // ✅ DO: Proper server action
69 | export async function createUser(input: CreateUserInput) {
70 | const result = await createUserMutation(input);
71 | if (result.error) {
72 | return { error: result.error };
73 | }
74 | return { data: result.data };
75 | }
76 |
77 | // ❌ DON'T: Skip validation/typing
78 | export async function createUser(formData: any) {
79 | const user = await db.users.create(formData);
80 | return user;
81 | }
82 | ```
83 |
84 | - [ ] 'use server' directive present
85 | - [ ] Abstracted database operations
86 | - [ ] Comprehensive error handling
87 | - [ ] Zod schema validation
88 | - [ ] Proper async patterns
89 | - [ ] Appropriate response handling
90 |
91 | ### Security
92 | ```typescript
93 | // ✅ DO: Proper RLS policy
94 | CREATE POLICY "users can only access their own data"
95 | ON public.users
96 | FOR SELECT
97 | USING (auth.uid() = user_id);
98 |
99 | // ❌ DON'T: Skip RLS
100 | CREATE POLICY "allow all"
101 | ON public.users
102 | FOR ALL
103 | USING (true);
104 | ```
105 |
106 | - [ ] RLS policy implementation
107 | - [ ] Client-side data security
108 | - [ ] Authentication checks
109 | - [ ] Secret management
110 | - [ ] Proper access scoping
111 |
112 | ### Component Structure
113 | ```typescript
114 | // ✅ DO: Proper component structure
115 | import { Button } from '@/components/ui/button'
116 | import { cn } from '@/lib/utils'
117 |
118 | export function CustomButton({ className, ...props }) {
119 | return
120 | }
121 |
122 | // ❌ DON'T: Skip component conventions
123 | export function CustomButton(props) {
124 | return
125 | }
126 | ```
127 |
128 | - [ ] shadcn/ui consistency
129 | - [ ] Tailwind v4 practices
130 | - [ ] TypeScript typing
131 | - [ ] Client/server separation
132 | - [ ] Component abstraction
133 |
134 | ### Naming Conventions
135 | ```typescript
136 | // ✅ DO: Follow conventions
137 | // user-profile.tsx
138 | export function UserProfile() {}
139 | // useUserData.ts
140 | export function useUserData() {}
141 | // USER_ROLES.ts
142 | export const USER_ROLES = {}
143 |
144 | // ❌ DON'T: Mix conventions
145 | // UserData.tsx
146 | export function userData() {}
147 | ```
148 |
149 | - [ ] kebab-case files
150 | - [ ] PascalCase components
151 | - [ ] camelCase functions
152 | - [ ] snake_case database
153 | - [ ] PascalCase types
154 | - [ ] UPPER_SNAKE_CASE constants
155 |
156 | ### Error Handling
157 | ```typescript
158 | // ✅ DO: Proper error handling
159 | try {
160 | const result = await db.users.create(data)
161 | return { data: result, error: null }
162 | } catch (error) {
163 | console.error('Failed to create user:', error)
164 | return { data: null, error: 'Failed to create user' }
165 | }
166 |
167 | // ❌ DON'T: Skip error handling
168 | const result = await db.users.create(data)
169 | return result
170 | ```
171 |
172 | - [ ] Database error handling
173 | - [ ] User-facing errors
174 | - [ ] Error boundaries
175 | - [ ] Validation messages
176 | - [ ] Error logging
177 |
178 | ### Type Safety
179 | ```typescript
180 | // ✅ DO: Proper typing
181 | interface User {
182 | id: string
183 | name: string
184 | email: string
185 | }
186 |
187 | export async function getUser(id: string): Promise {
188 | // Implementation
189 | }
190 |
191 | // ❌ DON'T: Use any
192 | export async function getUser(id: any): Promise {
193 | // Implementation
194 | }
195 | ```
196 |
197 | - [ ] TypeScript strict mode
198 | - [ ] Function type definitions
199 | - [ ] Database type inference
200 | - [ ] Minimal any usage
201 | - [ ] Module type exports
202 |
203 | ### Performance
204 | ```typescript
205 | // ✅ DO: Optimize queries
206 | const users = await db
207 | .select({ id: users.id, name: users.name })
208 | .from(users)
209 | .limit(10)
210 |
211 | // ❌ DON'T: Over-fetch
212 | const users = await db.select().from(users)
213 | ```
214 |
215 | - [ ] Query optimization
216 | - [ ] React.cache() usage
217 | - [ ] Loading/error states
218 | - [ ] Image optimization
219 | - [ ] Bundle size management
220 |
221 | ### Testing
222 | ```typescript
223 | // ✅ DO: Proper testing
224 | describe('createUser', () => {
225 | it('should create a user', async () => {
226 | const input = { name: 'Test' }
227 | const result = await createUser(input)
228 | expect(result.data).toBeDefined()
229 | })
230 | })
231 |
232 | // ❌ DON'T: Skip error cases
233 | describe('createUser', () => {
234 | it('creates user', async () => {
235 | expect(await createUser({})).toBeDefined()
236 | })
237 | })
238 | ```
239 |
240 | - [ ] Server action tests
241 | - [ ] Mocked database operations
242 | - [ ] Component testing
243 | - [ ] Integration tests
244 | - [ ] Error scenario tests
245 |
246 | ### Documentation
247 | ```typescript
248 | // ✅ DO: Proper documentation
249 | /**
250 | * Creates a new user in the system
251 | * @param {CreateUserInput} input - User creation input
252 | * @returns {Promise} Created user or error
253 | */
254 | export async function createUser(input: CreateUserInput) {
255 | // Implementation
256 | }
257 |
258 | // ❌ DON'T: Skip documentation
259 | export async function createUser(input) {
260 | // Implementation
261 | }
262 | ```
263 |
264 | - [ ] JSDoc comments
265 | - [ ] Function documentation
266 | - [ ] API documentation
267 | - [ ] Schema documentation
268 | - [ ] README updates
269 |
270 | ## Review Response Guidelines
271 |
272 | ### Providing Feedback
273 | - Be specific and reference rules
274 | - Explain why changes are needed
275 | - Provide examples when possible
276 | - Keep feedback constructive
277 |
278 | ### Addressing Feedback
279 | - Acknowledge all comments
280 | - Explain complex changes
281 | - Update related documentation
282 | - Verify fixes with tests
283 |
284 | ## References
285 | - [Next.js 15 Rules](mdc:.cursor/rules/nextjs-15.mdc)
286 | - [Data Access Rules](mdc:.cursor/rules/data-access.mdc)
287 | - [Server Actions Rules](mdc:.cursor/rules/server-actions.mdc)
288 | - [Naming Conventions](mdc:.cursor/rules/naming-conventions.mdc)
289 |
--------------------------------------------------------------------------------
/nextjs/data-access.mdc:
--------------------------------------------------------------------------------
1 | ---
2 | description: Guidelines for implementing data access through query and mutation modules
3 | globs: lib/data/**/*.ts
4 | alwaysApply: true
5 | ---
6 |
7 | # Data Access Layer Structure
8 |
9 | ## Overview
10 | Best practices for implementing data access through query and mutation modules. These modules serve as the single source of truth for database operations and should be used by server actions.
11 |
12 | - **File Organization**
13 | ```
14 | lib/data/
15 | ├── mutations/
16 | │ ├── organizations.ts
17 | │ ├── users.ts
18 | │ └── comments.ts
19 | └── queries/
20 | ├── organizations.ts
21 | ├── users.ts
22 | └── comments.ts
23 | ```
24 |
25 | - **Query Module Structure**
26 | - Place all read operations in `queries/` directory
27 | - Name files after the primary entity they query
28 | - Return consistent data structures
29 | ```typescript
30 | // ✅ DO: Consistent error handling and return types
31 | import { organizations, organizationMembers } from '@/db/schema/organizations'
32 | import { eq, or } from 'drizzle-orm'
33 | import { createDrizzleSupabaseClient } from '@/db'
34 |
35 | export async function getUserOrganization(userId: string) {
36 | try {
37 | const db = await createDrizzleSupabaseClient()
38 | const orgs = await db.rls((tx) =>
39 | tx
40 | .select()
41 | .from(organizations)
42 | .innerJoin(organizationMembers, eq(organizations.id, organizationMembers.organization_id))
43 | .where(or(eq(organizations.owner_id, userId), eq(organizationMembers.user_id, userId)))
44 | .limit(1),
45 | )
46 | return { data: orgs[0] || null, error: null }
47 | } catch (error) {
48 | return {
49 | data: null,
50 | error: error instanceof Error ? error : new Error('Failed to fetch organization')
51 | }
52 | }
53 | }
54 | ```
55 |
56 | ```typescript
57 | // ❌ DON'T: Inconsistent error handling or return types
58 | export async function getUserOrganization(userId: string) {
59 | const db = await createDrizzleSupabaseClient()
60 | const orgs = await db.rls((tx) =>
61 | tx.select().from(organizations).where(eq(organizations.owner_id, userId))
62 | )
63 | return orgs[0] // ❌ No error handling, inconsistent return type
64 | }
65 | ```
66 |
67 | - **Mutation Module Structure**
68 | - Place all write operations in `mutations/` directory
69 | - Name files after the primary entity they modify
70 | - Handle transactions and related updates
71 | ```typescript
72 | // ✅ DO: Handle transactions and related updates
73 | import { organizations, organizationMembers } from '@/db/schema/organizations'
74 | import { createDrizzleSupabaseClient } from '@/db'
75 | import { eq } from 'drizzle-orm'
76 |
77 | export async function createOrganization(name: string, logoUrl: string | null, ownerId: string) {
78 | try {
79 | const db = await createDrizzleSupabaseClient()
80 | const org = await db.rls((tx) =>
81 | tx
82 | .insert(organizations)
83 | .values({
84 | name,
85 | logo_url: logoUrl,
86 | owner_id: ownerId,
87 | })
88 | .returning(),
89 | )
90 |
91 | // Related update in the same transaction
92 | await db.rls((tx) =>
93 | tx.insert(organizationMembers).values({
94 | organization_id: org[0].id,
95 | user_id: ownerId,
96 | role: 'owner',
97 | }),
98 | )
99 |
100 | return { data: org[0], error: null }
101 | } catch (error) {
102 | return {
103 | data: null,
104 | error: error instanceof Error ? error : new Error('Failed to create organization')
105 | }
106 | }
107 | }
108 | ```
109 |
110 | ```typescript
111 | // ❌ DON'T: Skip related updates or error handling
112 | export async function createOrganization(name: string, ownerId: string) {
113 | const db = await createDrizzleSupabaseClient()
114 | return await db.rls((tx) =>
115 | tx.insert(organizations).values({ name, owner_id: ownerId })
116 | ) // ❌ Missing member creation, no error handling
117 | }
118 | ```
119 |
120 | - **Error Handling**
121 | - Use consistent error return types
122 | - Wrap all database operations in try-catch
123 | - Return typed error objects
124 | ```typescript
125 | // ✅ DO: Consistent error handling
126 | type QueryResult = {
127 | data: T | null;
128 | error: Error | null;
129 | }
130 |
131 | export async function getOrganizationById(id: string): Promise> {
132 | try {
133 | const db = await createDrizzleSupabaseClient()
134 | const [org] = await db.rls((tx) =>
135 | tx.select().from(organizations).where(eq(organizations.id, id)).limit(1)
136 | )
137 | return { data: org || null, error: null }
138 | } catch (error) {
139 | return {
140 | data: null,
141 | error: error instanceof Error ? error : new Error('Failed to fetch organization')
142 | }
143 | }
144 | }
145 | ```
146 |
147 | - **Type Safety**
148 | - Use Drizzle's inferred types
149 | - Define explicit return types for all functions
150 | ```typescript
151 | // ✅ DO: Use inferred types and type parameters
152 | export async function updateOrganization(
153 | id: string,
154 | data: Partial
155 | ) {
156 | try {
157 | const db = await createDrizzleSupabaseClient()
158 | const [org] = await db.rls((tx) =>
159 | tx.update(organizations)
160 | .set(data)
161 | .where(eq(organizations.id, id))
162 | .returning()
163 | )
164 | return { data: org, error: null }
165 | } catch (error) {
166 | return {
167 | data: null,
168 | error: error instanceof Error ? error : new Error('Failed to update organization')
169 | }
170 | }
171 | }
172 | ```
173 |
174 | - **Query Optimization**
175 | - Use appropriate joins
176 | - Select only needed columns
177 | - Add proper where clauses
178 | ```typescript
179 | // ✅ DO: Optimize queries with joins and column selection
180 | export async function getUserOrganizations() {
181 | try {
182 | const db = await createDrizzleSupabaseClient()
183 | const result = await db.rls(async (tx) => {
184 | return await tx
185 | .select({
186 | id: organizations.id,
187 | name: organizations.name,
188 | logo_url: organizations.logo_url,
189 | created_at: organizations.created_at,
190 | updated_at: organizations.updated_at,
191 | owner_id: organizations.owner_id,
192 | role: organizationMembers.role,
193 | })
194 | .from(organizations)
195 | .innerJoin(
196 | organizationMembers,
197 | eq(organizations.id, organizationMembers.organization_id)
198 | )
199 | })
200 | return result
201 | } catch (error) {
202 | console.error('Error fetching organizations:', error)
203 | return []
204 | }
205 | }
206 | ```
207 |
208 | - **Delete Operations**
209 | - Return consistent response format
210 | - Handle cascading deletes appropriately
211 | ```typescript
212 | // ✅ DO: Consistent delete operation structure
213 | export async function deleteOrganization(id: string) {
214 | try {
215 | const db = await createDrizzleSupabaseClient()
216 | await db.rls((tx) =>
217 | tx.delete(organizations).where(eq(organizations.id, id))
218 | )
219 | return { error: null }
220 | } catch (error) {
221 | return {
222 | error: error instanceof Error ? error : new Error('Failed to delete organization')
223 | }
224 | }
225 | }
226 | ```
227 |
228 | ## Best Practices Summary
229 | 1. **Separation of Concerns**
230 | - Queries handle read operations
231 | - Mutations handle write operations
232 | - Each file focuses on one entity type
233 |
234 | 2. **Error Handling**
235 | - Consistent error return types
236 | - Descriptive error messages
237 | - Proper error propagation
238 |
239 | 3. **Type Safety**
240 | - Use Drizzle's inferred types
241 | - Define explicit return types
242 | - Type all function parameters
243 |
244 | 4. **Performance**
245 | - Optimize database queries
246 | - Use appropriate joins
247 | - Select only needed columns
248 |
249 | 5. **Transactions**
250 | - Handle related updates together
251 | - Maintain data consistency
252 | - Proper error rollback
253 |
254 | ## References
255 | - See also: [server-actions.mdc](mdc:.cursor/rules/server-actions.mdc) for using these modules in server actions
256 | - See also: [supabase-drizzle-bootstrap.mdc](mdc:.cursor/rules/supabase-drizzle-bootstrap.mdc) for Drizzle setup
257 |
--------------------------------------------------------------------------------
/nextjs/naming-conventions.mdc:
--------------------------------------------------------------------------------
1 | ---
2 | description: Enforces consistent naming patterns for files, types, and functions
3 | globs: *.ts, *.js, *.tsx
4 | ---
5 | # Naming Conventions
6 | Standards for naming TypeScript and JavaScript files, types, and functions.
7 |
8 |
9 | name: naming_conventions
10 | description: Enforces consistent naming patterns for files, types, and functions
11 | filters:
12 | # Match TypeScript and JavaScript files
13 | - type: file_extension
14 | pattern: "\\.(ts|js)$"
15 | # Match file creation and modification events
16 | - type: event
17 | pattern: "(file_create|file_modify)"
18 |
19 | actions:
20 | - type: reject
21 | conditions:
22 | # Reject files not in kebab-case
23 | - pattern: "^(?!.*[A-Z])(?!.*\\s)(?!.*_)[a-z0-9-]+\\.(ts|js)$"
24 | message: "File names must be in kebab-case (e.g., my-file-name.ts)"
25 |
26 | - type: suggest
27 | message: |
28 | Follow these naming conventions:
29 |
30 | 1. Files:
31 | - Use kebab-case for all TypeScript and JavaScript files
32 | - Examples:
33 | ✅ user-service.ts
34 | ✅ api-client.js
35 | ❌ UserService.ts
36 | ❌ apiClient.js
37 |
38 | 2. Types (interfaces, types, classes):
39 | - Use PascalCase
40 | - Examples:
41 | ✅ interface UserProfile
42 | ✅ type ApiResponse
43 | ✅ class HttpClient
44 | ❌ interface userProfile
45 | ❌ type api_response
46 |
47 | 3. Functions:
48 | - Use camelCase
49 | - Examples:
50 | ✅ function getUserData()
51 | ✅ const fetchApiResponse = () => {}
52 | ❌ function GetUserData()
53 | ❌ const fetch_api_response = () => {}
54 |
55 | examples:
56 | - input: |
57 | // Bad: Incorrect naming
58 | UserService.ts
59 | API_client.js
60 |
61 | interface user_profile {}
62 | function FetchData() {}
63 |
64 | // Good: Correct naming
65 | user-service.ts
66 | api-client.js
67 |
68 | interface UserProfile {}
69 | function fetchData() {}
70 | output: "Correctly named files, types, and functions"
71 |
72 | metadata:
73 | priority: high
74 | version: 1.0
75 |
76 |
--------------------------------------------------------------------------------
/nextjs/nextjs-15.mdc:
--------------------------------------------------------------------------------
1 | ---
2 | description: Best practices and conventions for Next.js 15 applications
3 | globs: *.tsx, *.jsx
4 | alwaysApply: false
5 | ---
6 | # Next.js 15 Best Practices
7 |
8 | name: nextjs_15
9 | description: Best practices and conventions for Next.js 15 applications
10 | filters:
11 | - type: file_extension
12 | pattern: ".tsx?$|.jsx?$"
13 | - type: content
14 | pattern: "(?s).*"
15 |
16 | actions:
17 | # Folder Structure Rules
18 | - type: reject
19 | conditions:
20 | - pattern: "^src/"
21 | message: "Avoid using a src folder; structure your project as per Next.js 15 conventions."
22 |
23 | - type: suggest
24 | message: |
25 | Ensure your Next.js 15 project follows this directory structure:
26 | ```
27 | app/
28 | ├── actions/ # Server actions
29 | ├── api/ # API routes
30 | ├── auth/ # Authentication related pages
31 | ├── login/ # Login page
32 | └── signup/ # Signup page
33 |
34 | components/
35 | ├── auth/ # Authentication components
36 | ├── layout/ # Layout components
37 | └── ui/ # UI components (shadcn)
38 |
39 | db/
40 | └── schema/ # Drizzle schema files
41 |
42 | lib/ # Libraries and utilities
43 | public/ # Static assets
44 | utils/ # Utility functions
45 | ```
46 |
47 | # General Best Practices
48 | - type: reject
49 | conditions:
50 | - pattern: "import\s+.*\s+from\s+['\"]\.\./.*"
51 | message: "Use absolute imports instead of relative imports. Configure paths in tsconfig.json"
52 |
53 | - pattern: "use client['\"]\s*;?\s*export\s+default\s+function\s+Page"
54 | message: "page.tsx files should not include 'use client'; they are server-only by default"
55 |
56 | - pattern: "export\s+default\s+function\s+Page\s*\(\s*\{\s*params\s*\}\s*\)\s*\{"
57 | message: "Pages with params or searchParams should be async functions"
58 |
59 | - pattern: "
{
90 | // server action
91 | }}>
92 | {/* form fields */}
93 |
94 | );
95 | }
96 | ```
97 |
98 | # Layout Rules
99 | - type: reject
100 | conditions:
101 | - pattern: "export\s+default\s+function\s+\w+Layout\s*\(\s*\{\s*children\s*,\s*params\s*\}\s*\)\s*\{"
102 | message: "Layouts with params should be async functions"
103 |
104 | - type: suggest
105 | conditions:
106 | - pattern: "function\s+\w+Layout"
107 | message: |
108 | Layout best practices:
109 | - RootLayout should be a standard function
110 | - Layouts with params should be async
111 | - Implement loading.tsx for Suspense
112 | - Implement not-found.tsx for 404 errors
113 |
114 | # Route Handler Rules
115 | - type: reject
116 | conditions:
117 | - pattern: "export\s+function\s+(GET|POST|PUT|DELETE|PATCH)\s*\("
118 | message: "Route handlers should be async functions"
119 |
120 | - type: suggest
121 | conditions:
122 | - pattern: "route.ts$"
123 | message: |
124 | Route handler best practices:
125 | ```typescript
126 | import { NextResponse } from 'next/server';
127 |
128 | export async function GET(
129 | request: Request,
130 | { params }: { params: { id: string } }
131 | ) {
132 | try {
133 | // Your logic here
134 | return NextResponse.json({ data });
135 | } catch (error) {
136 | return NextResponse.json(
137 | { error: 'Error message' },
138 | { status: 500 }
139 | );
140 | }
141 | }
142 | ```
143 |
144 | # SEO and Performance
145 | - type: suggest
146 | conditions:
147 | - pattern: "app/layout.tsx$"
148 | message: |
149 | SEO best practices:
150 | - Implement metadata in layout.tsx
151 | - Generate sitemap.ts
152 | - Use generateStaticParams for static pages
153 | - Implement robots.txt
154 | Example:
155 | ```typescript
156 | import type { Metadata } from 'next';
157 |
158 | export const metadata: Metadata = {
159 | title: {
160 | template: '%s | Your Site',
161 | default: 'Your Site',
162 | },
163 | description: 'Your site description',
164 | };
165 | ```
166 |
167 | metadata:
168 | priority: high
169 | version: 1.0
170 | framework: next.js
171 | frameworkVersion: "15.0.0"
172 |
173 |
--------------------------------------------------------------------------------
/nextjs/server-actions.mdc:
--------------------------------------------------------------------------------
1 | ---
2 | description: Guidelines for implementing server actions with direct database mutations and queries
3 | globs: app/actions/**/*.ts, app/actions/**/*.tsx
4 | alwaysApply: true
5 | ---
6 |
7 | # Server Actions with Database Operations
8 |
9 | ## Overview
10 | Best practices for implementing server actions that interact with the database through abstracted query and mutation modules.
11 |
12 | - **File Organization**
13 | - Place all server actions in `app/actions/` directory
14 | - Group related actions in subdirectories by feature
15 | - Place database operations in separate query/mutation modules
16 | ```
17 | app/
18 | ├── actions/
19 | │ ├── auth/
20 | │ │ ├── login.ts
21 | │ │ └── register.ts
22 | │ └── organization/
23 | │ ├── create.ts
24 | │ └── update.ts
25 | lib/
26 | ├── data/
27 | │ ├── mutations/
28 | │ │ └── organizations.ts
29 | │ └── queries/
30 | │ └── organizations.ts
31 | ```
32 |
33 | - **Server Action Implementation**
34 | - **Always use 'use server' directive**
35 | - **Import mutations/queries from lib/data**
36 | ```typescript
37 | // ✅ DO: Use abstracted database operations
38 | 'use server';
39 |
40 | import { createOrganization } from '@/lib/data/mutations/organizations';
41 | import { getUserOrganizations } from '@/lib/data/queries/organizations';
42 | import { redirect } from 'next/navigation';
43 |
44 | export async function createUserOrganization(formData: FormData) {
45 | const name = formData.get('name') as string;
46 | const logoUrl = formData.get('logo_url') as string;
47 |
48 | // Get user from auth if needed
49 | const {
50 | data: { user },
51 | } = await supabase.auth.getUser();
52 |
53 | if (!user) {
54 | return redirect('/login?error=No user found');
55 | }
56 |
57 | const { error } = await createOrganization(name, logoUrl, user.id);
58 |
59 | if (error) {
60 | return redirect('/login/organization?error=Could not create organization');
61 | }
62 |
63 | return redirect('/welcome');
64 | }
65 |
66 | export async function fetchUserOrganizations() {
67 | const organizations = await getUserOrganizations();
68 | return organizations;
69 | }
70 | ```
71 |
72 | ```typescript
73 | // ❌ DON'T: Mix database logic in server actions
74 | 'use server';
75 |
76 | import { createDrizzleSupabaseClient } from '@/db';
77 | import { organizations } from '@/db/schema';
78 |
79 | export async function createUserOrganization(formData: FormData) {
80 | const db = await createDrizzleSupabaseClient();
81 | await db.rls(async (tx) => {
82 | await tx.insert(organizations).values({
83 | name: formData.get('name') as string,
84 | logo_url: formData.get('logo_url') as string,
85 | });
86 | });
87 | }
88 | ```
89 |
90 | - **Query/Mutation Module Structure**
91 | ```typescript
92 | // ✅ DO: lib/data/mutations/organizations.ts
93 | import { createDrizzleSupabaseClient } from '@/db';
94 | import { organizations } from '@/db/schema';
95 | import { eq } from 'drizzle-orm';
96 |
97 | export async function createOrganization(name: string, logoUrl: string, userId: string) {
98 | const db = await createDrizzleSupabaseClient();
99 |
100 | try {
101 | await db.rls(async (tx) => {
102 | await tx.insert(organizations).values({
103 | name,
104 | logo_url: logoUrl,
105 | user_id: userId,
106 | });
107 | });
108 | return { error: null };
109 | } catch (error) {
110 | console.error('Failed to create organization:', error);
111 | return { error };
112 | }
113 | }
114 | ```
115 |
116 | ```typescript
117 | // ✅ DO: lib/data/queries/organizations.ts
118 | import { createDrizzleSupabaseClient } from '@/db';
119 | import { organizations } from '@/db/schema';
120 | import { cache } from 'react';
121 |
122 | export const getUserOrganizations = cache(async () => {
123 | const db = await createDrizzleSupabaseClient();
124 |
125 | return await db.rls(async (tx) => {
126 | return await tx.query.organizations.findMany({
127 | columns: {
128 | id: true,
129 | name: true,
130 | logo_url: true,
131 | },
132 | orderBy: (orgs, { desc }) => [desc(orgs.created_at)],
133 | });
134 | });
135 | });
136 | ```
137 |
138 | - **Error Handling**
139 | - Handle database errors in mutation/query modules
140 | - Handle UI/redirect logic in server actions
141 | ```typescript
142 | // ✅ DO: Separate error handling concerns
143 | // lib/data/mutations/organizations.ts
144 | export async function updateOrganization(id: string, data: UpdateOrganizationInput) {
145 | const db = await createDrizzleSupabaseClient();
146 |
147 | try {
148 | await db.rls(async (tx) => {
149 | await tx.update(organizations)
150 | .set(data)
151 | .where(eq(organizations.id, id));
152 | });
153 | return { error: null };
154 | } catch (error) {
155 | console.error('Failed to update organization:', error);
156 | return { error };
157 | }
158 | }
159 |
160 | // app/actions/organization/update.ts
161 | export async function updateUserOrganization(formData: FormData) {
162 | const { error } = await updateOrganization(
163 | formData.get('id') as string,
164 | {
165 | name: formData.get('name') as string,
166 | logo_url: formData.get('logo_url') as string,
167 | }
168 | );
169 |
170 | if (error) {
171 | return redirect('/organization?error=Could not update organization');
172 | }
173 |
174 | return redirect('/organization?success=Organization updated');
175 | }
176 | ```
177 |
178 | - **Data Validation**
179 | - Define validation schemas in separate files
180 | - Validate in mutation modules before database operations
181 | ```typescript
182 | // ✅ DO: lib/validations/organization.ts
183 | import { z } from 'zod';
184 |
185 | export const organizationSchema = z.object({
186 | name: z.string().min(1).max(100),
187 | logo_url: z.string().url().optional(),
188 | });
189 |
190 | // lib/data/mutations/organizations.ts
191 | import { organizationSchema } from '@/lib/validations/organization';
192 |
193 | export async function createOrganization(name: string, logoUrl: string, userId: string) {
194 | const result = organizationSchema.safeParse({ name, logo_url: logoUrl });
195 |
196 | if (!result.success) {
197 | return { error: { message: 'Invalid input', details: result.error.format() } };
198 | }
199 |
200 | // Database operations...
201 | }
202 | ```
203 |
204 | - **Type Safety**
205 | - Define types for mutation/query inputs and outputs
206 | - Use Drizzle's generated types
207 | ```typescript
208 | // ✅ DO: lib/types/organization.ts
209 | import { type Organization } from '@/db/schema';
210 |
211 | export type CreateOrganizationInput = Pick;
212 | export type UpdateOrganizationInput = Partial;
213 |
214 | // lib/data/mutations/organizations.ts
215 | import { type CreateOrganizationInput } from '@/lib/types/organization';
216 |
217 | export async function createOrganization(input: CreateOrganizationInput, userId: string) {
218 | // Implementation...
219 | }
220 | ```
221 |
222 | - **Testing**
223 | - Test mutation/query modules independently
224 | - Test server actions with mocked mutation/query functions
225 | ```typescript
226 | // ✅ DO: Test separation of concerns
227 | import { describe, it, expect, vi } from 'vitest';
228 | import { createUserOrganization } from './organization';
229 | import { createOrganization } from '@/lib/data/mutations/organizations';
230 |
231 | vi.mock('@/lib/data/mutations/organizations', () => ({
232 | createOrganization: vi.fn(),
233 | }));
234 |
235 | describe('createUserOrganization', () => {
236 | it('should create an organization', async () => {
237 | vi.mocked(createOrganization).mockResolvedValue({ error: null });
238 |
239 | const formData = new FormData();
240 | formData.append('name', 'Test Org');
241 | formData.append('logo_url', 'https://example.com/logo.png');
242 |
243 | const result = await createUserOrganization(formData);
244 | expect(result).toBeDefined();
245 | });
246 | });
247 | ```
248 |
249 | ## References
250 | - [Next.js Server Actions](mdc:https:/nextjs.org/docs/app/api-reference/functions/server-actions)
251 | - [Drizzle ORM Documentation](mdc:https:/orm.drizzle.team/docs/overview)
252 | - See also: [nextjs-15.mdc](mdc:.cursor/rules/nextjs-15.mdc) for general Next.js conventions
253 | - See also: [supabase-drizzle-bootstrap.mdc](mdc:.cursor/rules/supabase-drizzle-bootstrap.mdc) for Drizzle setup
254 |
--------------------------------------------------------------------------------
/nextjs/shadcn.mdc:
--------------------------------------------------------------------------------
1 | ---
2 | description: Use shadcn/ui components as needed for any UI code
3 | globs: *.tsx
4 | alwaysApply: false
5 | ---
6 |
7 | # Shadcn UI Components
8 |
9 | This project uses @shadcn/ui for UI components. These are beautifully designed, accessible components that you can copy and paste into your apps.
10 |
11 | ## Finding and Using Components
12 |
13 | Components are available in the `src/components/ui` directory, following the aliases configured in `components.json`
14 |
15 | ## Using Components
16 |
17 | Import components from the ui directory using the configured aliases:
18 |
19 | ```tsx
20 | import { Button } from "@/components/ui/button"
21 | import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
22 | import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"
23 | ```
24 |
25 | Example usage:
26 |
27 | ```tsx
28 |
29 |
30 |
31 |
32 | Card Title
33 | Card Description
34 |
35 |
36 | Card Content
37 |
38 |
39 | Card Footer
40 |
41 |
42 | ```
43 |
44 | ## Installing Additional Components
45 |
46 | Many more components are available but not currently installed. You can view the complete list at https://ui.shadcn.com/r
47 |
48 | To install additional components, use the Shadcn CLI:
49 |
50 |
51 | ```bash
52 | npx shadcn@latest add [component-name]
53 | ```
54 |
55 | For example, to add the Accordion component:
56 |
57 | ```bash
58 | npx shadcn@latest add accordion
59 | ```
60 |
61 | Note: `npx shadcn-ui@latest` is deprecated, use `npx shadcn@latest` instead
62 |
63 | Some commonly used components are
64 |
65 | - Accordion
66 | - Alert
67 | - AlertDialog
68 | - AspectRatio
69 | - Avatar
70 | - Calendar
71 | - Checkbox
72 | - Collapsible
73 | - Command
74 | - ContextMenu
75 | - DataTable
76 | - DatePicker
77 | - Dropdown Menu
78 | - Form
79 | - Hover Card
80 | - Menubar
81 | - Navigation Menu
82 | - Popover
83 | - Progress
84 | - Radio Group
85 | - ScrollArea
86 | - Select
87 | - Separator
88 | - Sheet
89 | - Skeleton
90 | - Slider
91 | - Switch
92 | - Table
93 | - Textarea
94 | - Toast
95 | - Toggle
96 | - Tooltip
97 |
98 | ## Component Styling
99 |
100 | This project uses the "new-york" style variant with the "neutral" base color and CSS variables for theming, as configured in `components.json`.
--------------------------------------------------------------------------------
/nextjs/solid-principles.mdc:
--------------------------------------------------------------------------------
1 | ---
2 | description:
3 | globs:
4 | alwaysApply: false
5 | ---
6 | # SOLID Principles
7 | Guidelines for implementing SOLID principles in the codebase.
8 |
9 |
10 | name: solid_principles
11 | description: Enforces SOLID principles in code design and implementation
12 | filters:
13 | - type: file_extension
14 | pattern: "\\.ts$|\\.js$"
15 | - type: content
16 | pattern: "(?s)class.*?\\{|interface.*?\\{|function.*?\\{"
17 |
18 | actions:
19 | - type: suggest
20 | message: |
21 | When writing code, follow these SOLID principles:
22 |
23 | 1. Single Responsibility Principle (SRP):
24 | - Each class/module should have only one reason to change
25 | - Keep classes focused and cohesive
26 | - Extract separate concerns into their own classes
27 | Example:
28 | ```typescript
29 | // Good: Single responsibility
30 | class UserAuthentication {
31 | authenticate(credentials: Credentials): boolean { ... }
32 | }
33 | class UserProfile {
34 | updateProfile(data: ProfileData): void { ... }
35 | }
36 |
37 | // Bad: Multiple responsibilities
38 | class User {
39 | authenticate(credentials: Credentials): boolean { ... }
40 | updateProfile(data: ProfileData): void { ... }
41 | sendEmail(message: string): void { ... }
42 | }
43 | ```
44 |
45 | 2. Open/Closed Principle (OCP):
46 | - Classes should be open for extension but closed for modification
47 | - Use interfaces and abstract classes
48 | - Implement new functionality through inheritance/composition
49 | Example:
50 | ```typescript
51 | // Good: Open for extension
52 | interface PaymentProcessor {
53 | process(payment: Payment): void;
54 | }
55 | class CreditCardProcessor implements PaymentProcessor { ... }
56 | class PayPalProcessor implements PaymentProcessor { ... }
57 |
58 | // Bad: Closed for extension
59 | class PaymentProcessor {
60 | process(payment: Payment, type: string): void {
61 | if (type === 'credit') { ... }
62 | else if (type === 'paypal') { ... }
63 | }
64 | }
65 | ```
66 |
67 | 3. Liskov Substitution Principle (LSP):
68 | - Derived classes must be substitutable for their base classes
69 | - Maintain expected behavior when using inheritance
70 | - Don't violate base class contracts
71 | Example:
72 | ```typescript
73 | // Good: Derived class maintains base contract
74 | class Bird {
75 | fly(): void { ... }
76 | }
77 | class Sparrow extends Bird {
78 | fly(): void { ... } // Implements flying behavior
79 | }
80 |
81 | // Bad: Violates base contract
82 | class Penguin extends Bird {
83 | fly(): void {
84 | throw new Error("Can't fly!"); // Violates base class contract
85 | }
86 | }
87 | ```
88 |
89 | 4. Interface Segregation Principle (ISP):
90 | - Don't force clients to depend on interfaces they don't use
91 | - Keep interfaces small and focused
92 | - Split large interfaces into smaller ones
93 | Example:
94 | ```typescript
95 | // Good: Segregated interfaces
96 | interface Readable {
97 | read(): void;
98 | }
99 | interface Writable {
100 | write(data: string): void;
101 | }
102 |
103 | // Bad: Fat interface
104 | interface FileSystem {
105 | read(): void;
106 | write(data: string): void;
107 | delete(): void;
108 | create(): void;
109 | modify(): void;
110 | }
111 | ```
112 |
113 | 5. Dependency Inversion Principle (DIP):
114 | - High-level modules shouldn't depend on low-level modules
115 | - Both should depend on abstractions
116 | - Use dependency injection
117 | Example:
118 | ```typescript
119 | // Good: Depends on abstraction
120 | interface Logger {
121 | log(message: string): void;
122 | }
123 | class UserService {
124 | constructor(private logger: Logger) {}
125 | }
126 |
127 | // Bad: Depends on concrete implementation
128 | class UserService {
129 | private logger = new FileLogger();
130 | }
131 | ```
132 |
133 | Additional Guidelines:
134 | - Use interfaces to define contracts
135 | - Implement dependency injection
136 | - Keep classes small and focused
137 | - Use composition over inheritance when possible
138 | - Write unit tests to verify SOLID compliance
139 |
140 | examples:
141 | - input: |
142 | // Bad example - violates SRP and OCP
143 | class OrderProcessor {
144 | processOrder(order: Order) {
145 | // Handles validation
146 | // Handles payment
147 | // Handles shipping
148 | // Handles notification
149 | }
150 | }
151 | output: |
152 | // Good example - follows SOLID principles
153 | interface OrderValidator {
154 | validate(order: Order): boolean;
155 | }
156 | interface PaymentProcessor {
157 | process(order: Order): void;
158 | }
159 | interface ShippingService {
160 | ship(order: Order): void;
161 | }
162 | interface NotificationService {
163 | notify(order: Order): void;
164 | }
165 |
166 | class OrderProcessor {
167 | constructor(
168 | private validator: OrderValidator,
169 | private paymentProcessor: PaymentProcessor,
170 | private shippingService: ShippingService,
171 | private notificationService: NotificationService
172 | ) {}
173 |
174 | processOrder(order: Order) {
175 | if (this.validator.validate(order)) {
176 | this.paymentProcessor.process(order);
177 | this.shippingService.ship(order);
178 | this.notificationService.notify(order);
179 | }
180 | }
181 | }
182 |
183 | metadata:
184 | priority: high
185 | version: 1.0
186 | tags:
187 | - code-quality
188 | - design-patterns
189 | - best-practices
190 |
191 |
--------------------------------------------------------------------------------
/nextjs/tailwindcss-4.mdc:
--------------------------------------------------------------------------------
1 | ---
2 | description: Guide for using Tailwind CSS v4 instead of v3.x
3 | globs: **/*.{js,ts,jsx,tsx,mdx,css}
4 | alwaysApply: false
5 | ---
6 |
7 |
8 | # Tailwind CSS v4
9 |
10 | ## Core Changes
11 |
12 | - **CSS-first configuration**: Configuration is now done in CSS instead of JavaScript
13 | - Use `@theme` directive in CSS instead of `tailwind.config.js`
14 | - Example:
15 | ```css
16 | @import "tailwindcss";
17 |
18 | @theme {
19 | --font-display: "Satoshi", "sans-serif";
20 | --breakpoint-3xl: 1920px;
21 | --color-avocado-500: oklch(0.84 0.18 117.33);
22 | --ease-fluid: cubic-bezier(0.3, 0, 0, 1);
23 | }
24 | ```
25 | - Legacy `tailwind.config.js` files can still be imported using the `@config` directive:
26 | ```css
27 | @import "tailwindcss";
28 | @config "../../tailwind.config.js";
29 | ```
30 | - **CSS import syntax**: Use `@import "tailwindcss"` instead of `@tailwind` directives
31 | - Old: `@tailwind base; @tailwind components; @tailwind utilities;`
32 | - New: `@import "tailwindcss";`
33 |
34 | - **Package changes**:
35 | - PostCSS plugin is now `@tailwindcss/postcss` (not `tailwindcss`)
36 | - CLI is now `@tailwindcss/cli`
37 | - Vite plugin is `@tailwindcss/vite`
38 | - No need for `postcss-import` or `autoprefixer` anymore
39 |
40 | - **Native CSS cascade layers**: Uses real CSS `@layer` instead of Tailwind's custom implementation
41 |
42 | ## Theme Configuration
43 |
44 | - **CSS theme variables**: All design tokens are available as CSS variables
45 | - Namespace format: `--category-name` (e.g., `--color-blue-500`, `--font-sans`)
46 | - Access in CSS: `var(--color-blue-500)`
47 | - Available namespaces:
48 | - `--color-*` : Color utilities like `bg-red-500` and `text-sky-300`
49 | - `--font-*` : Font family utilities like `font-sans`
50 | - `--text-*` : Font size utilities like `text-xl`
51 | - `--font-weight-*` : Font weight utilities like `font-bold`
52 | - `--tracking-*` : Letter spacing utilities like `tracking-wide`
53 | - `--leading-*` : Line height utilities like `leading-tight`
54 | - `--breakpoint-*` : Responsive breakpoint variants like `sm:*`
55 | - `--container-*` : Container query variants like `@sm:*` and size utilities like `max-w-md`
56 | - `--spacing-*` : Spacing and sizing utilities like `px-4` and `max-h-16`
57 | - `--radius-*` : Border radius utilities like `rounded-sm`
58 | - `--shadow-*` : Box shadow utilities like `shadow-md`
59 | - `--inset-shadow-*` : Inset box shadow utilities like `inset-shadow-xs`
60 | - `--drop-shadow-*` : Drop shadow filter utilities like `drop-shadow-md`
61 | - `--blur-*` : Blur filter utilities like `blur-md`
62 | - `--perspective-*` : Perspective utilities like `perspective-near`
63 | - `--aspect-*` : Aspect ratio utilities like `aspect-video`
64 | - `--ease-*` : Transition timing function utilities like `ease-out`
65 | - `--animate-*` : Animation utilities like `animate-spin`
66 |
67 |
68 | - **Simplified theme configuration**: Many utilities no longer need theme configuration
69 | - Utilities like `grid-cols-12`, `z-40`, and `opacity-70` work without configuration
70 | - Data attributes like `data-selected:opacity-100` don't need configuration
71 |
72 | - **Dynamic spacing scale**: Derived from a single spacing value
73 | - Default: `--spacing: 0.25rem`
74 | - Every multiple of the base value is available (e.g., `mt-21` works automatically)
75 |
76 | - **Overriding theme namespaces**:
77 | - Override entire namespace: `--font-*: initial;`
78 | - Override entire theme: `--*: initial;`
79 |
80 |
81 | ## New Features
82 |
83 | - **Container query support**: Built-in now, no plugin needed
84 | - `@container` for container context
85 | - `@sm:`, `@md:`, etc. for container-based breakpoints
86 | - `@max-md:` for max-width container queries
87 | - Combine with `@min-md:@max-xl:hidden` for ranges
88 |
89 | - **3D transforms**:
90 | - `transform-3d` enables 3D transforms
91 | - `rotate-x-*`, `rotate-y-*`, `rotate-z-*` for 3D rotation
92 | - `scale-z-*` for z-axis scaling
93 | - `translate-z-*` for z-axis translation
94 | - `perspective-*` utilities (`perspective-near`, `perspective-distant`, etc.)
95 | - `perspective-origin-*` utilities
96 | - `backface-visible` and `backface-hidden`
97 |
98 | - **Gradient enhancements**:
99 | - Linear gradient angles: `bg-linear-45` (renamed from `bg-gradient-*`)
100 | - Gradient interpolation: `bg-linear-to-r/oklch`, `bg-linear-to-r/srgb`
101 | - Conic and radial gradients: `bg-conic`, `bg-radial-[at_25%_25%]`
102 |
103 | - **Shadow enhancements**:
104 | - `inset-shadow-*` and `inset-ring-*` utilities
105 | - Can be composed with regular `shadow-*` and `ring-*`
106 |
107 | - **New CSS property utilities**:
108 | - `field-sizing-content` for auto-resizing textareas
109 | - `scheme-light`, `scheme-dark` for `color-scheme` property
110 | - `font-stretch-*` utilities for variable fonts
111 |
112 | ## New Variants
113 |
114 | - **Composable variants**: Chain variants together
115 | - Example: `group-has-data-potato:opacity-100`
116 |
117 | - **New variants**:
118 | - `starting` variant for `@starting-style` transitions
119 | - `not-*` variant for `:not()` pseudo-class
120 | - `inert` variant for `inert` attribute
121 | - `nth-*` variants (`nth-3:`, `nth-last-5:`, `nth-of-type-4:`, `nth-last-of-type-6:`)
122 | - `in-*` variant (like `group-*` but without adding `group` class)
123 | - `open` variant now supports `:popover-open`
124 | - `**` variant for targeting all descendants
125 |
126 | ## Custom Extensions
127 |
128 | - **Custom utilities**: Use `@utility` directive
129 | ```css
130 | @utility tab-4 {
131 | tab-size: 4;
132 | }
133 | ```
134 |
135 | - **Custom variants**: Use `@variant` directive
136 | ```css
137 | @variant pointer-coarse (@media (pointer: coarse));
138 | @variant theme-midnight (&:where([data-theme="midnight"] *));
139 | ```
140 |
141 | - **Plugins**: Use `@plugin` directive
142 | ```css
143 | @plugin "@tailwindcss/typography";
144 | ```
145 |
146 | ## Breaking Changes
147 |
148 | - **Removed deprecated utilities**:
149 | - `bg-opacity-*` → Use `bg-black/50` instead
150 | - `text-opacity-*` → Use `text-black/50` instead
151 | - And others: `border-opacity-*`, `divide-opacity-*`, etc.
152 |
153 | - **Renamed utilities**:
154 | - `shadow-sm` → `shadow-xs` (and `shadow` → `shadow-sm`)
155 | - `drop-shadow-sm` → `drop-shadow-xs` (and `drop-shadow` → `drop-shadow-sm`)
156 | - `blur-sm` → `blur-xs` (and `blur` → `blur-sm`)
157 | - `rounded-sm` → `rounded-xs` (and `rounded` → `rounded-sm`)
158 | - `outline-none` → `outline-hidden` (for the old behavior)
159 |
160 | - **Default style changes**:
161 | - Default border color is now `currentColor` (was `gray-200`)
162 | - Default `ring` width is now 1px (was 3px)
163 | - Placeholder text now uses current color at 50% opacity (was `gray-400`)
164 | - Hover styles only apply on devices that support hover (`@media (hover: hover)`)
165 |
166 | - **Syntax changes**:
167 | - CSS variables in arbitrary values: `bg-(--brand-color)` instead of `bg-[--brand-color]`
168 | - Stacked variants now apply left-to-right (not right-to-left)
169 | - Use CSS variables instead of `theme()` function
170 |
171 | ## Advanced Configuration
172 |
173 | - **Using a prefix**:
174 | ```css
175 | @import "tailwindcss" prefix(tw);
176 | ```
177 | - Results in classes like `tw:flex`, `tw:bg-red-500`, `tw:hover:bg-red-600`
178 |
179 | - **Source detection**:
180 | - Automatic by default (ignores `.gitignore` files and binary files)
181 | - Add sources: `@source "../node_modules/@my-company/ui-lib";`
182 | - Disable automatic detection: `@import "tailwindcss" source(none);`
183 |
184 | - **Legacy config files**:
185 | ```css
186 | @import "tailwindcss";
187 | @config "../../tailwind.config.js";
188 | ```
189 |
190 | - **Dark mode configuration**:
191 | ```css
192 | @import "tailwindcss";
193 | @variant dark (&:where(.dark, .dark *));
194 | ```
195 |
196 | - **Container customization**: Extend with `@utility`
197 | ```css
198 | @utility container {
199 | margin-inline: auto;
200 | padding-inline: 2rem;
201 | }
202 | ```
203 |
204 | - **Using `@apply` in Vue/Svelte**:
205 | ```html
206 |
215 | ```
--------------------------------------------------------------------------------
/open-source/community-projects.mdc:
--------------------------------------------------------------------------------
1 | ---
2 | description: Ensures proper setup of community project files and
3 | globs:
4 | ---
5 | # Community Projects Rule
6 | Standards for initializing and maintaining community-focused open source projects.
7 |
8 |
9 | name: community_projects
10 | description: Ensures proper setup of community project files and documentation
11 | filters:
12 | - type: event
13 | pattern: "project_init|project_validate"
14 | - type: directory
15 | pattern: ".*"
16 |
17 | actions:
18 | - type: validate
19 | description: "Validate required community files"
20 | requirements:
21 | - name: "README.md"
22 | required: true
23 | content:
24 | - "Project title and description"
25 | - "Installation instructions"
26 | - "Usage examples"
27 | - "Contributing guidelines reference"
28 | - "License reference"
29 | - name: "CONTRIBUTING.md"
30 | required: true
31 | content:
32 | - "How to contribute"
33 | - "Development setup"
34 | - "Pull request process"
35 | - "Code style guidelines"
36 | - "Testing requirements"
37 | - name: "LICENSE"
38 | required: true
39 | content:
40 | - "Valid open source license text"
41 | - "Current year"
42 | - "Copyright holder information"
43 | - name: "CODE_OF_CONDUCT.md"
44 | required: true
45 | content:
46 | - "Expected behavior"
47 | - "Unacceptable behavior"
48 | - "Reporting process"
49 | - "Enforcement guidelines"
50 | - "Contact information"
51 |
52 | - type: suggest
53 | message: |
54 | When setting up a community project, ensure:
55 |
56 | 1. README.md contains:
57 | ```markdown
58 | # Project Name
59 |
60 | Brief description of the project.
61 |
62 | ## Installation
63 |
64 | Step-by-step installation instructions.
65 |
66 | ## Usage
67 |
68 | Basic usage examples.
69 |
70 | ## Contributing
71 |
72 | Please read [CONTRIBUTING.md](mdc:CONTRIBUTING.md) for details on our code of conduct and the process for submitting pull requests.
73 |
74 | ## License
75 |
76 | This project is licensed under the [LICENSE_NAME] - see the [LICENSE](mdc:LICENSE) file for details.
77 | ```
78 |
79 | 2. CONTRIBUTING.md contains:
80 | ```markdown
81 | # Contributing Guidelines
82 |
83 | ## Development Setup
84 | [Development environment setup instructions]
85 |
86 | ## Pull Request Process
87 | 1. Update documentation
88 | 2. Update tests
89 | 3. Follow code style
90 | 4. Get reviews
91 |
92 | ## Code Style
93 | [Code style guidelines]
94 |
95 | ## Testing
96 | [Testing requirements and instructions]
97 | ```
98 |
99 | 3. LICENSE file:
100 | - Choose appropriate license (MIT, Apache 2.0, etc.)
101 | - Include current year
102 | - Include copyright holder
103 |
104 | 4. CODE_OF_CONDUCT.md:
105 | - Based on Contributor Covenant
106 | - Include contact information
107 | - Clear enforcement guidelines
108 |
109 | examples:
110 | - input: |
111 | # Bad: Missing required files
112 | my-project/
113 | ├── src/
114 | └── README.md
115 |
116 | # Good: Complete community project setup
117 | my-project/
118 | ├── src/
119 | ├── README.md
120 | ├── CONTRIBUTING.md
121 | ├── LICENSE
122 | └── CODE_OF_CONDUCT.md
123 | output: "Properly configured community project"
124 |
125 | metadata:
126 | priority: high
127 | version: 1.0
128 | tags:
129 | - community
130 | - documentation
131 | - open-source
132 |
133 |
--------------------------------------------------------------------------------
/open-source/conventional-commits.mdc:
--------------------------------------------------------------------------------
1 | ---
2 | description: Automatically commit changes using conventional commits format
3 | globs:
4 | ---
5 | # Conventional Commits Rule
6 |
7 | ## Description
8 | This rule defines the format and structure for commit messages following the Conventional Commits 1.0.0 specification. It ensures consistent, semantic, and machine-readable commit messages.
9 |
10 | ## Rule Type
11 | workflow
12 |
13 | ## Rule Format
14 | ```json
15 | {
16 | "type": "workflow",
17 | "name": "conventional_commits",
18 | "description": "Enforces Conventional Commits 1.0.0 specification",
19 | "filters": [
20 | {
21 | "type": "event",
22 | "pattern": "pre_commit"
23 | }
24 | ],
25 | "steps": [
26 | {
27 | "action": "validate",
28 | "description": "Validate commit message format",
29 | "requirements": [
30 | "Message MUST be prefixed with a type",
31 | "Type MUST be one of: feat, fix, docs, style, refactor, perf, test, build, ci, chore",
32 | "Scope is OPTIONAL and MUST be in parentheses",
33 | "Description MUST immediately follow the colon and space",
34 | "Description MUST use imperative mood ('add' not 'added')",
35 | "Description MUST be less than 100 characters",
36 | "Breaking changes MUST be indicated by '!' or 'BREAKING CHANGE:' footer",
37 | "Body MUST be separated from description by one blank line",
38 | "Footer MUST be separated from body by one blank line"
39 | ]
40 | },
41 | {
42 | "action": "execute",
43 | "description": "Format and create commit",
44 | "script": {
45 | "detect_type": {
46 | "feat": ["add", "create", "implement", "introduce"],
47 | "fix": ["fix", "correct", "resolve", "patch"],
48 | "docs": ["document", "comment", "update.*docs"],
49 | "style": ["style", "format", "lint"],
50 | "refactor": ["refactor", "restructure", "reorganize"],
51 | "perf": ["optimize", "performance", "improve.*speed"],
52 | "test": ["test", "spec", "coverage"],
53 | "build": ["build", "dependency", "package"],
54 | "ci": ["ci", "pipeline", "workflow"],
55 | "chore": ["chore", "misc", "task"]
56 | },
57 | "format_message": {
58 | "template": "${type}${scope}: ${description}\n\n${body}\n\n${footer}",
59 | "variables": {
60 | "type": "Detected from changes or user input",
61 | "scope": "Optional, derived from file paths",
62 | "description": "First line of commit message",
63 | "body": "Detailed explanation of changes",
64 | "footer": "Optional references or breaking changes"
65 | }
66 | },
67 | "command": [
68 | "# Extract type from changes or prompt user",
69 | "TYPE=$(detect_change_type \"$CHANGES\" || prompt_user \"Enter commit type:\")",
70 | "",
71 | "# Extract scope from file paths",
72 | "SCOPE=$(get_common_path \"$CHANGED_FILES\")",
73 | "",
74 | "# Format the commit message",
75 | "printf \"%s\\n\\n%s\\n\\n%s\" \"$TYPE${SCOPE:+($SCOPE)}: $DESCRIPTION\" \"$BODY\" \"$FOOTER\" > \"$COMMIT_MSG_FILE\""
76 | ]
77 | }
78 | }
79 | ]
80 | }
81 | ```
82 |
83 | ## Manual Commit Syntax
84 | When creating commits manually, always use the printf syntax to properly handle newlines and formatting:
85 |
86 | ```bash
87 | printf "type(scope): description\n\nbody of the commit explaining the changes in detail\n\nfooter information" | git commit -F -
88 | ```
89 |
90 | For example:
91 | ```bash
92 | printf "feat(auth): add OAuth2 support\n\nAdd Google and GitHub provider integration\nImplement token refresh handling\nAdd user profile synchronization\n\nCloses #123" | git commit -F -
93 | ```
94 |
95 | This ensures proper formatting and newline handling in the commit message.
96 |
97 | ## Examples
98 |
99 | ### Feature with Scope
100 | ```
101 | feat(auth): implement OAuth2 support
102 |
103 | - Add Google and GitHub provider integration
104 | - Implement token refresh handling
105 | - Add user profile synchronization
106 |
107 | Closes #123
108 | ```
109 |
110 | ### Bug Fix with Breaking Change
111 | ```
112 | fix(api): update user serialization
113 |
114 | - Modify user data structure for better consistency
115 | - Add validation for new fields
116 |
117 | BREAKING CHANGE: user.fullName split into firstName and lastName
118 | ```
119 |
120 | ### Documentation Update
121 | ```
122 | docs(readme): add modern package manager instructions
123 |
124 | - Add yarn and pnpm installation methods
125 | - Update minimum Node.js version requirement
126 | ```
127 |
128 | ### Performance Improvement
129 | ```
130 | perf(core): optimize database queries
131 |
132 | - Add query result caching
133 | - Implement proper indexing
134 | - Reduce unnecessary joins
135 |
136 | Closes #456
137 | ```
138 |
139 | ## Integration
140 | This rule should be used in conjunction with the git-commit-workflow rule to ensure changes are properly reviewed before creating the commit message. The workflow should be:
141 |
142 | 1. Review changes (git-commit-workflow)
143 | 2. Format commit message (conventional-commits)
144 | 3. Validate commit message (conventional-commits)
145 | 4. Commit changes
146 |
--------------------------------------------------------------------------------
/supabase/drizzle-migrations.mdc:
--------------------------------------------------------------------------------
1 | ---
2 | description: Guidelines for generating and managing database migrations using drizzle-kit
3 | globs: ["db/migrations/*.sql"]
4 | alwaysApply: true
5 | ---
6 |
7 | # Drizzle Migration Guidelines
8 |
9 | ## Migration Generation
10 | - **ALWAYS use `npm run generate` to create migrations**
11 | - Never create migration files manually
12 | - This ensures consistent migration file naming and structure
13 | - Drizzle-kit will automatically detect schema changes
14 | - Example: `npm run generate` will execute drizzle-kit generate command
15 |
16 | ## Migration Best Practices
17 | - **Review Generated Migrations**
18 | ```sql
19 | -- ✅ DO: Review and verify generated migrations
20 | ALTER TABLE "customers" ADD COLUMN "status" text DEFAULT 'new_customer';
21 |
22 | -- ❌ DON'T: Manually modify generated migration files
23 | -- Let drizzle-kit handle the migration generation
24 | ```
25 |
26 | - **Version Control**
27 | - Commit migration files along with schema changes
28 | - Never modify committed migrations
29 | - Create new migrations for additional changes
30 |
31 | ## Migration Commands
32 | - `npm run generate` - Generate new migrations
33 | - `npm run migrate` - Apply pending migrations
34 | - `npm run studio` - Open Drizzle Studio for database inspection
35 |
36 | ## Migration Workflow
37 | 1. Make changes to schema files in `db/schema/`
38 | 2. Run `npm run generate` to create migration
39 | 3. Review generated migration file
40 | 4. Run `npm run migrate` to apply changes
41 | 5. Commit both schema and migration files
42 |
43 | ## References
44 | - [Drizzle Kit Documentation](mdc:https:/orm.drizzle.team/kit-docs/overview)
45 | - See also: [supabase-drizzle-bootstrap.mdc](mdc:.cursor/rules/supabase-drizzle-bootstrap.mdc)
46 |
--------------------------------------------------------------------------------
/supabase/drizzle-queries.mdc:
--------------------------------------------------------------------------------
1 | ---
2 | description:
3 | globs:
4 | alwaysApply: false
5 | ---
6 | # Drizzle Query Patterns
7 | Guidelines for writing consistent and secure Drizzle ORM queries with RLS.
8 |
9 | ## Overview
10 | This rule defines patterns for writing Drizzle ORM queries and mutations that respect Row Level Security (RLS) policies.
11 |
12 |
13 | name: drizzle_queries
14 | description: Guidelines for writing Drizzle ORM queries with RLS
15 | filters:
16 | - type: file_extension
17 | pattern: "\\.(ts|js)$"
18 | - type: content
19 | pattern: "drizzle-orm|createDrizzleSupabaseClient"
20 |
21 | actions:
22 | - type: suggest
23 | message: |
24 | When writing Drizzle queries:
25 |
26 | 1. Query Structure:
27 | ```typescript
28 | // ✅ DO: Use simple, direct queries with RLS
29 | export async function getItems() {
30 | const db = await createDrizzleSupabaseClient()
31 | const result = await db.rls(async (tx) => {
32 | return await tx.select().from(items)
33 | })
34 | return result
35 | }
36 |
37 | // ❌ DON'T: Add unnecessary complexity or manual auth checks
38 | export async function getItems() {
39 | const supabase = await createClient() // ❌ Don't use Supabase client directly
40 | const { data: { user } } = await supabase.auth.getUser()
41 | if (!user) throw new Error('Not authenticated')
42 | // ... more unnecessary checks
43 | }
44 | ```
45 |
46 | 2. Mutations:
47 | ```typescript
48 | // ✅ DO: Return the mutated record when possible
49 | export async function createItem(data: NewItem) {
50 | const db = await createDrizzleSupabaseClient()
51 | const result = await db.rls(async (tx) => {
52 | const [item] = await tx.insert(items)
53 | .values(data)
54 | .returning()
55 | return item
56 | })
57 | return result
58 | }
59 |
60 | // ❌ DON'T: Return void or boolean when you can return the record
61 | export async function createItem(data: NewItem) {
62 | const db = await createDrizzleSupabaseClient()
63 | await db.rls(async (tx) => {
64 | await tx.insert(items).values(data)
65 | })
66 | return true // ❌ Less useful than returning the record
67 | }
68 | ```
69 |
70 | 3. Type Safety:
71 | ```typescript
72 | // ✅ DO: Use schema types and type assertions
73 | export async function updateItem(id: string, data: Partial- ) {
74 | const db = await createDrizzleSupabaseClient()
75 | const result = await db.rls(async (tx) => {
76 | const [item] = await tx.update(items)
77 | .set(data)
78 | .where(eq(items.id, id))
79 | .returning()
80 | return item
81 | })
82 | return result
83 | }
84 |
85 | // ❌ DON'T: Use any or unknown types
86 | export async function updateItem(id: string, data: any) {
87 | // ...
88 | }
89 | ```
90 |
91 | 4. Single Record Queries:
92 | ```typescript
93 | // ✅ DO: Use limit(1) and array destructuring
94 | export async function getItemById(id: string) {
95 | const db = await createDrizzleSupabaseClient()
96 | const result = await db.rls(async (tx) => {
97 | const [item] = await tx.select()
98 | .from(items)
99 | .where(eq(items.id, id))
100 | .limit(1)
101 | return item
102 | })
103 | return result
104 | }
105 |
106 | // ❌ DON'T: Return array for single record queries
107 | export async function getItemById(id: string) {
108 | const db = await createDrizzleSupabaseClient()
109 | const result = await db.rls(async (tx) => {
110 | return await tx.select()
111 | .from(items)
112 | .where(eq(items.id, id))
113 | })
114 | return result[0] // ❌ Less explicit than using limit(1)
115 | }
116 | ```
117 |
118 | 5. Error Handling:
119 | ```typescript
120 | // ✅ DO: Let RLS handle authorization
121 | export async function deleteItem(id: string) {
122 | const db = await createDrizzleSupabaseClient()
123 | await db.rls(async (tx) => {
124 | await tx.delete(items)
125 | .where(eq(items.id, id))
126 | })
127 | return true
128 | }
129 |
130 | // ❌ DON'T: Add manual auth checks
131 | export async function deleteItem(id: string) {
132 | const db = await createDrizzleSupabaseClient()
133 | // ❌ Don't check auth manually, RLS handles this
134 | const user = await getCurrentUser()
135 | if (!user.canDelete) throw new Error('Not authorized')
136 | // ...
137 | }
138 | ```
139 |
140 | 6. Query Organization:
141 | - Keep queries in `lib/data/queries` directory
142 | - Keep mutations in `lib/data/mutations` directory
143 | - Name files after the primary table they operate on
144 | - Export functions with clear, action-based names
145 |
146 | 7. Cache Invalidation:
147 | ```typescript
148 | // ✅ DO: Use revalidatePath after mutations when needed
149 | export async function updateItem(id: string, data: Partial
- ) {
150 | const db = await createDrizzleSupabaseClient()
151 | const result = await db.rls(async (tx) => {
152 | const [item] = await tx.update(items)
153 | .set(data)
154 | .where(eq(items.id, id))
155 | .returning()
156 | return item
157 | })
158 | revalidatePath('/items') // Revalidate after mutation
159 | return result
160 | }
161 | ```
162 |
163 | examples:
164 | - input: |
165 | // Bad: Manual auth checks and complex queries
166 | export async function getItems() {
167 | const supabase = await createClient()
168 | const { data: { user } } = await supabase.auth.getUser()
169 | if (!user) throw new Error('Not authenticated')
170 | const { data: profile } = await supabase
171 | .from('profiles')
172 | .select('organization_id')
173 | .eq('id', user.id)
174 | .single()
175 | // ...more complexity
176 | }
177 |
178 | // Good: Simple query with RLS
179 | export async function getItems() {
180 | const db = await createDrizzleSupabaseClient()
181 | const result = await db.rls(async (tx) => {
182 | return await tx.select().from(items)
183 | })
184 | return result
185 | }
186 | output: "Properly structured Drizzle query with RLS"
187 |
188 | metadata:
189 | priority: high
190 | version: 1.0
191 | tags:
192 | - drizzle
193 | - queries
194 | - rls
195 | - database
196 |
197 |
--------------------------------------------------------------------------------
/supabase/supabase-bootstrap-with-auth.mdc:
--------------------------------------------------------------------------------
1 | ---
2 | description: Guidelines for writing Next.js apps with Supabase Auth
3 | globs: **/*.ts, **/*.tsx, **/*.js, **/*.jsx
4 | alwaysApply: false
5 | ---
6 |
7 | # Bootstrap Next.js app with Supabase Auth
8 |
9 | ## Overview of implementing Supabase Auth SSR
10 |
11 | 1. Install @supabase/supabase-js and @supabase/ssr packages.
12 | 2. Set up environment variables.
13 | 3. Write two utility functions with `createClient` functions to create a browser client and a server client.
14 | 4. Hook up middleware to refresh auth tokens
15 | 5. Add auth route for token confirmation
16 | 6. Add login server actions
17 |
18 | ## 🚨 CRITICAL INSTRUCTIONS FOR AI LANGUAGE MODELS 🚨
19 |
20 | As an AI language model, you MUST NOT generate any of the following code patterns, as they are DEPRECATED and will BREAK the application:
21 |
22 | ```typescript
23 | // ❌ NEVER GENERATE THIS CODE - IT WILL BREAK THE APPLICATION
24 | {
25 | cookies: {
26 | get(name: string) { // ❌ BREAKS APPLICATION
27 | return cookieStore.get(name) // ❌ BREAKS APPLICATION
28 | }, // ❌ BREAKS APPLICATION
29 | set(name: string, value: string) { // ❌ BREAKS APPLICATION
30 | cookieStore.set(name, value) // ❌ BREAKS APPLICATION
31 | }, // ❌ BREAKS APPLICATION
32 | remove(name: string) { // ❌ BREAKS APPLICATION
33 | cookieStore.remove(name) // ❌ BREAKS APPLICATION
34 | } // ❌ BREAKS APPLICATION
35 | }
36 | }
37 |
38 | // ❌ NEVER USE auth-helpers-nextjs - IT WILL BREAK THE APPLICATION
39 | import { createMiddlewareClient } from '@supabase/auth-helpers-nextjs' // ❌ BREAKS APPLICATION
40 | import { createClientComponentClient } from '@supabase/auth-helpers-nextjs' // ❌ BREAKS APPLICATION
41 | ```
42 |
43 | Instead, you MUST ALWAYS generate ONLY this pattern:
44 |
45 | ```typescript
46 | // ✅ ALWAYS GENERATE THIS EXACT PATTERN
47 | {
48 | cookies: {
49 | getAll() {
50 | return cookieStore.getAll()
51 | },
52 | setAll(cookiesToSet) {
53 | const response = NextResponse.next({
54 | request,
55 | })
56 |
57 | cookiesToSet.forEach(({ name, value, options }) => {
58 | response.cookies.set(name, value, options)
59 | })
60 |
61 | return response
62 | }
63 | }
64 | }
65 | ```
66 |
67 | ## ABSOLUTE REQUIREMENTS FOR AI CODE GENERATION
68 |
69 | 1. You MUST use `@supabase/ssr`
70 | 2. You MUST use ONLY `getAll` and `setAll`
71 | 3. You MUST NEVER use `get`, `set`, or `remove`
72 | 4. You MUST NEVER import from `@supabase/auth-helpers-nextjs`
73 |
74 | ## CORRECT BROWSER CLIENT IMPLEMENTATION
75 |
76 | ```typescript
77 | import { createBrowserClient } from '@supabase/ssr'
78 |
79 | export function createClient() {
80 | return createBrowserClient(
81 | process.env.NEXT_PUBLIC_SUPABASE_URL!,
82 | process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
83 | )
84 | }
85 | ```
86 |
87 | ## CORRECT SERVER CLIENT IMPLEMENTATION
88 |
89 | ```typescript
90 | import { createServerClient } from '@supabase/ssr'
91 | import { cookies } from 'next/headers'
92 |
93 | export async function createClient() {
94 | const cookieStore = await cookies()
95 |
96 | return createServerClient(
97 | process.env.NEXT_PUBLIC_SUPABASE_URL!,
98 | process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
99 | {
100 | cookies: {
101 | getAll() {
102 | return cookieStore.getAll()
103 | },
104 | setAll(cookiesToSet) {
105 | try {
106 | cookiesToSet.forEach(({ name, value, options }) =>
107 | cookieStore.set(name, value, options)
108 | )
109 | } catch {
110 | // The `setAll` method was called from a Server Component.
111 | // This can be ignored if you have middleware refreshing
112 | // user sessions.
113 | }
114 | },
115 | },
116 | }
117 | )
118 | }
119 | ```
120 |
121 | ## CORRECT MIDDLEWARE IMPLEMENTATION
122 |
123 | ```typescript
124 | import { createServerClient } from '@supabase/ssr'
125 | import { NextResponse, type NextRequest } from 'next/server'
126 |
127 | export async function middleware(request: NextRequest) {
128 | let supabaseResponse = NextResponse.next({
129 | request,
130 | })
131 |
132 | const supabase = createServerClient(
133 | process.env.NEXT_PUBLIC_SUPABASE_URL!,
134 | process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
135 | {
136 | cookies: {
137 | getAll() {
138 | return request.cookies.getAll()
139 | },
140 | setAll(cookiesToSet) {
141 | cookiesToSet.forEach(({ name, value, options }) => request.cookies.set(name, value))
142 | supabaseResponse = NextResponse.next({
143 | request,
144 | })
145 | cookiesToSet.forEach(({ name, value, options }) =>
146 | supabaseResponse.cookies.set(name, value, options)
147 | )
148 | },
149 | },
150 | }
151 | )
152 |
153 | // Do not run code between createServerClient and
154 | // supabase.auth.getUser(). A simple mistake could make it very hard to debug
155 | // issues with users being randomly logged out.
156 |
157 | // IMPORTANT: DO NOT REMOVE auth.getUser()
158 |
159 | const {
160 | data: { user },
161 | } = await supabase.auth.getUser()
162 |
163 | if (
164 | !user &&
165 | !request.nextUrl.pathname.startsWith('/login') &&
166 | !request.nextUrl.pathname.startsWith('/auth')
167 | ) {
168 | // no user, potentially respond by redirecting the user to the login page
169 | const url = request.nextUrl.clone()
170 | url.pathname = '/login'
171 | return NextResponse.redirect(url)
172 | }
173 |
174 | // IMPORTANT: You *must* return the supabaseResponse object as it is.
175 | // If you're creating a new response object with NextResponse.next() make sure to:
176 | // 1. Pass the request in it, like so:
177 | // const myNewResponse = NextResponse.next({ request })
178 | // 2. Copy over the cookies, like so:
179 | // myNewResponse.cookies.setAll(supabaseResponse.cookies.getAll())
180 | // 3. Change the myNewResponse object to fit your needs, but avoid changing
181 | // the cookies!
182 | // 4. Finally:
183 | // return myNewResponse
184 | // If this is not done, you may be causing the browser and server to go out
185 | // of sync and terminate the user's session prematurely!
186 |
187 | return supabaseResponse
188 | }
189 | ```
190 |
191 | ## CORRECT ROOT MIDDLEWARE IMPLEMENTATION
192 | ```typescript
193 | import { type NextRequest } from "next/server"
194 | import { updateSession } from "@/utils/supabase/middleware"
195 |
196 | export async function middleware(request: NextRequest) {
197 | return await updateSession(request)
198 | }
199 |
200 | // Specify which routes should be protected by the middleware
201 | export const config = {
202 | matcher: [
203 | /*
204 | * Match all request paths except:
205 | * - _next/static (static files)
206 | * - _next/image (image optimization files)
207 | * - favicon.ico (favicon file)
208 | * - public folder
209 | * - public files
210 | */
211 | "/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)",
212 | ],
213 | }
214 | ```
215 |
216 | ## AUTH ROUTE FOR TOKEN VERIFICATION to @/app/auth/confirm/route.ts
217 | ```typescript
218 | import { type EmailOtpType } from "@supabase/supabase-js"
219 | import { type NextRequest, NextResponse } from "next/server"
220 |
221 | import { createClient } from "@/utils/supabase/server"
222 |
223 | // Creating a handler to a GET request to route /auth/confirm
224 | export async function GET(request: NextRequest) {
225 | const { searchParams } = new URL(request.url)
226 | const token_hash = searchParams.get("token_hash")
227 | const type = searchParams.get("type") as EmailOtpType | null
228 | const next = "/"
229 |
230 | // Create redirect link without the secret token
231 | const redirectTo = request.nextUrl.clone()
232 | redirectTo.pathname = next
233 | redirectTo.searchParams.delete("token_hash")
234 | redirectTo.searchParams.delete("type")
235 |
236 | if (token_hash && type) {
237 | const supabase = await createClient()
238 |
239 | const { error } = await supabase.auth.verifyOtp({
240 | type,
241 | token_hash,
242 | })
243 | if (!error) {
244 | redirectTo.searchParams.delete("next")
245 | return NextResponse.redirect(redirectTo)
246 | }
247 | }
248 |
249 | // return the user to an error page with some instructions
250 | redirectTo.pathname = "/error"
251 | return NextResponse.redirect(redirectTo)
252 | }
253 | ```
254 |
255 | ## LOGIN SERVER ACTIONS IN @/app/actions/login.ts
256 | ```typescript
257 | "use server"
258 | import { createClient } from "@/utils/supabase/server"
259 | import { redirect } from "next/navigation"
260 |
261 | export async function signIn(formData: FormData) {
262 | const email = formData.get("email") as string
263 | const password = formData.get("password") as string
264 |
265 | const supabase = await createClient()
266 |
267 | const {
268 | error,
269 | data: { user },
270 | } = await supabase.auth.signInWithPassword({
271 | email,
272 | password,
273 | })
274 | console.log("attempting to login", user)
275 | if (error) {
276 | return redirect("/login?error=Invalid credentials")
277 | }
278 | console.log("logged in", user)
279 | const { error: profileError, data } = await supabase
280 | .from("profiles")
281 | .select("*")
282 | .eq("id", user?.id)
283 | console.log("profile", data, profileError)
284 | if (profileError) {
285 | return redirect("/login?error=Could not get profile")
286 | }
287 | console.log("profile", data)
288 | if (data[0].avatar_url === null) {
289 | return redirect("/login/avatar")
290 | }
291 |
292 | return redirect("/")
293 | }
294 |
295 | export async function signUp(formData: FormData) {
296 | const name = formData.get("name") as string
297 | const email = formData.get("email") as string
298 | const password = formData.get("password") as string
299 |
300 | const supabase = await createClient()
301 |
302 | const {
303 | error,
304 | data: { user },
305 | } = await supabase.auth.signUp({
306 | email,
307 | password,
308 | options: {
309 | emailRedirectTo: `${process.env.NEXT_PUBLIC_SITE_URL}/auth/callback`,
310 | },
311 | })
312 |
313 | if (error) {
314 | return redirect("/login?error=Could not sign up")
315 | }
316 |
317 | await supabase
318 | .from("profiles")
319 | .update({
320 | full_name: name,
321 | })
322 | .eq("id", user?.id)
323 |
324 | return redirect("/login?message=Check email to continue sign in process")
325 | }
326 |
327 | export async function signOut() {
328 | const supabase = await createClient()
329 | await supabase.auth.signOut()
330 | return redirect("/login")
331 | }
332 |
333 | ```
334 |
335 | ## AI MODEL VERIFICATION STEPS
336 |
337 | Before generating any code, you MUST verify:
338 |
339 | 1. Are you using ONLY `getAll` and `setAll`? If not, STOP and FIX.
340 | 2. Are you importing from `@supabase/ssr`? If not, STOP and FIX.
341 | 3. Do you see ANY instance of `get`, `set`, or `remove`? If yes, STOP and FIX.
342 | 4. Are you importing from `auth-helpers-nextjs`? If yes, STOP and FIX.
343 | 5. Did you place the `client.ts`, `server.ts` and `middleware.ts` in the location `@/utils/supabase`? If not, STOP and FIX.
344 | 6. Did you place the auth confirmation `route.ts` in the location `@/app/auth/confirm`? If not, STOP and FIX.
345 | 7. Did you place the login server actions `login.ts` in the location `@/app/actions`? If not, STOP and FIX.
346 |
347 | ## CONSEQUENCES OF INCORRECT IMPLEMENTATION
348 |
349 | If you generate code using:
350 | - Individual cookie methods (`get`/`set`/`remove`)
351 | - `auth-helpers-nextjs` package
352 |
353 | The implementation will:
354 | 1. Break in production
355 | 2. Fail to maintain session state
356 | 3. Cause authentication loops
357 | 4. Result in security vulnerabilities
358 |
359 | ## AI MODEL RESPONSE TEMPLATE
360 |
361 | When asked about Supabase Auth SSR implementation, you MUST:
362 | 1. ONLY use code from this guide
363 | 2. NEVER suggest deprecated approaches
364 | 3. ALWAYS use the exact cookie handling shown above
365 | 4. VERIFY your response against the patterns shown here
366 |
367 | Remember: There are NO EXCEPTIONS to these rules.
368 |
--------------------------------------------------------------------------------
/supabase/supabase-create-functions.mdc:
--------------------------------------------------------------------------------
1 | ---
2 | description: Guidelines for writing Supabase database functions
3 | globs: **/*.sql
4 | alwaysApply: false
5 | ---
6 |
7 | # Database: Create functions
8 |
9 | You're a Supabase Postgres expert in writing database functions. Generate **high-quality PostgreSQL functions** that adhere to the following best practices:
10 |
11 | ## General Guidelines
12 |
13 | 1. **Default to `SECURITY INVOKER`:**
14 |
15 | - Functions should run with the permissions of the user invoking the function, ensuring safer access control.
16 | - Use `SECURITY DEFINER` only when explicitly required and explain the rationale.
17 |
18 | 2. **Set the `search_path` Configuration Parameter:**
19 |
20 | - Always set `search_path` to an empty string (`set search_path = '';`).
21 | - This avoids unexpected behavior and security risks caused by resolving object references in untrusted or unintended schemas.
22 | - Use fully qualified names (e.g., `schema_name.table_name`) for all database objects referenced within the function.
23 |
24 | 3. **Adhere to SQL Standards and Validation:**
25 | - Ensure all queries within the function are valid PostgreSQL SQL queries and compatible with the specified context (ie. Supabase).
26 |
27 | ## Best Practices
28 |
29 | 1. **Minimize Side Effects:**
30 |
31 | - Prefer functions that return results over those that modify data unless they serve a specific purpose (e.g., triggers).
32 |
33 | 2. **Use Explicit Typing:**
34 |
35 | - Clearly specify input and output types, avoiding ambiguous or loosely typed parameters.
36 |
37 | 3. **Default to Immutable or Stable Functions:**
38 |
39 | - Where possible, declare functions as `IMMUTABLE` or `STABLE` to allow better optimization by PostgreSQL. Use `VOLATILE` only if the function modifies data or has side effects.
40 |
41 | 4. **Triggers (if Applicable):**
42 | - If the function is used as a trigger, include a valid `CREATE TRIGGER` statement that attaches the function to the desired table and event (e.g., `BEFORE INSERT`).
43 |
44 | ## Example Templates
45 |
46 | ### Simple Function with `SECURITY INVOKER`
47 |
48 | ```sql
49 | create or replace function my_schema.hello_world()
50 | returns text
51 | language plpgsql
52 | security invoker
53 | set search_path = ''
54 | as $$
55 | begin
56 | return 'hello world';
57 | end;
58 | $$;
59 | ```
60 |
61 | ### Function with Parameters and Fully Qualified Object Names
62 |
63 | ```sql
64 | create or replace function public.calculate_total_price(order_id bigint)
65 | returns numeric
66 | language plpgsql
67 | security invoker
68 | set search_path = ''
69 | as $$
70 | declare
71 | total numeric;
72 | begin
73 | select sum(price * quantity)
74 | into total
75 | from public.order_items
76 | where order_id = calculate_total_price.order_id;
77 |
78 | return total;
79 | end;
80 | $$;
81 | ```
82 |
83 | ### Function as a Trigger
84 |
85 | ```sql
86 | create or replace function my_schema.update_updated_at()
87 | returns trigger
88 | language plpgsql
89 | security invoker
90 | set search_path = ''
91 | as $$
92 | begin
93 | -- Update the "updated_at" column on row modification
94 | new.updated_at := now();
95 | return new;
96 | end;
97 | $$;
98 |
99 | create trigger update_updated_at_trigger
100 | before update on my_schema.my_table
101 | for each row
102 | execute function my_schema.update_updated_at();
103 | ```
104 |
105 | ### Function with Error Handling
106 |
107 | ```sql
108 | create or replace function my_schema.safe_divide(numerator numeric, denominator numeric)
109 | returns numeric
110 | language plpgsql
111 | security invoker
112 | set search_path = ''
113 | as $$
114 | begin
115 | if denominator = 0 then
116 | raise exception 'Division by zero is not allowed';
117 | end if;
118 |
119 | return numerator / denominator;
120 | end;
121 | $$;
122 | ```
123 |
124 | ### Immutable Function for Better Optimization
125 |
126 | ```sql
127 | create or replace function my_schema.full_name(first_name text, last_name text)
128 | returns text
129 | language sql
130 | security invoker
131 | set search_path = ''
132 | immutable
133 | as $$
134 | select first_name || ' ' || last_name;
135 | $$;
136 | ```
137 |
--------------------------------------------------------------------------------
/supabase/supabase-create-migration.mdc:
--------------------------------------------------------------------------------
1 | ---
2 | description: Guidelines for writing Postgres migrations
3 | globs: supabase/migrations/**/*.sql
4 | alwaysApply: false
5 | ---
6 |
7 | # Database: Create migration
8 |
9 | You are a Postgres Expert who loves creating secure database schemas.
10 |
11 | This project uses the migrations provided by the Supabase CLI.
12 |
13 | ## Creating a migration file
14 |
15 | Given the context of the user's message, create a database migration file inside the folder `supabase/migrations/`.
16 |
17 | The file MUST following this naming convention:
18 |
19 | The file MUST be named in the format `YYYYMMDDHHmmss_short_description.sql` with proper casing for months, minutes, and seconds in UTC time:
20 |
21 | 1. `YYYY` - Four digits for the year (e.g., `2024`).
22 | 2. `MM` - Two digits for the month (01 to 12).
23 | 3. `DD` - Two digits for the day of the month (01 to 31).
24 | 4. `HH` - Two digits for the hour in 24-hour format (00 to 23).
25 | 5. `mm` - Two digits for the minute (00 to 59).
26 | 6. `ss` - Two digits for the second (00 to 59).
27 | 7. Add an appropriate description for the migration.
28 |
29 | For example:
30 |
31 | ```
32 | 20240906123045_create_profiles.sql
33 | ```
34 |
35 |
36 | ## SQL Guidelines
37 |
38 | Write Postgres-compatible SQL code for Supabase migration files that:
39 |
40 | - Includes a header comment with metadata about the migration, such as the purpose, affected tables/columns, and any special considerations.
41 | - Includes thorough comments explaining the purpose and expected behavior of each migration step.
42 | - Write all SQL in lowercase.
43 | - Add copious comments for any destructive SQL commands, including truncating, dropping, or column alterations.
44 | - When creating a new table, you MUST enable Row Level Security (RLS) even if the table is intended for public access.
45 | - When creating RLS Policies
46 | - Ensure the policies cover all relevant access scenarios (e.g. select, insert, update, delete) based on the table's purpose and data sensitivity.
47 | - If the table is intended for public access the policy can simply return `true`.
48 | - RLS Policies should be granular: one policy for `select`, one for `insert` etc) and for each supabase role (`anon` and `authenticated`). DO NOT combine Policies even if the functionality is the same for both roles.
49 | - Include comments explaining the rationale and intended behavior of each security policy
50 |
51 | The generated SQL code should be production-ready, well-documented, and aligned with Supabase's best practices.
52 |
--------------------------------------------------------------------------------
/supabase/supabase-drizzle-bootstrap.mdc:
--------------------------------------------------------------------------------
1 | ---
2 | description: Guidelines for setting up and using Drizzle ORM with Supabase PostgreSQL
3 | globs: *.ts, *.js
4 | alwaysApply: false
5 | ---
6 | # Bootstrap Drizzle with Supabase
7 |
8 | ## Overview
9 | Guidelines for setting up and using Drizzle ORM with Supabase PostgreSQL.
10 |
11 |
12 | name: supabase_drizzle_bootstrap
13 | description: Guidelines for setting up and using Drizzle ORM with Supabase PostgreSQL
14 | filters:
15 | - type: file_extension
16 | pattern: "\\.(ts|js)$"
17 | - type: content
18 | pattern: "drizzle-orm|@supabase/supabase-js"
19 |
20 | actions:
21 | - type: suggest
22 | message: |
23 | When setting up Drizzle with Supabase:
24 |
25 | 1. Install required dependencies:
26 | ```bash
27 | npm install drizzle-orm pg @types/pg postgres jwt-decode
28 | npm install -D drizzle-kit
29 | ```
30 |
31 | 2. Create a drizzle config file (drizzle.config.ts):
32 | ```typescript
33 | import { config } from 'dotenv';
34 | import { defineConfig } from 'drizzle-kit';
35 |
36 | config({ path: '.env' });
37 |
38 | export default defineConfig({
39 | schema: './db/schema/index.ts',
40 | out: './supabase/migrations',
41 | dialect: 'postgresql',
42 | dbCredentials: {
43 | url: process.env.DATABASE_URL!,
44 | },
45 | });
46 | ```
47 |
48 | 3. Schema files should be organized as:
49 | ```
50 | src/
51 | └── db/
52 | ├── schema/
53 | │ ├── index.ts // exports all schema definitions.
54 | │ ├── auth.ts
55 | │ ├── todos.ts
56 | │ └── ...
57 | ├── drizzle.ts
58 | ├── index.ts
59 | └── jwt.ts
60 | ```
61 |
62 | 4. Example schema structure:
63 | ```typescript
64 | import { eq } from 'drizzle-orm'
65 | import { pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core'
66 | import { authUid, authUsers, authenticatedRole } from 'drizzle-orm/supabase'
67 |
68 | export const todos = pgTable('todos', {
69 | id: uuid('id').defaultRandom().primaryKey(),
70 | title: text('title').notNull(),
71 | completed: boolean('completed').notNull().default(false),
72 | created_at: timestamp('created_at').defaultNow().notNull(),
73 | user_id: uuid('user_id').notNull().references(() => authUsers.id, { onDelete: "cascade" })
74 | }, (table) => [
75 |
76 | // Row Level Security is defined here
77 | pgPolicy("users can insert their own todos", {
78 | for: "insert",
79 | to: authenticatedRole,
80 | withCheck: eq(table.id, authUid)
81 | }),
82 | pgPolicy("users can update their own todos", {
83 | for: "update",
84 | to: authenticatedRole,
85 | using: eq(table.id, authUid),
86 | withCheck: eq(table.id, authUid),
87 | }),
88 | ])
89 | ```
90 |
91 | 5. Database client setup:
92 | ```typescript
93 | import postgres from "postgres"
94 | import { DrizzleConfig } from "drizzle-orm"
95 | import { drizzle } from "drizzle-orm/postgres-js"
96 |
97 | import { createClient } from "@/utils/supabase/server"
98 |
99 | import { createDrizzle } from "./drizzle"
100 | import * as schema from "./schema"
101 | import { decode } from "./jwt"
102 |
103 | const config = {
104 | casing: "snake_case",
105 | schema,
106 | } satisfies DrizzleConfig
107 |
108 | // ByPass RLS
109 | const admin = drizzle({
110 | client: postgres(process.env.SUPABASE_DATABASE_URL!, { prepare: false }),
111 | ...config,
112 | })
113 |
114 | // Protected by RLS
115 | const client = drizzle({
116 | client: postgres(process.env.SUPABASE_DATABASE_URL!, { prepare: false }),
117 | ...config,
118 | })
119 |
120 | // https://github.com/orgs/supabase/discussions/23224
121 | // Should be secure because we use the access token that is signed, and not the data read directly from the storage
122 | export async function createDrizzleSupabaseClient() {
123 | const {
124 | data: { session },
125 | } = await (await createClient()).auth.getSession()
126 | return createDrizzle(decode(session?.access_token ?? ""), { admin, client })
127 | }
128 |
129 | ```
130 |
131 | 6. Add createDrizzle to drizzle.ts
132 | ```typescript
133 | import { sql } from "drizzle-orm"
134 | import { PgDatabase } from "drizzle-orm/pg-core"
135 |
136 | type SupabaseToken = {
137 | iss?: string
138 | sub?: string
139 | aud?: string[] | string
140 | exp?: number
141 | nbf?: number
142 | iat?: number
143 | jti?: string
144 | role?: string
145 | }
146 |
147 | export function createDrizzle,
148 | Token extends SupabaseToken = SupabaseToken>(token: Token, { admin, client }: { admin: Database; client: Database })
149 | {
150 | return {
151 | admin,
152 | rls: (async (transaction, ...rest) => {
153 | return await client.transaction(async (tx) => {
154 | // Supabase exposes auth.uid() and auth.jwt()
155 | // https://supabase.com/docs/guides/database/postgres/row-level-security#helper-functions
156 | try {
157 | await tx.execute(sql`
158 | -- auth.jwt()
159 | select set_config('request.jwt.claims', '${sql.raw(
160 | JSON.stringify(token)
161 | )}', TRUE);
162 | -- auth.uid()
163 | select set_config('request.jwt.claim.sub', '${sql.raw(
164 | token.sub ?? ""
165 | )}', TRUE);
166 | -- set local role
167 | set local role ${sql.raw(token.role ?? "anon")};
168 | `)
169 | return await transaction(tx)
170 | } finally {
171 | await tx.execute(sql`
172 | -- reset
173 | select set_config('request.jwt.claims', NULL, TRUE);
174 | select set_config('request.jwt.claim.sub', NULL, TRUE);
175 | reset role;
176 | `)
177 | }
178 | }, ...rest)
179 | }) as typeof client.transaction,
180 | }
181 | }
182 | ```
183 |
184 | 7. Add jwt decode to jwt.ts:
185 | ```typescript
186 | import { jwtDecode, JwtPayload } from "jwt-decode"
187 |
188 | export function decode(accessToken: string) {
189 | try {
190 | return jwtDecode(accessToken)
191 | } catch (error) {
192 | console.error(error)
193 | return { role: "anon" } as JwtPayload & { role: string }
194 | }
195 | }
196 | ```
197 | 8. Add migration scripts to package.json:
198 | ```json
199 | {
200 | "scripts": {
201 | "generate": "drizzle-kit generate:pg",
202 | "migrate": "drizzle-kit push:pg"
203 | }
204 | }
205 | ```
206 |
207 |
208 | 8. Best practices:
209 | - Always use TypeScript for type safety
210 | - Define explicit table relationships
211 | - Use migrations for schema changes
212 | - Enable RLS for all tables
213 | - Use UUIDs for primary keys
214 | - Include created_at/updated_at timestamps
215 | - Add user_id foreign keys for RLS
216 |
217 | examples:
218 | - input: |
219 | // Bad: No type safety
220 | const todos = pgTable('todos', {
221 | id: serial('id'),
222 | title: text('title')
223 | })
224 |
225 | // Good: Type-safe with proper structure
226 | const todos = pgTable('todos', {
227 | id: uuid('id').defaultRandom().primaryKey(),
228 | title: text('title').notNull(),
229 | user_id: uuid('user_id').notNull(),
230 | created_at: timestamp('created_at').defaultNow().notNull()
231 | })
232 | output: "Properly structured Drizzle schema with types and RLS support"
233 |
234 | metadata:
235 | priority: high
236 | version: 1.0
237 | tags:
238 | - drizzle
239 | - supabase
240 | - database
241 | - orm
242 |
243 |
--------------------------------------------------------------------------------
/supabase/supabase-postgres-style-guide.mdc:
--------------------------------------------------------------------------------
1 | ---
2 | description: Guidelines for writing Postgres SQL
3 | globs: **/*.sql
4 | alwaysApply: false
5 | ---
6 |
7 |
8 | # Postgres SQL Style Guide
9 |
10 | ## General
11 |
12 | - Use lowercase for SQL reserved words to maintain consistency and readability.
13 | - Employ consistent, descriptive identifiers for tables, columns, and other database objects.
14 | - Use white space and indentation to enhance the readability of your code.
15 | - Store dates in ISO 8601 format (`yyyy-mm-ddThh:mm:ss.sssss`).
16 | - Include comments for complex logic, using '/* ... */' for block comments and '--' for line comments.
17 |
18 | ## Naming Conventions
19 |
20 | - Avoid SQL reserved words and ensure names are unique and under 63 characters.
21 | - Use snake_case for tables and columns.
22 | - Prefer plurals for table names
23 | - Prefer singular names for columns.
24 |
25 | ## Tables
26 |
27 | - Avoid prefixes like 'tbl_' and ensure no table name matches any of its column names.
28 | - Always add an `id` column of type `identity generated always` unless otherwise specified.
29 | - Create all tables in the `public` schema unless otherwise specified.
30 | - Always add the schema to SQL queries for clarity.
31 | - Always add a comment to describe what the table does. The comment can be up to 1024 characters.
32 |
33 | ## Columns
34 |
35 | - Use singular names and avoid generic names like 'id'.
36 | - For references to foreign tables, use the singular of the table name with the `_id` suffix. For example `user_id` to reference the `users` table
37 | - Always use lowercase except in cases involving acronyms or when readability would be enhanced by an exception.
38 |
39 | #### Examples:
40 |
41 | ```sql
42 | create table books (
43 | id bigint generated always as identity primary key,
44 | title text not null,
45 | author_id bigint references authors (id)
46 | );
47 | comment on table books is 'A list of all the books in the library.';
48 | ```
49 |
50 |
51 | ## Queries
52 |
53 | - When the query is shorter keep it on just a few lines. As it gets larger start adding newlines for readability
54 | - Add spaces for readability.
55 |
56 | Smaller queries:
57 |
58 |
59 | ```sql
60 | select *
61 | from employees
62 | where end_date is null;
63 |
64 | update employees
65 | set end_date = '2023-12-31'
66 | where employee_id = 1001;
67 | ```
68 |
69 | Larger queries:
70 |
71 | ```sql
72 | select
73 | first_name,
74 | last_name
75 | from
76 | employees
77 | where
78 | start_date between '2021-01-01' and '2021-12-31'
79 | and
80 | status = 'employed';
81 | ```
82 |
83 |
84 | ### Joins and Subqueries
85 |
86 | - Format joins and subqueries for clarity, aligning them with related SQL clauses.
87 | - Prefer full table names when referencing tables. This helps for readability.
88 |
89 | ```sql
90 | select
91 | employees.employee_name,
92 | departments.department_name
93 | from
94 | employees
95 | join
96 | departments on employees.department_id = departments.department_id
97 | where
98 | employees.start_date > '2022-01-01';
99 | ```
100 |
101 | ## Aliases
102 |
103 | - Use meaningful aliases that reflect the data or transformation applied, and always include the 'as' keyword for clarity.
104 |
105 | ```sql
106 | select count(*) as total_employees
107 | from employees
108 | where end_date is null;
109 | ```
110 |
111 |
112 | ## Complex queries and CTEs
113 |
114 | - If a query is extremely complex, prefer a CTE.
115 | - Make sure the CTE is clear and linear. Prefer readability over performance.
116 | - Add comments to each block.
117 |
118 | ```sql
119 | with department_employees as (
120 | -- Get all employees and their departments
121 | select
122 | employees.department_id,
123 | employees.first_name,
124 | employees.last_name,
125 | departments.department_name
126 | from
127 | employees
128 | join
129 | departments on employees.department_id = departments.department_id
130 | ),
131 | employee_counts as (
132 | -- Count how many employees in each department
133 | select
134 | department_name,
135 | count(*) as num_employees
136 | from
137 | department_employees
138 | group by
139 | department_name
140 | )
141 | select
142 | department_name,
143 | num_employees
144 | from
145 | employee_counts
146 | order by
147 | department_name;
148 | ```
149 |
--------------------------------------------------------------------------------
/supabase/supabase-rls-policies.mdc:
--------------------------------------------------------------------------------
1 | ---
2 | description: Guidelines for writing Postgres Row Level Security policies
3 | globs: **/*.sql
4 | alwaysApply: false
5 | ---
6 | # Database: Create RLS policies
7 |
8 | You're a Supabase Postgres expert in writing row level security policies. Your purpose is to generate a policy with the constraints given by the user. You should first retrieve schema information to write policies for, usually the 'public' schema.
9 |
10 | The output should use the following instructions:
11 |
12 | - The generated SQL must be valid SQL.
13 | - You can use only CREATE POLICY or ALTER POLICY queries, no other queries are allowed.
14 | - Always use double apostrophe in SQL strings (eg. 'Night''s watch')
15 | - You can add short explanations to your messages.
16 | - The result should be a valid markdown. The SQL code should be wrapped in ``` (including sql language tag).
17 | - Always use "auth.uid()" instead of "current_user".
18 | - SELECT policies should always have USING but not WITH CHECK
19 | - INSERT policies should always have WITH CHECK but not USING
20 | - UPDATE policies should always have WITH CHECK and most often have USING
21 | - DELETE policies should always have USING but not WITH CHECK
22 | - Don't use `FOR ALL`. Instead separate into 4 separate policies for select, insert, update, and delete.
23 | - The policy name should be short but detailed text explaining the policy, enclosed in double quotes.
24 | - Always put explanations as separate text. Never use inline SQL comments.
25 | - If the user asks for something that's not related to SQL policies, explain to the user
26 | that you can only help with policies.
27 | - Discourage `RESTRICTIVE` policies and encourage `PERMISSIVE` policies, and explain why.
28 |
29 | The output should look like this:
30 |
31 | ```sql
32 | CREATE POLICY "My descriptive policy." ON books FOR INSERT to authenticated USING ( (select auth.uid()) = author_id ) WITH ( true );
33 | ```
34 |
35 | Since you are running in a Supabase environment, take note of these Supabase-specific additions below.
36 |
37 | ## Authenticated and unauthenticated roles
38 |
39 | Supabase maps every request to one of the roles:
40 |
41 | - `anon`: an unauthenticated request (the user is not logged in)
42 | - `authenticated`: an authenticated request (the user is logged in)
43 |
44 | These are actually [Postgres Roles](mdc:docs/guides/database/postgres/roles). You can use these roles within your Policies using the `TO` clause:
45 |
46 | ```sql
47 | create policy "Profiles are viewable by everyone"
48 | on profiles
49 | for select
50 | to authenticated, anon
51 | using ( true );
52 |
53 | -- OR
54 |
55 | create policy "Public profiles are viewable only by authenticated users"
56 | on profiles
57 | for select
58 | to authenticated
59 | using ( true );
60 | ```
61 |
62 | Note that `for ...` must be added after the table but before the roles. `to ...` must be added after `for ...`:
63 |
64 | ### Incorrect
65 |
66 | ```sql
67 | create policy "Public profiles are viewable only by authenticated users"
68 | on profiles
69 | to authenticated
70 | for select
71 | using ( true );
72 | ```
73 |
74 | ### Correct
75 |
76 | ```sql
77 | create policy "Public profiles are viewable only by authenticated users"
78 | on profiles
79 | for select
80 | to authenticated
81 | using ( true );
82 | ```
83 |
84 | ## Multiple operations
85 |
86 | PostgreSQL policies do not support specifying multiple operations in a single FOR clause. You need to create separate policies for each operation.
87 |
88 | ### Incorrect
89 |
90 | ```sql
91 | create policy "Profiles can be created and deleted by any user"
92 | on profiles
93 | for insert, delete -- cannot create a policy on multiple operators
94 | to authenticated
95 | with check ( true )
96 | using ( true );
97 | ```
98 |
99 | ### Correct
100 |
101 | ```sql
102 | create policy "Profiles can be created by any user"
103 | on profiles
104 | for insert
105 | to authenticated
106 | with check ( true );
107 |
108 | create policy "Profiles can be deleted by any user"
109 | on profiles
110 | for delete
111 | to authenticated
112 | using ( true );
113 | ```
114 |
115 | ## Helper functions
116 |
117 | Supabase provides some helper functions that make it easier to write Policies.
118 |
119 | ### `auth.uid()`
120 |
121 | Returns the ID of the user making the request.
122 |
123 | ### `auth.jwt()`
124 |
125 | Returns the JWT of the user making the request. Anything that you store in the user's `raw_app_meta_data` column or the `raw_user_meta_data` column will be accessible using this function. It's important to know the distinction between these two:
126 |
127 | - `raw_user_meta_data` - can be updated by the authenticated user using the `supabase.auth.update()` function. It is not a good place to store authorization data.
128 | - `raw_app_meta_data` - cannot be updated by the user, so it's a good place to store authorization data.
129 |
130 | The `auth.jwt()` function is extremely versatile. For example, if you store some team data inside `app_metadata`, you can use it to determine whether a particular user belongs to a team. For example, if this was an array of IDs:
131 |
132 | ```sql
133 | create policy "User is in team"
134 | on my_table
135 | to authenticated
136 | using ( team_id in (select auth.jwt() -> 'app_metadata' -> 'teams'));
137 | ```
138 |
139 | ### MFA
140 |
141 | The `auth.jwt()` function can be used to check for [Multi-Factor Authentication](mdc:docs/guides/auth/auth-mfa#enforce-rules-for-mfa-logins). For example, you could restrict a user from updating their profile unless they have at least 2 levels of authentication (Assurance Level 2):
142 |
143 | ```sql
144 | create policy "Restrict updates."
145 | on profiles
146 | as restrictive
147 | for update
148 | to authenticated using (
149 | (select auth.jwt()->>'aal') = 'aal2'
150 | );
151 | ```
152 |
153 | ## RLS performance recommendations
154 |
155 | Every authorization system has an impact on performance. While row level security is powerful, the performance impact is important to keep in mind. This is especially true for queries that scan every row in a table - like many `select` operations, including those using limit, offset, and ordering.
156 |
157 | Based on a series of [tests](mdc:https:/github.com/GaryAustin1/RLS-Performance), we have a few recommendations for RLS:
158 |
159 | ### Add indexes
160 |
161 | Make sure you've added [indexes](mdc:docs/guides/database/postgres/indexes) on any columns used within the Policies which are not already indexed (or primary keys). For a Policy like this:
162 |
163 | ```sql
164 | create policy "Users can access their own records" on test_table
165 | to authenticated
166 | using ( (select auth.uid()) = user_id );
167 | ```
168 |
169 | You can add an index like:
170 |
171 | ```sql
172 | create index userid
173 | on test_table
174 | using btree (user_id);
175 | ```
176 |
177 | ### Call functions with `select`
178 |
179 | You can use `select` statement to improve policies that use functions. For example, instead of this:
180 |
181 | ```sql
182 | create policy "Users can access their own records" on test_table
183 | to authenticated
184 | using ( auth.uid() = user_id );
185 | ```
186 |
187 | You can do:
188 |
189 | ```sql
190 | create policy "Users can access their own records" on test_table
191 | to authenticated
192 | using ( (select auth.uid()) = user_id );
193 | ```
194 |
195 | This method works well for JWT functions like `auth.uid()` and `auth.jwt()` as well as `security definer` Functions. Wrapping the function causes an `initPlan` to be run by the Postgres optimizer, which allows it to "cache" the results per-statement, rather than calling the function on each row.
196 |
197 | Caution: You can only use this technique if the results of the query or function do not change based on the row data.
198 |
199 | ### Minimize joins
200 |
201 | You can often rewrite your Policies to avoid joins between the source and the target table. Instead, try to organize your policy to fetch all the relevant data from the target table into an array or set, then you can use an `IN` or `ANY` operation in your filter.
202 |
203 | For example, this is an example of a slow policy which joins the source `test_table` to the target `team_user`:
204 |
205 | ```sql
206 | create policy "Users can access records belonging to their teams" on test_table
207 | to authenticated
208 | using (
209 | (select auth.uid()) in (
210 | select user_id
211 | from team_user
212 | where team_user.team_id = team_id -- joins to the source "test_table.team_id"
213 | )
214 | );
215 | ```
216 |
217 | We can rewrite this to avoid this join, and instead select the filter criteria into a set:
218 |
219 | ```sql
220 | create policy "Users can access records belonging to their teams" on test_table
221 | to authenticated
222 | using (
223 | team_id in (
224 | select team_id
225 | from team_user
226 | where user_id = (select auth.uid()) -- no join
227 | )
228 | );
229 | ```
230 |
231 | ### Specify roles in your policies
232 |
233 | Always use the Role of inside your policies, specified by the `TO` operator. For example, instead of this query:
234 |
235 | ```sql
236 | create policy "Users can access their own records" on rls_test
237 | using ( auth.uid() = user_id );
238 | ```
239 |
240 | Use:
241 |
242 | ```sql
243 | create policy "Users can access their own records" on rls_test
244 | to authenticated
245 | using ( (select auth.uid()) = user_id );
246 | ```
247 |
248 | This prevents the policy `( (select auth.uid()) = user_id )` from running for any `anon` users, since the execution stops at the `to authenticated` step.
249 |
--------------------------------------------------------------------------------
/supabase/supabase-writing-edge-functions.mdc:
--------------------------------------------------------------------------------
1 | ---
2 | description: Coding rules for Supabase Edge Functions
3 | globs: supabase/functions/**/*.ts
4 | alwaysApply: false
5 | ---
6 | # Writing Supabase Edge Functions
7 |
8 | You're an expert in writing TypeScript and Deno JavaScript runtime. Generate **high-quality Supabase Edge Functions** that adhere to the following best practices:
9 |
10 | ## Guidelines
11 |
12 | 1. Try to use Web APIs and Deno’s core APIs instead of external dependencies (eg: use fetch instead of Axios, use WebSockets API instead of node-ws)
13 | 2. If you are reusing utility methods between Edge Functions, add them to `supabase/functions/_shared` and import using a relative path. Do NOT have cross dependencies between Edge Functions.
14 | 3. Do NOT use bare specifiers when importing dependecnies. If you need to use an external dependency, make sure it's prefixed with either `npm:` or `jsr:`. For example, `@supabase/supabase-js` should be written as `npm:@supabase/supabase-js`.
15 | 4. For external imports, always define a version. For example, `npm:@express` should be written as `npm:express@4.18.2`.
16 | 5. For external dependencies, importing via `npm:` and `jsr:` is preferred. Minimize the use of imports from @`deno.land/x` , `esm.sh` and @`unpkg.com` . If you have a package from one of those CDNs, you can replace the CDN hostname with `npm:` specifier.
17 | 6. You can also use Node built-in APIs. You will need to import them using `node:` specifier. For example, to import Node process: `import process from "node:process". Use Node APIs when you find gaps in Deno APIs.
18 | 7. Do NOT use `import { serve } from "https://deno.land/std@0.168.0/http/server.ts"`. Instead use the built-in `Deno.serve`.
19 | 8. Following environment variables (ie. secrets) are pre-populated in both local and hosted Supabase environments. Users don't need to manually set them:
20 | * SUPABASE_URL
21 | * SUPABASE_ANON_KEY
22 | * SUPABASE_SERVICE_ROLE_KEY
23 | * SUPABASE_DB_URL
24 | 9. To set other environment variables (ie. secrets) users can put them in a env file and run the `supabase secrets set --env-file path/to/env-file`
25 | 10. A single Edge Function can handle multiple routes. It is recommended to use a library like Express or Hono to handle the routes as it's easier for developer to understand and maintain. Each route must be prefixed with `/function-name` so they are routed correctly.
26 | 11. File write operations are ONLY permitted on `/tmp` directory. You can use either Deno or Node File APIs.
27 | 12. Use `EdgeRuntime.waitUntil(promise)` static method to run long-running tasks in the background without blocking response to a request. Do NOT assume it is available in the request / execution context.
28 |
29 | ## Example Templates
30 |
31 | ### Simple Hello World Function
32 |
33 | ```tsx
34 | interface reqPayload {
35 | name: string;
36 | }
37 |
38 | console.info('server started');
39 |
40 | Deno.serve(async (req: Request) => {
41 | const { name }: reqPayload = await req.json();
42 | const data = {
43 | message: `Hello ${name} from foo!`,
44 | };
45 |
46 | return new Response(
47 | JSON.stringify(data),
48 | { headers: { 'Content-Type': 'application/json', 'Connection': 'keep-alive' }}
49 | );
50 | });
51 |
52 | ```
53 |
54 | ### Example Function using Node built-in API
55 |
56 | ```tsx
57 | import { randomBytes } from "node:crypto";
58 | import { createServer } from "node:http";
59 | import process from "node:process";
60 |
61 | const generateRandomString = (length) => {
62 | const buffer = randomBytes(length);
63 | return buffer.toString('hex');
64 | };
65 |
66 | const randomString = generateRandomString(10);
67 | console.log(randomString);
68 |
69 | const server = createServer((req, res) => {
70 | const message = `Hello`;
71 | res.end(message);
72 | });
73 |
74 | server.listen(9999);
75 | ```
76 |
77 | ### Using npm packages in Functions
78 |
79 | ```tsx
80 | import express from "npm:express@4.18.2";
81 |
82 | const app = express();
83 |
84 | app.get(/(.*)/, (req, res) => {
85 | res.send("Welcome to Supabase");
86 | });
87 |
88 | app.listen(8000);
89 |
90 | ```
91 |
92 | ### Generate embeddings using built-in @Supabase.ai API
93 |
94 | ```tsx
95 | const model = new Supabase.ai.Session('gte-small');
96 |
97 | Deno.serve(async (req: Request) => {
98 | const params = new URL(req.url).searchParams;
99 | const input = params.get('text');
100 | const output = await model.run(input, { mean_pool: true, normalize: true });
101 | return new Response(
102 | JSON.stringify(
103 | output,
104 | ),
105 | {
106 | headers: {
107 | 'Content-Type': 'application/json',
108 | 'Connection': 'keep-alive',
109 | },
110 | },
111 | );
112 | });
113 |
114 | ```
115 |
--------------------------------------------------------------------------------
/task-master/cursor_rules.mdc:
--------------------------------------------------------------------------------
1 | ---
2 | description: Guidelines for creating and maintaining Cursor rules to ensure consistency and effectiveness.
3 | globs: .cursor/rules/*.mdc
4 | alwaysApply: true
5 | ---
6 |
7 | - **Required Rule Structure:**
8 | ```markdown
9 | ---
10 | description: Clear, one-line description of what the rule enforces
11 | globs: path/to/files/*.ext, other/path/**/*
12 | alwaysApply: boolean
13 | ---
14 |
15 | - **Main Points in Bold**
16 | - Sub-points with details
17 | - Examples and explanations
18 | ```
19 |
20 | - **File References:**
21 | - Use `[filename](mdc:path/to/file)` ([filename](mdc:filename)) to reference files
22 | - Example: [prisma.mdc](mdc:.cursor/rules/prisma.mdc) for rule references
23 | - Example: [schema.prisma](mdc:prisma/schema.prisma) for code references
24 |
25 | - **Code Examples:**
26 | - Use language-specific code blocks
27 | ```typescript
28 | // ✅ DO: Show good examples
29 | const goodExample = true;
30 |
31 | // ❌ DON'T: Show anti-patterns
32 | const badExample = false;
33 | ```
34 |
35 | - **Rule Content Guidelines:**
36 | - Start with high-level overview
37 | - Include specific, actionable requirements
38 | - Show examples of correct implementation
39 | - Reference existing code when possible
40 | - Keep rules DRY by referencing other rules
41 |
42 | - **Rule Maintenance:**
43 | - Update rules when new patterns emerge
44 | - Add examples from actual codebase
45 | - Remove outdated patterns
46 | - Cross-reference related rules
47 |
48 | - **Best Practices:**
49 | - Use bullet points for clarity
50 | - Keep descriptions concise
51 | - Include both DO and DON'T examples
52 | - Reference actual code over theoretical examples
53 | - Use consistent formatting across rules
--------------------------------------------------------------------------------
/task-master/dev_workflow.mdc:
--------------------------------------------------------------------------------
1 | ---
2 | description: Guide for using meta-development script (scripts/dev.js) to manage task-driven development workflows
3 | globs: **/*
4 | alwaysApply: true
5 | ---
6 |
7 | - **Global CLI Commands**
8 | - Task Master now provides a global CLI through the `task-master` command
9 | - All functionality from `scripts/dev.js` is available through this interface
10 | - Install globally with `npm install -g claude-task-master` or use locally via `npx`
11 | - Use `task-master ` instead of `node scripts/dev.js `
12 | - Examples:
13 | - `task-master list` instead of `node scripts/dev.js list`
14 | - `task-master next` instead of `node scripts/dev.js next`
15 | - `task-master expand --id=3` instead of `node scripts/dev.js expand --id=3`
16 | - All commands accept the same options as their script equivalents
17 | - The CLI provides additional commands like `task-master init` for project setup
18 |
19 | - **Development Workflow Process**
20 | - Start new projects by running `task-master init` or `node scripts/dev.js parse-prd --input=` to generate initial tasks.json
21 | - Begin coding sessions with `task-master list` to see current tasks, status, and IDs
22 | - Analyze task complexity with `task-master analyze-complexity --research` before breaking down tasks
23 | - Select tasks based on dependencies (all marked 'done'), priority level, and ID order
24 | - Clarify tasks by checking task files in tasks/ directory or asking for user input
25 | - View specific task details using `task-master show ` to understand implementation requirements
26 | - Break down complex tasks using `task-master expand --id=` with appropriate flags
27 | - Clear existing subtasks if needed using `task-master clear-subtasks --id=` before regenerating
28 | - Implement code following task details, dependencies, and project standards
29 | - Verify tasks according to test strategies before marking as complete
30 | - Mark completed tasks with `task-master set-status --id= --status=done`
31 | - Update dependent tasks when implementation differs from original plan
32 | - Generate task files with `task-master generate` after updating tasks.json
33 | - Maintain valid dependency structure with `task-master fix-dependencies` when needed
34 | - Respect dependency chains and task priorities when selecting work
35 | - Report progress regularly using the list command
36 |
37 | - **Task Complexity Analysis**
38 | - Run `node scripts/dev.js analyze-complexity --research` for comprehensive analysis
39 | - Review complexity report in scripts/task-complexity-report.json
40 | - Or use `node scripts/dev.js complexity-report` for a formatted, readable version of the report
41 | - Focus on tasks with highest complexity scores (8-10) for detailed breakdown
42 | - Use analysis results to determine appropriate subtask allocation
43 | - Note that reports are automatically used by the expand command
44 |
45 | - **Task Breakdown Process**
46 | - For tasks with complexity analysis, use `node scripts/dev.js expand --id=`
47 | - Otherwise use `node scripts/dev.js expand --id= --subtasks=`
48 | - Add `--research` flag to leverage Perplexity AI for research-backed expansion
49 | - Use `--prompt=""` to provide additional context when needed
50 | - Review and adjust generated subtasks as necessary
51 | - Use `--all` flag to expand multiple pending tasks at once
52 | - If subtasks need regeneration, clear them first with `clear-subtasks` command
53 |
54 | - **Implementation Drift Handling**
55 | - When implementation differs significantly from planned approach
56 | - When future tasks need modification due to current implementation choices
57 | - When new dependencies or requirements emerge
58 | - Call `node scripts/dev.js update --from= --prompt=""` to update tasks.json
59 |
60 | - **Task Status Management**
61 | - Use 'pending' for tasks ready to be worked on
62 | - Use 'done' for completed and verified tasks
63 | - Use 'deferred' for postponed tasks
64 | - Add custom status values as needed for project-specific workflows
65 |
66 | - **Task File Format Reference**
67 | ```
68 | # Task ID:
69 | # Title:
70 | # Status:
71 | # Dependencies:
72 | # Priority:
73 | # Description:
74 | # Details:
75 |
76 |
77 | # Test Strategy:
78 |
79 | ```
80 |
81 | - **Command Reference: parse-prd**
82 | - Legacy Syntax: `node scripts/dev.js parse-prd --input=`
83 | - CLI Syntax: `task-master parse-prd --input=`
84 | - Description: Parses a PRD document and generates a tasks.json file with structured tasks
85 | - Parameters:
86 | - `--input=`: Path to the PRD text file (default: sample-prd.txt)
87 | - Example: `task-master parse-prd --input=requirements.txt`
88 | - Notes: Will overwrite existing tasks.json file. Use with caution.
89 |
90 | - **Command Reference: update**
91 | - Legacy Syntax: `node scripts/dev.js update --from= --prompt=""`
92 | - CLI Syntax: `task-master update --from= --prompt=""`
93 | - Description: Updates tasks with ID >= specified ID based on the provided prompt
94 | - Parameters:
95 | - `--from=`: Task ID from which to start updating (required)
96 | - `--prompt=""`: Explanation of changes or new context (required)
97 | - Example: `task-master update --from=4 --prompt="Now we are using Express instead of Fastify."`
98 | - Notes: Only updates tasks not marked as 'done'. Completed tasks remain unchanged.
99 |
100 | - **Command Reference: generate**
101 | - Legacy Syntax: `node scripts/dev.js generate`
102 | - CLI Syntax: `task-master generate`
103 | - Description: Generates individual task files in tasks/ directory based on tasks.json
104 | - Parameters:
105 | - `--file=, -f`: Use alternative tasks.json file (default: 'tasks/tasks.json')
106 | - `--output=, -o`: Output directory (default: 'tasks')
107 | - Example: `task-master generate`
108 | - Notes: Overwrites existing task files. Creates tasks/ directory if needed.
109 |
110 | - **Command Reference: set-status**
111 | - Legacy Syntax: `node scripts/dev.js set-status --id= --status=`
112 | - CLI Syntax: `task-master set-status --id= --status=`
113 | - Description: Updates the status of a specific task in tasks.json
114 | - Parameters:
115 | - `--id=`: ID of the task to update (required)
116 | - `--status=`: New status value (required)
117 | - Example: `task-master set-status --id=3 --status=done`
118 | - Notes: Common values are 'done', 'pending', and 'deferred', but any string is accepted.
119 |
120 | - **Command Reference: list**
121 | - Legacy Syntax: `node scripts/dev.js list`
122 | - CLI Syntax: `task-master list`
123 | - Description: Lists all tasks in tasks.json with IDs, titles, and status
124 | - Parameters:
125 | - `--status=, -s`: Filter by status
126 | - `--with-subtasks`: Show subtasks for each task
127 | - `--file=, -f`: Use alternative tasks.json file (default: 'tasks/tasks.json')
128 | - Example: `task-master list`
129 | - Notes: Provides quick overview of project progress. Use at start of sessions.
130 |
131 | - **Command Reference: expand**
132 | - Legacy Syntax: `node scripts/dev.js expand --id= [--num=] [--research] [--prompt=""]`
133 | - CLI Syntax: `task-master expand --id= [--num=] [--research] [--prompt=""]`
134 | - Description: Expands a task with subtasks for detailed implementation
135 | - Parameters:
136 | - `--id=`: ID of task to expand (required unless using --all)
137 | - `--all`: Expand all pending tasks, prioritized by complexity
138 | - `--num=`: Number of subtasks to generate (default: from complexity report)
139 | - `--research`: Use Perplexity AI for research-backed generation
140 | - `--prompt=""`: Additional context for subtask generation
141 | - `--force`: Regenerate subtasks even for tasks that already have them
142 | - Example: `task-master expand --id=3 --num=5 --research --prompt="Focus on security aspects"`
143 | - Notes: Uses complexity report recommendations if available.
144 |
145 | - **Command Reference: analyze-complexity**
146 | - Legacy Syntax: `node scripts/dev.js analyze-complexity [options]`
147 | - CLI Syntax: `task-master analyze-complexity [options]`
148 | - Description: Analyzes task complexity and generates expansion recommendations
149 | - Parameters:
150 | - `--output=, -o`: Output file path (default: scripts/task-complexity-report.json)
151 | - `--model=, -m`: Override LLM model to use
152 | - `--threshold=, -t`: Minimum score for expansion recommendation (default: 5)
153 | - `--file=, -f`: Use alternative tasks.json file
154 | - `--research, -r`: Use Perplexity AI for research-backed analysis
155 | - Example: `task-master analyze-complexity --research`
156 | - Notes: Report includes complexity scores, recommended subtasks, and tailored prompts.
157 |
158 | - **Command Reference: clear-subtasks**
159 | - Legacy Syntax: `node scripts/dev.js clear-subtasks --id=`
160 | - CLI Syntax: `task-master clear-subtasks --id=`
161 | - Description: Removes subtasks from specified tasks to allow regeneration
162 | - Parameters:
163 | - `--id=`: ID or comma-separated IDs of tasks to clear subtasks from
164 | - `--all`: Clear subtasks from all tasks
165 | - Examples:
166 | - `task-master clear-subtasks --id=3`
167 | - `task-master clear-subtasks --id=1,2,3`
168 | - `task-master clear-subtasks --all`
169 | - Notes:
170 | - Task files are automatically regenerated after clearing subtasks
171 | - Can be combined with expand command to immediately generate new subtasks
172 | - Works with both parent tasks and individual subtasks
173 |
174 | - **Task Structure Fields**
175 | - **id**: Unique identifier for the task (Example: `1`)
176 | - **title**: Brief, descriptive title (Example: `"Initialize Repo"`)
177 | - **description**: Concise summary of what the task involves (Example: `"Create a new repository, set up initial structure."`)
178 | - **status**: Current state of the task (Example: `"pending"`, `"done"`, `"deferred"`)
179 | - **dependencies**: IDs of prerequisite tasks (Example: `[1, 2]`)
180 | - Dependencies are displayed with status indicators (✅ for completed, ⏱️ for pending)
181 | - This helps quickly identify which prerequisite tasks are blocking work
182 | - **priority**: Importance level (Example: `"high"`, `"medium"`, `"low"`)
183 | - **details**: In-depth implementation instructions (Example: `"Use GitHub client ID/secret, handle callback, set session token."`)
184 | - **testStrategy**: Verification approach (Example: `"Deploy and call endpoint to confirm 'Hello World' response."`)
185 | - **subtasks**: List of smaller, more specific tasks (Example: `[{"id": 1, "title": "Configure OAuth", ...}]`)
186 |
187 | - **Environment Variables Configuration**
188 | - **ANTHROPIC_API_KEY** (Required): Your Anthropic API key for Claude (Example: `ANTHROPIC_API_KEY=sk-ant-api03-...`)
189 | - **MODEL** (Default: `"claude-3-7-sonnet-20250219"`): Claude model to use (Example: `MODEL=claude-3-opus-20240229`)
190 | - **MAX_TOKENS** (Default: `"4000"`): Maximum tokens for responses (Example: `MAX_TOKENS=8000`)
191 | - **TEMPERATURE** (Default: `"0.7"`): Temperature for model responses (Example: `TEMPERATURE=0.5`)
192 | - **DEBUG** (Default: `"false"`): Enable debug logging (Example: `DEBUG=true`)
193 | - **LOG_LEVEL** (Default: `"info"`): Console output level (Example: `LOG_LEVEL=debug`)
194 | - **DEFAULT_SUBTASKS** (Default: `"3"`): Default subtask count (Example: `DEFAULT_SUBTASKS=5`)
195 | - **DEFAULT_PRIORITY** (Default: `"medium"`): Default priority (Example: `DEFAULT_PRIORITY=high`)
196 | - **PROJECT_NAME** (Default: `"MCP SaaS MVP"`): Project name in metadata (Example: `PROJECT_NAME=My Awesome Project`)
197 | - **PROJECT_VERSION** (Default: `"1.0.0"`): Version in metadata (Example: `PROJECT_VERSION=2.1.0`)
198 | - **PERPLEXITY_API_KEY**: For research-backed features (Example: `PERPLEXITY_API_KEY=pplx-...`)
199 | - **PERPLEXITY_MODEL** (Default: `"sonar-medium-online"`): Perplexity model (Example: `PERPLEXITY_MODEL=sonar-large-online`)
200 |
201 | - **Determining the Next Task**
202 | - Run `task-master next` to show the next task to work on
203 | - The next command identifies tasks with all dependencies satisfied
204 | - Tasks are prioritized by priority level, dependency count, and ID
205 | - The command shows comprehensive task information including:
206 | - Basic task details and description
207 | - Implementation details
208 | - Subtasks (if they exist)
209 | - Contextual suggested actions
210 | - Recommended before starting any new development work
211 | - Respects your project's dependency structure
212 | - Ensures tasks are completed in the appropriate sequence
213 | - Provides ready-to-use commands for common task actions
214 |
215 | - **Viewing Specific Task Details**
216 | - Run `task-master show ` or `task-master show --id=` to view a specific task
217 | - Use dot notation for subtasks: `task-master show 1.2` (shows subtask 2 of task 1)
218 | - Displays comprehensive information similar to the next command, but for a specific task
219 | - For parent tasks, shows all subtasks and their current status
220 | - For subtasks, shows parent task information and relationship
221 | - Provides contextual suggested actions appropriate for the specific task
222 | - Useful for examining task details before implementation or checking status
223 |
224 | - **Managing Task Dependencies**
225 | - Use `task-master add-dependency --id= --depends-on=` to add a dependency
226 | - Use `task-master remove-dependency --id= --depends-on=` to remove a dependency
227 | - The system prevents circular dependencies and duplicate dependency entries
228 | - Dependencies are checked for existence before being added or removed
229 | - Task files are automatically regenerated after dependency changes
230 | - Dependencies are visualized with status indicators in task listings and files
231 |
232 | - **Command Reference: add-dependency**
233 | - Legacy Syntax: `node scripts/dev.js add-dependency --id= --depends-on=`
234 | - CLI Syntax: `task-master add-dependency --id= --depends-on=`
235 | - Description: Adds a dependency relationship between two tasks
236 | - Parameters:
237 | - `--id=`: ID of task that will depend on another task (required)
238 | - `--depends-on=`: ID of task that will become a dependency (required)
239 | - Example: `task-master add-dependency --id=22 --depends-on=21`
240 | - Notes: Prevents circular dependencies and duplicates; updates task files automatically
241 |
242 | - **Command Reference: remove-dependency**
243 | - Legacy Syntax: `node scripts/dev.js remove-dependency --id= --depends-on=`
244 | - CLI Syntax: `task-master remove-dependency --id= --depends-on=`
245 | - Description: Removes a dependency relationship between two tasks
246 | - Parameters:
247 | - `--id=`: ID of task to remove dependency from (required)
248 | - `--depends-on=`: ID of task to remove as a dependency (required)
249 | - Example: `task-master remove-dependency --id=22 --depends-on=21`
250 | - Notes: Checks if dependency actually exists; updates task files automatically
251 |
252 | - **Command Reference: validate-dependencies**
253 | - Legacy Syntax: `node scripts/dev.js validate-dependencies [options]`
254 | - CLI Syntax: `task-master validate-dependencies [options]`
255 | - Description: Checks for and identifies invalid dependencies in tasks.json and task files
256 | - Parameters:
257 | - `--file=, -f`: Use alternative tasks.json file (default: 'tasks/tasks.json')
258 | - Example: `task-master validate-dependencies`
259 | - Notes:
260 | - Reports all non-existent dependencies and self-dependencies without modifying files
261 | - Provides detailed statistics on task dependency state
262 | - Use before fix-dependencies to audit your task structure
263 |
264 | - **Command Reference: fix-dependencies**
265 | - Legacy Syntax: `node scripts/dev.js fix-dependencies [options]`
266 | - CLI Syntax: `task-master fix-dependencies [options]`
267 | - Description: Finds and fixes all invalid dependencies in tasks.json and task files
268 | - Parameters:
269 | - `--file=, -f`: Use alternative tasks.json file (default: 'tasks/tasks.json')
270 | - Example: `task-master fix-dependencies`
271 | - Notes:
272 | - Removes references to non-existent tasks and subtasks
273 | - Eliminates self-dependencies (tasks depending on themselves)
274 | - Regenerates task files with corrected dependencies
275 | - Provides detailed report of all fixes made
276 |
277 | - **Command Reference: complexity-report**
278 | - Legacy Syntax: `node scripts/dev.js complexity-report [options]`
279 | - CLI Syntax: `task-master complexity-report [options]`
280 | - Description: Displays the task complexity analysis report in a formatted, easy-to-read way
281 | - Parameters:
282 | - `--file=, -f`: Path to the complexity report file (default: 'scripts/task-complexity-report.json')
283 | - Example: `task-master complexity-report`
284 | - Notes:
285 | - Shows tasks organized by complexity score with recommended actions
286 | - Provides complexity distribution statistics
287 | - Displays ready-to-use expansion commands for complex tasks
288 | - If no report exists, offers to generate one interactively
289 |
290 | - **Command Reference: add-task**
291 | - CLI Syntax: `task-master add-task [options]`
292 | - Description: Add a new task to tasks.json using AI
293 | - Parameters:
294 | - `--file=, -f`: Path to the tasks file (default: 'tasks/tasks.json')
295 | - `--prompt=, -p`: Description of the task to add (required)
296 | - `--dependencies=, -d`: Comma-separated list of task IDs this task depends on
297 | - `--priority=`: Task priority (high, medium, low) (default: 'medium')
298 | - Example: `task-master add-task --prompt="Create user authentication using Auth0"`
299 | - Notes: Uses AI to convert description into structured task with appropriate details
300 |
301 | - **Command Reference: init**
302 | - CLI Syntax: `task-master init`
303 | - Description: Initialize a new project with Task Master structure
304 | - Parameters: None
305 | - Example: `task-master init`
306 | - Notes:
307 | - Creates initial project structure with required files
308 | - Prompts for project settings if not provided
309 | - Merges with existing files when appropriate
310 | - Can be used to bootstrap a new Task Master project quickly
311 |
312 | - **Code Analysis & Refactoring Techniques**
313 | - **Top-Level Function Search**
314 | - Use grep pattern matching to find all exported functions across the codebase
315 | - Command: `grep -E "export (function|const) \w+|function \w+\(|const \w+ = \(|module\.exports" --include="*.js" -r ./`
316 | - Benefits:
317 | - Quickly identify all public API functions without reading implementation details
318 | - Compare functions between files during refactoring (e.g., monolithic to modular structure)
319 | - Verify all expected functions exist in refactored modules
320 | - Identify duplicate functionality or naming conflicts
321 | - Usage examples:
322 | - When migrating from `scripts/dev.js` to modular structure: `grep -E "function \w+\(" scripts/dev.js`
323 | - Check function exports in a directory: `grep -E "export (function|const)" scripts/modules/`
324 | - Find potential naming conflicts: `grep -E "function (get|set|create|update)\w+\(" -r ./`
325 | - Variations:
326 | - Add `-n` flag to include line numbers
327 | - Add `--include="*.ts"` to filter by file extension
328 | - Use with `| sort` to alphabetize results
329 | - Integration with refactoring workflow:
330 | - Start by mapping all functions in the source file
331 | - Create target module files based on function grouping
332 | - Verify all functions were properly migrated
333 | - Check for any unintentional duplications or omissions
334 |
--------------------------------------------------------------------------------
/task-master/self_improve.mdc:
--------------------------------------------------------------------------------
1 | ---
2 | description: Guidelines for continuously improving Cursor rules based on emerging code patterns and best practices.
3 | globs: **/*
4 | alwaysApply: true
5 | ---
6 |
7 | - **Rule Improvement Triggers:**
8 | - New code patterns not covered by existing rules
9 | - Repeated similar implementations across files
10 | - Common error patterns that could be prevented
11 | - New libraries or tools being used consistently
12 | - Emerging best practices in the codebase
13 |
14 | - **Analysis Process:**
15 | - Compare new code with existing rules
16 | - Identify patterns that should be standardized
17 | - Look for references to external documentation
18 | - Check for consistent error handling patterns
19 | - Monitor test patterns and coverage
20 |
21 | - **Rule Updates:**
22 | - **Add New Rules When:**
23 | - A new technology/pattern is used in 3+ files
24 | - Common bugs could be prevented by a rule
25 | - Code reviews repeatedly mention the same feedback
26 | - New security or performance patterns emerge
27 |
28 | - **Modify Existing Rules When:**
29 | - Better examples exist in the codebase
30 | - Additional edge cases are discovered
31 | - Related rules have been updated
32 | - Implementation details have changed
33 |
34 | - **Example Pattern Recognition:**
35 | ```typescript
36 | // If you see repeated patterns like:
37 | const data = await prisma.user.findMany({
38 | select: { id: true, email: true },
39 | where: { status: 'ACTIVE' }
40 | });
41 |
42 | // Consider adding to [prisma.mdc](mdc:.cursor/rules/prisma.mdc):
43 | // - Standard select fields
44 | // - Common where conditions
45 | // - Performance optimization patterns
46 | ```
47 |
48 | - **Rule Quality Checks:**
49 | - Rules should be actionable and specific
50 | - Examples should come from actual code
51 | - References should be up to date
52 | - Patterns should be consistently enforced
53 |
54 | - **Continuous Improvement:**
55 | - Monitor code review comments
56 | - Track common development questions
57 | - Update rules after major refactors
58 | - Add links to relevant documentation
59 | - Cross-reference related rules
60 |
61 | - **Rule Deprecation:**
62 | - Mark outdated patterns as deprecated
63 | - Remove rules that no longer apply
64 | - Update references to deprecated rules
65 | - Document migration paths for old patterns
66 |
67 | - **Documentation Updates:**
68 | - Keep examples synchronized with code
69 | - Update references to external docs
70 | - Maintain links between related rules
71 | - Document breaking changes
72 |
73 | Follow [cursor_rules.mdc](mdc:.cursor/rules/cursor_rules.mdc) for proper rule formatting and structure.
--------------------------------------------------------------------------------