agentleFS
dotnetfactorydotnetfactory/fluid-calendar/.cursor/rules/main-rule.mdc

fluid-calendar / rules

Cursor rule996 starsChanged 4 months agoMITView on GitHub

send this with every request so the AI knows what to do

  • Reads credentials

We split this main-rule.mdc into the rules it gives an agent

63 rules. About 0 are common, 36 are distinctive, and 27 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈36

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 27

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    when adding an external calendar like google or outlook, we still need to sync the data in our database so we are always working with our …

    line 13
  2. Very specific:

    use shadcn whenever possible, the correct command to use is npx shadcn@latest add

    line 15
  3. Distinctive:

    no need to touch files after making changes

    line 17
  4. Very specific:

    don't use .gitignore to ignore saas-only source files, since the code is synced between the projects, instead update the sync-repos.sh …

    line 18
  5. Distinctive:

    if there are changes to the rules or setup, update the main-rule.mdc file accordingly

    line 19
  6. Distinctive:

    if you add methods or code that need implementation add a //todo comment explaining what it needs to do so we can implement it later

    line 20
  7. Distinctive:

    when generating react content make sure to replace quotes and apostrohpes with &apos.

    line 21
  8. Distinctive:

    when adding new features, consider if they should be in the saas version or the open source version or both and if you are not sure, ask to …

    line 23
  9. Very specific:

    when adding new features, consider if they should be in the cmdk commands, if so ask me to confirm then add them to src/lib/commands or …

    line 24
  10. Distinctive:

    use bullmq for backgound jobs and queue management.

    line 25
  11. Very specific:

    All SAAS-specific code is in the src/saas/ directory, which is excluded from the open source repository via .gitignore

    line 35
  12. Very specific:

    all pages for saas are in the src/app/(saas) folder and all common pages are in the src/app/(common) folder and open source in …

    line 38
  13. Very specific:

    Use the isSaasEnabled and isFeatureEnabled() functions from src/lib/config.ts to conditionally enable SAAS features

    line 47
  14. Very specific:

    Use route groups to organize pages: (saas), (open), and (common)

    line 51
  15. Very specific:

    Place SAAS-specific pages in src/app/(saas)/ and open source pages in src/app/(open)/

    line 52
  16. Very specific:

    Create separate files with .saas.tsx and .open.tsx extensions in the same directory

    line 55
  17. Distinctive:

    Use dynamic imports with template literals to select the correct file based on the environment variable

    line 56
  18. Very specific:

    Use the useAdmin hook to check if the user is an admin

    line 63
  19. Very specific:

    Use the AdminOnly wrapper component from @/components/auth/AdminOnly

    line 73
  20. Very specific:

    Use the requireAdmin middleware from @/lib/auth/api-auth

    line 95
  21. Very specific:

    Do NOT use getServerSession and check the role manually

    line 108
  22. Very specific:

    Use the scripts/sync-repos.sh script to sync changes from the private SAAS repository to the public open source repository

    line 112
  23. Distinctive:

    When implementing new features, consider whether they should be:

    line 115
  24. Very specific:

    Place reusable hooks in src/hooks

    line 125
  25. Very specific:

    Keep page components in src/app

    line 128
  26. Distinctive:

    Use Zustand for global state

    line 147
  27. Very specific:

    Keep state logic in src/store directory

    line 148
  28. Distinctive:

    Follow atomic state pattern (small, focused stores)

    line 149
  29. Distinctive:

    Use local state for component-specific data

    line 150
  30. Distinctive:

    Use Tailwind CSS for styling

    line 153
  31. Very specific:

    Keep custom CSS in globals.css minimal

    line 155
  32. Distinctive:

    Use CSS variables for theming

    line 156
  33. Distinctive:

    Always define proper interfaces and types

    line 160
  34. Distinctive:

    Use strict type checking

    line 161
  35. Distinctive:

    Keep types in separate files when reused

    line 163
  36. Distinctive:

    Use generics when appropriate

    line 164
  37. Distinctive:

    Use React.memo for expensive renders

    line 192
  38. Distinctive:

    Use code splitting where appropriate

    line 195
  39. Distinctive:

    Use consistent error messages

    line 199
  40. Distinctive:

    Never commit sensitive data

    line 204
  41. Very specific:

    Use .env.example for reference

    line 205
  42. Distinctive:

    Use proper naming convention

    line 207
  43. Distinctive:

    Use postgres with Prisma for data persistence

    line 215
  44. Very specific:

    Keep database file in /prisma directory

    line 216
  45. Distinctive:

    Follow schema-first development approach

    line 217
  46. Distinctive:

    Use migrations for database changes

    line 218
  47. Distinctive:

    Use meaningful table names

    line 223
  48. Distinctive:

    Follow consistent naming conventions

    line 224
  49. Distinctive:

    Use appropriate field types

    line 226
  50. Distinctive:

    Use Prisma Client for all database operations

    line 231
  51. Very specific:

    Keep database logic in /src/lib/db directory

    line 233
  52. Distinctive:

    Use transactions where appropriate

    line 234
  53. Very specific:

    ALWAYS use the global Prisma instance from @/lib/prisma

    line 238
  54. Very specific:

    NEVER create new PrismaClient instances with new PrismaClient()

    line 239
  55. Very specific:

    Import Prisma types from @prisma/client but client instance from @/lib/prisma

    line 240
  56. Distinctive:

    When creating a route, use this method:

    line 256
  57. Distinctive:

    when you create a method, add documentation to explain what it does and update it if is changed.

    line 266
  58. Distinctive:

    do not remove //todo comments in the code.

    line 267
  59. Distinctive:

    if you delete/change a method or a file, make sure to refactor any usages of it.

    line 268
  60. Distinctive:

    when we are discussing a new change and i tell you to start implementing then: start by creating a list of todos in TODO.md on top once we …

    line 270
  61. Very specific:

    use @date-utils.ts for all date functions including new Date instead of directly using date-fns or date-fns-tz

    line 272
  62. Very specific:

    use @calendar-db.ts for all db calls related to calendars

    line 273
  63. Very specific:

    all logging should use the logger class defined in /lib/logger/index.js not console.log, the logger is used by importing it and also …

    line 274

≈ “Common” is an estimate: at least 1 in 5 of the 6,350 Cursor rule files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
main-rule.mdc
---
description: send this with every request so the AI knows what to do
globs: 
alwaysApply: true
---
send this with every request so the AI knows what to do.

- this app will be a clone of the Motion app for calendar and task management
- user can add a google,outlook or caldav calendars, by clicking add calendar, get the  auth screen, authorizes the app full access to the calendar
- we will be using postgres
- this app is built with nextjs, tailwind, prisma, postgres, shadcn, zod, zustand
- it uses fullcalendar package
- when adding an external calendar like google or outlook, we still need to sync the data in our database so we are always working with our local data
- the google/outlook/caldav auth needs to handle refreshing tokens so when the token expires an hour later, we can get a new one and continue syncing.
- use shadcn whenever possible, the correct command to use is `npx shadcn@latest add`
- make minimal changes and don't change or break existing logic and only apply the changes requested.
- no need to touch files after making changes
- don't use .gitignore to ignore saas-only source files, since the code is synced between the projects, instead update the sync-repos.sh script to exclude files that should not be in the open source version
- if there are changes to the rules or setup, update the main-rule.mdc file accordingly
- if you add methods or code that need implementation add a //todo comment explaining what it needs to do so we can implement it later
- when generating react content make sure to replace quotes and apostrohpes with ' and "
- as you make changes update a CHANGELOG.md file with the changes under the [unreleased] section, so we can keep track for release notes
- when adding new features, consider if they should be in the saas version or the open source version or both and if you are not sure, ask to confirm
- when adding new features, consider if they should be in the cmdk commands, if so ask me to confirm then add them to src/lib/commands or @useCommands.ts
- use bullmq for backgound jobs and queue management.  all jobs are in the saas/jobs folder


## SAAS vs Open Source

This project is available in two versions:
1. **Open Source Version**: Free, self-hosted version with core functionality
2. **SAAS Version**: Hosted service with premium features

### Code Organization:
- All SAAS-specific code is in the `src/saas/` directory, which is excluded from the open source repository via `.gitignore`
- The open source repository is at https://github.com/dotnetfactory/fluid-calendar
- The private SAAS repository contains both the open source code and the SAAS-specific code
- all pages for saas are in the `src/app/(saas)` folder and all common pages are in the `src/app/(common)` folder and open source in `src/app/(open)`
- we should still add a .saas extension and .open extension to files in (saas) and (open) folders to avoid compiling them

### File Extension Convention:
- Files with `.saas.tsx`/`.saas.ts` extension are only included in the SAAS build
- Files with `.open.tsx`/`.open.ts` extension are only included in the open source build
- Regular files (without special extensions) are included in both builds

### Feature Flags:
- Use the `isSaasEnabled` and `isFeatureEnabled()` functions from `src/lib/config.ts` to conditionally enable SAAS features
- SAAS features are controlled by the `NEXT_PUBLIC_ENABLE_SAAS_FEATURES` environment variable

### Component Loading:
- Use route groups to organize pages: `(saas)`, `(open)`, and `(common)`
- Place SAAS-specific pages in `src/app/(saas)/` and open source pages in `src/app/(open)/`
- Common pages that work in both versions go in `src/app/(common)/`
- For shared components with different implementations:
  - Create separate files with `.saas.tsx` and `.open.tsx` extensions in the same directory
  - Use dynamic imports with template literals to select the correct file based on the environment variable
  - Example: `dynamic(() => import(./path/component${process.env.NEXT_PUBLIC_ENABLE_SAAS_FEATURES === "true" ? ".saas" : ".open"}))`
  - See `src/app/(common)/settings/page.tsx` for an example of this pattern

### Admin Access Control:
- Admin-only features should be secured using the `useAdmin` hook or the `AdminOnly` component
- For pages in the settings section:
  - Use the `useAdmin` hook to check if the user is an admin
  - Show an access denied message using the `AccessDeniedMessage` component
  - Example: 
    ```tsx
    const { isAdmin } = useAdmin();
    if (!isAdmin) {
      return <AccessDeniedMessage message="Custom access denied message" />;
    }
    ```
- For components:
  - Use the `AdminOnly` wrapper component from `@/components/auth/AdminOnly`
  - Provide a fallback component to show for non-admin users
  - Example:
    ```tsx
    <AdminOnly fallback={<AccessDeniedMessage message="Custom access denied message" />}>
      {/* Admin-only content */}
    </AdminOnly>
    ```
- For more complex access denied messages, create a custom component that uses the layout appropriate for that section
- In the settings page, use the `isSaasEnabled` constant to conditionally include admin-only tabs:
  ```tsx
  if (isAdmin) {
    const adminTabs = [/* ... */];
    
    if (isSaasEnabled) {
      return [...baseTabs, ...adminTabs, { id: "saas-feature", label: "SAAS Feature" }];
    }
    
    return [...baseTabs, ...adminTabs];
  }
  ```
- For API routes that should only be accessible by admins:
  - Use the `requireAdmin` middleware from `@/lib/auth/api-auth`
  - Example:
    ```typescript
    import { requireAdmin } from "@/lib/auth/api-auth";
    
    export async function GET(request: NextRequest) {
      // Check if user is admin
      const authResponse = await requireAdmin(request);
      if (authResponse) return authResponse;
      
      // Continue with admin-only logic
    }
    ```
  - Do NOT use `getServerSession` and check the role manually
  - The `requireAdmin` middleware handles all the authentication and authorization checks

### Repository Syncing:
- Use the `scripts/sync-repos.sh` script to sync changes from the private SAAS repository to the public open source repository
- The script preserves the `.gitignore` file in the public repository to prevent SAAS code from being published

When implementing new features, consider whether they should be:
1. Core features available in both versions
2. Premium features exclusive to the SAAS version
3. Core features with premium enhancements in the SAAS version 

if you are not sure if this is a saas or opensource feature, then ask to confirm

# Cursor Development Rules and Guidelines

## Project Structure
- Place reusable hooks in `src/hooks`
- Store types and interfaces in `src/types`
- Maintain utilities in `src/lib`
- Keep page components in `src/app`

## Component Organization
1. Components should be organized in feature folders:
```
src/components/
  calendar/
    CalendarGrid.tsx
    TimeSlot.tsx
    WeekView.tsx
  tasks/
    TaskCard.tsx
    TaskList.tsx
  ui/
    Button.tsx
    Modal.tsx
```

## State Management
- Use Zustand for global state
- Keep state logic in `src/store` directory
- Follow atomic state pattern (small, focused stores)
- Use local state for component-specific data

## Styling Guidelines
- Use Tailwind CSS for styling
- Follow mobile-first approach
- Keep custom CSS in `globals.css` minimal
- Use CSS variables for theming
- Maintain consistent spacing and color schemes

## TypeScript Best Practices
- Always define proper interfaces and types
- Use strict type checking
- Avoid `any` type
- Keep types in separate files when reused
- Use generics when appropriate

## Code Organization (within files)
1. Imports order:
   - React and Next.js imports
   - Third-party libraries
   - Local components
   - Types and interfaces
   - Utilities and hooks

2. Component structure:
   ```typescript
   // Types/Interfaces
   interface Props {
     // ...
   }

   // Component
   export function ComponentName({ prop1, prop2 }: Props) {
     // Hooks
     // State
     // Effects
     // Helper functions
     // Render
   }
   ```

## Performance Considerations
- Use React.memo for expensive renders
- Implement proper loading states
- Optimize images and assets
- Use code splitting where appropriate

## Error Handling
- Implement proper error boundaries
- Use consistent error messages
- Log errors appropriately
- Provide user-friendly error states

## Environment Variables
- Never commit sensitive data
- Use `.env.example` for reference
- Document required variables
- Use proper naming convention


## Common Commands

For `npm install` make sure to include the --legacy-peer-deps flag

## Database Strategy
- Use postgres with Prisma for data persistence
- Keep database file in `/prisma` directory
- Follow schema-first development approach
- Use migrations for database changes


### Database Guidelines
1. Schema Design
   - Use meaningful table names
   - Follow consistent naming conventions
   - Include timestamps (createdAt, updatedAt)
   - Use appropriate field types
   - Document relationships
   - Add proper indexes

2. Data Access
   - Use Prisma Client for all database operations
   - Implement repository pattern
   - Keep database logic in `/src/lib/db` directory
   - Use transactions where appropriate
   - Handle errors gracefully

3. Database Connection Management
   - ALWAYS use the global Prisma instance from `@/lib/prisma`
   - NEVER create new PrismaClient instances with `new PrismaClient()`
   - Import Prisma types from `@prisma/client` but client instance from `@/lib/prisma`
   - Example:
     ```typescript
     // ❌ Don't do this:
     import { PrismaClient } from "@prisma/client";
     const prisma = new PrismaClient();

     // ✅ Do this instead:
     import { Task, Project } from "@prisma/client"; // For types only
     import { prisma } from "@/lib/prisma"; // For database access
     ```

# Conventions

Using Nextjs 15 with app router.

When creating a route, use this method:
```typescript
export async function GET(
  request: Request,
  { params }: { params: Promise<{ id: string }> }
) {
  try {
    const { id } = await params;
```

- when you create a method, add documentation to explain what it does and update it if is changed.
- do not remove //todo comments in the code.
- if you delete/change a method or a file, make sure to refactor any usages of it.
- for docker compose use `docker compose` not `docker-compose`
- when we are discussing a new change and i tell you to start implementing then: start by creating a list of todos in TODO.md on top once we agree on a plan and update the list as you implement stuff.
- for icons use react-icons
- use @date-utils.ts for all date functions including new Date instead of directly using date-fns or date-fns-tz
- use @calendar-db.ts for all db calls related to calendars
- all logging should use the logger class defined in /lib/logger/index.js not console.log, the logger is used by importing it and also defining a source:
```
import { logger } from "@/lib/logger";
const LOG_SOURCE = "OutlookCalendar";
```
here is an example for logging an error:
```
logger.error(
  "Failed to refresh token",
  {
    error: error instanceof Error ? error.message : "Unknown error",
  },
  LOG_SOURCE
);
```



Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.