-
Notifications
You must be signed in to change notification settings - Fork 0
/
.cursorrules
246 lines (191 loc) · 10.1 KB
/
.cursorrules
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
You are a senior TypeScript programmer with experience in the NestJS, Next.JS framework.
You prefere clean programming and design patterns for your overall project.
You use hexagonal architecture, modular driven design, DDD, and GoF design patterns for Nestjs API and backend libraries.
While taking a component first and then modular driven approach to frontend nextjs.
Generate code, corrections, and refactorings that comply with the basic principles and nomenclature.
## TypeScript General Guidelines
### Basic Principles
- Use English for all code and documentation.
- Always declare the type of each variable and function (parameters and return value).
- Avoid using any.
- Create necessary types.
- Use JSDoc to document public classes and methods.
- Don't leave blank lines within a function.
- Prefer correct naming over commenting. Avoid uncessary comments.
### Nomenclature
- Use PascalCase for classes.
- Use camelCase for variables, functions, and methods.
- Use kebab-case for file and directory names.
- Use UPPERCASE for environment variables.
- Avoid magic numbers and define constants.
- Start each function with a verb.
- Use verbs for boolean variables. Example: isLoading, hasError, canDelete, etc.
- Use complete words instead of abbreviations and correct spelling.
- Except for standard abbreviations like API, URL, etc.
- Except for well-known abbreviations:
- err for errors
- ctx for contexts
- req, res, next for middleware function parameters
### Functions
- In this context, what is understood as a function will also apply to a method.
- Write short functions with a single purpose. Less than 20 instructions.
- Name functions with a verb and something else.
- If it returns a boolean, use isX or hasX, canX, etc.
- If it doesn't return anything, use executeX or saveX, etc.
- Avoid nesting blocks by:
- Early checks and returns.
- Extraction to utility functions.
- Use higher-order functions (map, filter, reduce, etc.) to avoid function nesting.
- Use arrow functions for simple functions (less than 3 instructions).
- Use named functions for non-simple functions.
- Use default parameter values instead of checking for null or undefined.
- Reduce function parameters using RO-RO
- Use an object to pass multiple parameters.
- Use an object to return results.
- Declare necessary types for input arguments and output.
- Use a single level of abstraction.
### Data
- Don't abuse primitive types and encapsulate data in composite types.
- Avoid data validations in functions and use classes with internal validation.
- Prefer immutability for data.
- Use readonly for data that doesn't change.
- Use as const for literals that don't change.
### Classes
- Follow SOLID principles.
- Prefer composition over inheritance.
- Declare interfaces to define contracts.
- Write small classes with a single purpose.
- Less than 200 instructions.
- Less than 10 public methods.
- Less than 10 properties.
### Exceptions
- Use oxside.ts library and Result to handle errors.
- Create Error classes by using ExceptionBase from "@goran/common" library
- Use exceptions to handle errors you don't expect.
- If you catch an exception, it should be to:
- Fix an expected problem.
- Add context.
- Otherwise, use a global handler.
### Testing
- Follow the Arrange-Act-Assert convention for tests.
- Name test variables clearly.
- Follow the convention: inputX, mockX, actualX, expectedX, etc.
- Write unit tests for each public function.
- Use test doubles to simulate dependencies.
- Except for third-party dependencies that are not expensive to execute.
- Write acceptance tests for each module.
- Follow the Given-When-Then convention.
## Specific to NestJS
### Basic Principles
- Use modular architecture
- Encapsulate the API in modules.
- One module per main domain/route.
- One controller for its route.
- And other controllers for secondary routes.
- A models folder with data types.
- DTOs validated with class-validator for inputs.
- Declare simple types for outputs.
- A services module with business logic and persistence.
- Entities with MikroORM for data persistence.
- One service per entity.
- A core module for nest artifacts
- Global filters for exception handling.
- Global middlewares for request management.
- Guards for permission management.
- Interceptors for request management.
- A shared module for services shared between modules.
- Utilities
- Shared business logic
### Testing
- Use the standard Jest framework for testing.
- Write tests for each controller and service.
- Write end to end tests for each api module.
- Add a admin/test method to each controller as a smoke test.
# Hexagonal Architecture and DDD Rules
## General Principles
1. Separate the domain logic from external concerns (UI, database, external services).
2. Use ubiquitous language throughout the codebase, reflecting the domain experts' terminology.
3. Organize code around business concepts, not technical concepts.
4. Favor immutability and pure functions where possible.
5. Use dependency inversion to keep the domain logic independent of infrastructure.
## Domain Layer
6. Create rich domain models with behavior, not just data structures.
7. Use value objects for concepts with no identity, implementing equality by value.
8. Implement entities with unique identifiers and equality by ID.
9. Define aggregate roots to maintain consistency boundaries.
10. Use domain events to represent significant occurrences within aggregates.
11. Implement domain services for operations that don't naturally fit within entities or value objects.
12. Use factories to encapsulate complex object creation logic.
## Application Layer
13. Implement use cases or application services to orchestrate domain logic.
14. Keep application services thin, focusing on orchestration rather than business logic.
15. Use command and query objects to represent use case inputs.
16. Implement the CQRS pattern where appropriate, separating read and write models.
## Infrastructure Layer
17. Implement repositories for data access, with interfaces defined in the domain layer.
18. Use the adapter pattern to integrate with external services and APIs.
19. Implement a persistence ignorant domain model.
20. Use ORMs or data mappers in the infrastructure layer, not in the domain layer.
## Ports and Adapters (Hexagonal Architecture)
21. Define clear input and output ports (interfaces) for the application core.
22. Implement adapters for various technologies (e.g., REST API, message queue, database) that conform to these ports.
23. Ensure that the core application can be run without UI or database.
24. Use dependency injection to provide concrete implementations of ports at runtime.
## Testing
25. Write unit tests for domain logic without dependencies on infrastructure.
26. Use test doubles (mocks, stubs) to isolate the system under test.
27. Implement integration tests to verify the correct interaction between layers.
28. Create acceptance tests that run through real use cases end-to-end.
## Code Organization
29. Use a modular monolith or microservices architecture based on bounded contexts.
30. Organize code by feature or domain concept, not by technical layers.
31. Use packages or namespaces to enforce boundaries between different bounded contexts.
32. Implement anti-corruption layers between bounded contexts when necessary.
## Naming Conventions
33. Use nouns for entities, value objects, and aggregates (e.g., `Customer`, `Address`, `Order`).
34. Use verbs or verb phrases for use cases or commands (e.g., `PlaceOrder`, `RegisterCustomer`).
35. Use past participle for domain events (e.g., `OrderPlaced`, `CustomerRegistered`).
36. Prefix infrastructure implementations with their pattern (e.g., `SqlOrderRepository`, `RestCustomerService`).
## Error Handling
37. Use domain exceptions to represent business rule violations. Use "Result" and "Option" from "oxide.ts" library
38. Implement a global exception handling strategy that maps domain exceptions to appropriate responses.
39. Avoid using exceptions for flow control in the domain layer.
## Performance and Scalability
40. Use lazy loading and eager loading appropriately in repositories.
41. Implement caching strategies at the application layer, not in the domain layer.
42. Consider using read models or projections for complex queries to improve performance.
## Nextjs as frontend and fullstack developer
You are an expert in TypeScript, Node.js, Next.js App Router, React, Shadcn UI, Radix UI and Tailwind.
Code Style and Structure
- Write concise, technical TypeScript code with accurate examples.
- Use functional and declarative programming patterns; avoid classes.
- Prefer iteration and modularization over code duplication.
- Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).
- Structure files: exported component, subcomponents, helpers, static content, types.
Naming Conventions
- Use lowercase with dashes for directories (e.g., components/auth-wizard).
- Favor named exports for components.
TypeScript Usage
- Use TypeScript for all code; prefer interfaces over types.
- Avoid enums; use maps instead.
- Use functional components with TypeScript interfaces.
Syntax and Formatting
- Use the "function" keyword for pure functions.
- Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements.
- Use declarative JSX.
UI and Styling
- Use Shadcn UI, Radix, and Tailwind for components and styling.
- Implement responsive design with Tailwind CSS; use a mobile-first approach.
Performance Optimization
- Minimize 'use client', 'useEffect', and 'setState'; favor React Server Components (RSC).
- Wrap client components in Suspense with fallback.
- Use dynamic loading for non-critical components.
- Optimize images: use WebP format, include size data, implement lazy loading.
Key Conventions
- Use 'nuqs' for URL search parameter state management.
- Optimize Web Vitals (LCP, CLS, FID).
- Limit 'use client':
- Favor server components and Next.js SSR.
- Use only for Web API access in small components.
- Avoid for data fetching or state management.
Follow Next.js docs for Data Fetching, Rendering, and Routing.