chore(dev): cursor rules for react+typescript, django+python, rust (#29116)

This commit is contained in:
Dylan Martin
2025-02-25 16:15:24 -05:00
committed by GitHub
parent 611a5c34ea
commit 7f51a1d7e5
4 changed files with 242 additions and 0 deletions

View File

@@ -0,0 +1,102 @@
---
description: Rules for writing Python with Django (most PostHog backend code)
globs: ee/*.py, posthog/*.py
---
You are an expert in Python, Django, and scalable web application development.
Key Principles
- Write clear, technical responses with precise Django examples.
- Use Django's built-in features and tools wherever possible to leverage its full capabilities.
- Prioritize readability and maintainability; follow Django's coding style guide (PEP 8 compliance for the most part, with the one exception being 120 characters per line instead of 79).
- Use descriptive variable and function names; adhere to naming conventions (e.g., lowercase with underscores for functions and variables).
Django/Python
- Use Django REST Framework viewsets for API endpoints.
- Leverage Djangos ORM for database interactions; avoid raw SQL queries unless necessary for performance.
- Use Djangos built-in user model and authentication framework for user management.
- Follow the MVT (Model-View-Template) pattern strictly for clear separation of concerns.
- Use middleware judiciously to handle cross-cutting concerns like authentication, logging, and caching.
Error Handling and Validation
- Implement error handling at the view level and use Django's built-in error handling mechanisms.
- Prefer try-except blocks for handling exceptions in business logic and views.
- Customize error pages (e.g., 404, 500) to improve user experience and provide helpful information.
- Use Django signals to decouple error handling and logging from core business logic.
Dependencies
- Django
- Django REST Framework (for API development)
- Celery (for background tasks)
- Redis (for caching and task queues)
- PostgreSQL (preferred databases for production)
Django-Specific Guidelines
- Use Django templates for rendering HTML and DRF serializers for JSON responses.
- Keep business logic in models and forms; keep views light and focused on request handling.
- Use Django's URL dispatcher (urls.py) to define clear and RESTful URL patterns.
- Apply Django's security best practices (e.g., CSRF protection, SQL injection protection, XSS prevention).
- Use Djangos built-in tools for testing (unittest and pytest-django) to ensure code quality and reliability.
- Leverage Djangos caching framework to optimize performance for frequently accessed data.
- Use Djangos middleware for common tasks such as authentication, logging, and security.
Performance Optimization
- Optimize query performance using Django ORM's select_related and prefetch_related for related object fetching.
- Use Djangos cache framework with backend support (e.g., Redis or Memcached) to reduce database load.
- Implement database indexing and query optimization techniques for better performance.
- Use asynchronous views and background tasks (via Celery) for I/O-bound or long-running operations.
- Optimize static file handling with Djangos static file management system (e.g., WhiteNoise or CDN integration).
Logging
- As a general rule, we should have logs for every expected and unexpected actions of the application, using the appropriate log level.
- We should also be logging these exceptions to Sentry with the Sentry Python SDK. Python exceptions should almost always be captured automatically without extra instrumentation, but custom ones (such as failed requests to external services, query errors, or Celery task failures) can be tracked using capture_exception().
Log Levels
- A log level or log severity is a piece of information telling how important a given log message is:
- DEBUG: should be used for information that may be needed for diagnosing issues and troubleshooting or when running application in the test environment for the purpose of making sure everything is running correctly
- INFO: should be used as standard log level, indicating that something happened
- WARN: should be used when something unexpected happened but the code can continue the work
- ERROR: should be used when the application hits an issue preventing one or more functionalities from properly functioning
Logging Format
- django-structlog is the default logging library we use (see docs). It's a structured logging framework that adds cohesive metadata on each logs that makes it easier to track events or incidents.
- Structured logging means that you dont write hard-to-parse and hard-to-keep-consistent prose in your logs but that you log events that happen in a context instead.
(example)
```python
import structlog
logger = structlog.get_logger(__name__)
logger.debug("event_sent_to_kafka", event_uuid=str(event_uuid), kafka_topic=topic)
```
will produce:
```sh
2021-10-28T13:46:40.099007Z [debug] event_sent_to_kafka [posthog.api.capture] event_uuid=017cc727-1662-0000-630c-d35f6a29bae3 kafka_topic=default
As you can see above, the log contains all the information needed to understand the app behaviour.
```
Security
- Dont log sensitive information. Make sure you never log:
- authorization tokens
- passwords
- financial data
- health data
- PII (Personal Identifiable Information)
Testing
- All new packages and most new significant functionality should come with unit tests
- Significant features should come with integration and/or end-to-end tests
- Analytics-related queries should be covered by snapshot tests for ease of reviewing
Unit tests
- A good unit test should:
- focus on a single use-case at a time
- have a minimal set of assertions per test
- demonstrate every use case. The rule of thumb is: if it can happen, it should be covered
Integration tests
- Integration tests should ensure that the feature works end-to-end. They must cover all the important use cases of the feature.
Refer to Django documentation for best practices in views, models, forms, and security considerations.

View File

@@ -0,0 +1,50 @@
---
description: Rules for writing frontend code at PostHog (mostly React + Typescript with Kea)
globs: frontend/*.tsx, frontend/*.ts
---
You are an expert in TypeScript, React, Kea, Tailwind, and UX design.
Architecture
- Two-layer system: Kea (data/state) -> React (view/template)
- Always implement data layer in Kea logic; avoid React state
Code Style and Structure
- Write TypeScript with proper typing for all new code
- Use functional programming patterns; avoid classes
- Prefer iteration and modularization over code duplication.
- Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).
- Don't use `useState` or `useEffect` to store local state. It's false convenience. Take the extra 3 minutes and change it to a `logic` early on in the development.
- Logics still have a tiny initialization cost. Hence this rule doesn't apply to library components in the `lib/` folder, which might be rendered hundreds of times on a page with different sets of data. Still feel free to write a logic for a complicated `lib/` component when needed.
- Use named exports; avoid default exports
- Structure files logically: logic, component, types, styles
Naming Conventions
- Always look around the codebase for naming conventions, and follow the best practices of the environment (e.g. use `camelCase` variables in JS, `snake_case` in Python).
- Use clear, yet functional names (`searchResults` vs `data`).
- Logics are camelCase (`dashboardLogic`)
- React components are PascalCase (`DashboardMenu`).
- Props for both logics and components are PascalCase and end with `Props` (`DashboardLogicProps` & `DashboardMenuProps`)
- Name the `.ts` file according to its main export: `DashboardMenu.ts` or `DashboardMenu.tsx` or `dashboardLogic.ts` or `Dashboard.scss`. Pay attention to the case.
- Avoid `index.ts`, `styles.css`, and other generic names, even if this is the only file in a directory.
UI and Styling
- Use Tailwind CSS as primary styling solution
- For non-Tailwind cases:
- Use SCSS with component-specific files
- Namespace under component class (.DashboardMenu)
- Follow BEM for modals (.DashboardMenu__modal)
- Import styles directly (MyComponent.scss)
- Replace custom SCSS with Tailwind when possible
Testing Requirements
- Logic tests for all Kea logic files
- React Testing Library tests for interactive lib/ components
- Add presentational elements to Storybook
- Run storybook locally: pnpm storybook
Core Principles
- Prioritize maintainability over development speed
- Keep data layer separate from view hierarchy
- Write clear, understandable code
- Think data first, implement views second

71
.cursor/rules/rust.mdc Normal file
View File

@@ -0,0 +1,71 @@
---
description: Rules for writing Rust services at PostHog. Focuses on writing async Rust with Tokio and encoding general Rust best practices from the Rust book and docs.
globs: *.rs, rust/
---
You are an expert in Rust, async programming, and concurrent systems.
Key Principles
- Write clear, concise, and idiomatic Rust code with accurate examples.
- Use async programming paradigms effectively, leveraging `tokio` for concurrency.
- Prioritize modularity, clean code organization, and efficient resource management.
- Use expressive variable names that convey intent with auxiliary verbs (e.g., `is_ready`, `has_data`).
- Adhere to Rust's naming conventions: snake_case for variables and functions, PascalCase for types and structs.
- Avoid code duplication; use functions and modules to encapsulate reusable logic.
- Write code with safety, concurrency, and performance in mind, embracing Rust's ownership and type system.
Async Programming
- Use `tokio` as the async runtime for handling asynchronous tasks and I/O.
- Implement async functions using `async fn` syntax.
- Leverage `tokio::spawn` for task spawning and concurrency.
- Use `tokio::select!` for managing multiple async tasks and cancellations.
- Favor structured concurrency: prefer scoped tasks and clean cancellation paths.
- Implement timeouts, retries, and backoff strategies for robust async operations.
Performance Optimization:
- try to maintain zero copy for all bytes
- try to avoid dynamic functions
- always prefer approaches that do not require allocation of new Strings or Vecs unless specifically requested
Channels and Concurrency
- Use Rust's `tokio::sync::mpsc` for asynchronous, multi-producer, single-consumer channels.
- Use `tokio::sync::broadcast` for broadcasting messages to multiple consumers.
- Implement `tokio::sync::oneshot` for one-time communication between tasks.
- Prefer bounded channels for backpressure; handle capacity limits gracefully.
- Use `tokio::sync::Mutex` and `tokio::sync::RwLock` for shared state across tasks, avoiding deadlocks.
Error Handling and Safety
- Embrace Rust's Result and Option types for error handling.
- Use `?` operator to propagate errors in async functions, avoid using unwrap() without proper error handling.
- Implement custom error types using `thiserror` or `anyhow` for more descriptive errors.
- Implement proper error logging and user-friendly messages
- Prioritize error handling: handle errors and edge cases early in the code
- Use early returns and guard clauses
- Use `.await` responsibly, ensuring safe points for context switching.
Testing
- Write unit tests with `tokio::test` for async tests.
- Use `tokio::time::pause` for testing time-dependent code without real delays.
- Implement integration tests to validate async behavior and concurrency.
- Use mocks and fakes for external dependencies in tests.
Performance Optimization
- Minimize async overhead; use sync code where async is not needed.
- Avoid blocking operations inside async functions; offload to dedicated blocking threads if necessary.
- Use `tokio::task::yield_now` to yield control in cooperative multitasking scenarios.
- Optimize data structures and algorithms for async use, reducing contention and lock duration.
- Use `tokio::time::sleep` and `tokio::time::interval` for efficient time-based operations.
Async Ecosystem
- Use `tokio` for async runtime and task management.
- Leverage `hyper` or `reqwest` for async HTTP requests.
- Use `serde` for serialization/deserialization.
- Use `sqlx` or `tokio-postgres` for async database interactions.
- Utilize `tonic` for gRPC with async support.
Key Conventions
1. Structure the application into modules: separate concerns like networking, database, and business logic.
2. Use environment variables for configuration management (e.g., `dotenv` crate).
3. Ensure code is well-documented with inline comments and Rustdoc.
Refer to Rust's async book and `tokio` documentation for in-depth information on async patterns, best practices, and advanced features. Follow Rust docs for style, examples, and code.

19
.cursorrules Normal file
View File

@@ -0,0 +1,19 @@
DO NOT GIVE ME HIGH LEVEL SHIT, IF I ASK FOR FIX OR EXPLANATION, I WANT ACTUAL CODE OR EXPLANATION! I DON'T WANT "Here's how you can blablabla"
- Be casual unless otherwise specified
- Be terse
- Suggest solutions that I didn't think about-anticipate my needs
- Treat me as an expert
- Be accurate and thorough
- Give the answer immediately. Provide detailed explanations and restate my query in your own words if necessary after giving the answer
- Value good arguments over authorities, the source is irrelevant
- Consider new technologies and contrarian ideas, not just the conventional wisdom
- You may use high levels of speculation or prediction, just flag it for me
- No moral lectures
- Discuss safety only when it's crucial and non-obvious
- If your content policy is an issue, provide the closest acceptable response and explain the content policy issue afterward
- Cite sources whenever possible at the end, not inline
- No need to mention your knowledge cutoff
- No need to disclose you're an AI
- Please respect my formatting preferences when you provide code.
- Split into multiple responses if one response isn't enough to answer the question.
If I ask for adjustments to code I have provided you, do not repeat all of my code unnecessarily. Instead try to keep the answer brief by giving just a couple lines before/after any changes you make. Multiple code blocks are ok.