Bądź konkretny
Niejasne reguły prowadzą do niespójnego kodu. Uwzględnij konkretne przykłady.
Niestandardowe reguły i szablony w Cursor przekształcają pomoc AI z ogólnej pomocy w precyzyjne narzędzie dostosowane do konkretnych potrzeb twojego zespołu. Zapewniają spójność, egzekwują standardy i przechwytują wiedzę instytucjonalną.
Reguły to instrukcje, które kształtują zachowanie AI Cursor w twoim projekcie. Mogą:
Cursor stosuje reguły w określonej kolejności:
# [Kategoria reguły]: [Konkretny temat]
## Kontekst
Krótki opis kiedy i dlaczego ta reguła ma zastosowanie.
## Wymagania
- Konkretne wymaganie 1- Konkretne wymaganie 2- Konkretne wymaganie 3
## Przykłady
### Dobry przykład
```language// Kod zgodny z regułą```
// Kod naruszający regułę
Wyjaśnienie dlaczego ta reguła istnieje i jej korzyści.
Przypadki, w których ta reguła może nie mieć zastosowania.
### Przykłady reguł z prawdziwego świata
<Tabs> <TabItem label="Reguły architektury"> ```markdown # Architektura: wzorzec warstwy serwisu
## Kontekst Cała logika biznesowa musi być zaimplementowana w klasach serwisu, nie w kontrolerach lub modelach.
## Wymagania - Kontrolery obsługują tylko kwestie HTTP (żądanie/odpowiedź) - Serwisy zawierają całą logikę biznesową - Serwisy są bezstanowe i testowalne - Serwisy wstrzykują zależności przez konstruktor - Jeden serwis na encję domenową
## Przykłady
### Dobry przykład ```typescript // UserController.ts export class UserController { constructor(private userService: UserService) {}
async createUser(req: Request, res: Response) { const userData = req.body; const user = await this.userService.create(userData); res.json(user); } }
// UserService.ts export class UserService { constructor( private userRepo: UserRepository, private emailService: EmailService ) {}
async create(data: CreateUserDto): Promise<User> { // Logika biznesowa tutaj const user = await this.userRepo.save(data); await this.emailService.sendWelcome(user); return user; } } ```
### Zły przykład ```typescript // UserController.ts - ŹLE: logika biznesowa w kontrolerze export class UserController { async createUser(req: Request, res: Response) { const user = new User(req.body);
// Logika biznesowa nie powinna być tutaj! if (await this.checkDuplicateEmail(user.email)) { throw new Error('Email istnieje'); }
await db.users.insert(user); await sendEmail(user.email, 'Witamy!');
res.json(user); } } ```
## Uzasadnienie - Separacja zagadnień - Łatwiejsze testowanie (mockowanie serwisów) - Wielokrotnego użytku logika biznesowa - Jasne granice między warstwami ``` </TabItem> <TabItem label="Reguły bezpieczeństwa"> ```markdown # Bezpieczeństwo: walidacja wejścia
## Kontekst Wszystkie dane wejściowe użytkownika muszą być zwalidowane przed przetworzeniem.
## Wymagania - Używaj biblioteki walidacji (Joi, Yup, Zod) - Waliduj na poziomie kontrolera - Sanityzuj ciągi znaków, aby zapobiec XSS - Używaj sparametryzowanych zapytań dla SQL - Nigdy nie ufaj tylko walidacji po stronie klienta
## Przykłady
### Dobry przykład ```typescript import { z } from 'zod';
const CreateUserSchema = z.object({ email: z.string().email(), password: z.string().min(8).regex(/[A-Z]/).regex(/[0-9]/), name: z.string().min(2).max(100).transform(sanitizeHtml), age: z.number().int().min(18).max(120) });
async createUser(req: Request, res: Response) { try { const validated = CreateUserSchema.parse(req.body); const user = await this.userService.create(validated); res.json(user); } catch (error) { if (error instanceof z.ZodError) { res.status(400).json({ errors: error.errors }); } } } ```
### Zły przykład ```typescript // ŹLE: brak walidacji async createUser(req: Request, res: Response) { const user = await this.userService.create(req.body); res.json(user); }
// ŹLE: luka SQL injection const query = `SELECT * FROM users WHERE email = '${email}'`; ```
## Wyjątki - Wewnętrzne wywołania serwis-do-serwisu mogą pomijać walidację - Ale zawsze waliduj na granicach systemu ``` </TabItem> <TabItem label="Reguły wydajności"> ```markdown # Wydajność: optymalizacja zapytań bazy danych
## Kontekst Optymalizuj wszystkie zapytania do bazy danych pod kątem wydajności.
## Wymagania - Zawsze używaj indeksów dla klauzul WHERE - Paginuj wyniki ponad 100 rekordów - Używaj SELECT z konkretnymi kolumnami, nie SELECT * - Grupuj operacje, gdy to możliwe - Monitoruj wolne zapytania
## Przykłady
### Dobry przykład ```typescript // Zoptymalizowane zapytanie z użyciem indeksu async findActiveUsers(page: number, limit: number = 50) { return this.db.users .select(['id', 'name', 'email', 'lastActive']) .where('status', 'active') .where('lastActive', '>', thirtyDaysAgo) .orderBy('lastActive', 'desc') .limit(limit) .offset(page * limit); }
// Operacja wsadowa async updateMultipleUsers(updates: UserUpdate[]) { const chunks = chunk(updates, 1000);
for (const batch of chunks) { await this.db.transaction(async (trx) => { await Promise.all( batch.map(update => trx.users.update(update.id, update.data) ) ); }); } } ```
### Zły przykład ```typescript // ŹLE: brak paginacji, SELECT * async getAllUsers() { return this.db.query('SELECT * FROM users'); }
// ŹLE: problem zapytania N+1 const users = await getUsers(); for (const user of users) { user.posts = await getPosts(user.id); } ``` ``` </TabItem></Tabs>
## Zaawansowane wzorce reguł
### Dynamiczne reguły z kontekstem
```markdown# Reguła dynamiczna: format odpowiedzi API
## KontekstOdpowiedzi API muszą följować nasz standardowy format, który różni się w zależności od środowiska.
## Implementacja```typescriptinterface ApiResponse<T> { success: boolean; data?: T; error?: { code: string; message: string; details?: any; }; metadata: { timestamp: string; version: string; environment: 'dev' | 'staging' | 'prod'; };}
// W środowisku rozwoju, uwzględnij informacje debugowaniaif (process.env.NODE_ENV === 'development') { response.metadata.debug = { query: req.query, headers: req.headers, processingTime: Date.now() - startTime };}
Podczas generowania punktów końcowych API:
### Reguły specyficzne dla technologii
<Tabs> <TabItem label="Reguły React"> ```markdown # React: wzorce komponentów
## Tylko komponenty funkcyjne Używaj komponentów funkcyjnych z hookami. Żadnych komponentów klasowych.
## Struktura komponentu ```tsx // 1. Importy import React, { useState, useEffect } from 'react'; import { useUser } from '@/hooks/useUser'; import { Button } from '@/components/ui/Button'; import type { UserProps } from '@/types';
// 2. Typy interface ComponentProps { userId: string; onUpdate?: (user: User) => void; }
// 3. Komponent export function UserProfile({ userId, onUpdate }: ComponentProps) { // 4. Hooki const { user, loading, error } = useUser(userId); const [isEditing, setIsEditing] = useState(false);
// 5. Efekty useEffect(() => { // Logika efektu }, [userId]);
// 6. Handlery const handleEdit = () => { setIsEditing(true); };
// 7. Render if (loading) return <Spinner />; if (error) return <ErrorDisplay error={error} />;
return ( <div> {/* JSX */} </div> ); } ```
## Zarządzanie stanem - Używaj React Query dla stanu serwera - Używaj Zustand dla stanu klienta - Unikaj prop drilling - używaj kontekstu oszczędnie ``` </TabItem> <TabItem label="Reguły Node.js"> ```markdown # Node.js: wzorce backendu
## Obsługa błędów ```typescript // Niestandardowe klasy błędów export class AppError extends Error { constructor( public statusCode: number, public message: string, public code: string ) { super(message); } }
// Globalny handler błędów app.use((err: Error, req: Request, res: Response, next: NextFunction) => { if (err instanceof AppError) { return res.status(err.statusCode).json({ success: false, error: { code: err.code, message: err.message } }); }
// Loguj nieoczekiwane błędy logger.error('Nieoczekiwany błąd:', err); res.status(500).json({ success: false, error: { code: 'INTERNAL_ERROR', message: 'Wystąpił nieoczekiwany błąd' } }); }); ```
## Wzorzec handler async ```typescript const asyncHandler = (fn: Function) => ( req: Request, res: Response, next: NextFunction ) => { Promise.resolve(fn(req, res, next)).catch(next); };
// Użycie router.post('/users', asyncHandler(async (req, res) => { const user = await userService.create(req.body); res.json(user); })); ``` ``` </TabItem></Tabs>
## System szablonów
### Tworzenie szablonów wielokrotnego użytku
```markdown# Szablon: nowy mikroserwis
Podczas tworzenia nowego mikroserwisu, wygeneruj następującą strukturę:
## Struktura katalogów
service-name/ ├── src/ │ ├── api/ │ │ ├── controllers/ │ │ ├── middlewares/ │ │ └── routes/ │ ├── core/ │ │ ├── domain/ │ │ ├── services/ │ │ └── repositories/ │ ├── infrastructure/ │ │ ├── database/ │ │ ├── cache/ │ │ └── messaging/ │ └── index.ts ├── tests/ │ ├── unit/ │ ├── integration/ │ └── e2e/ ├── .env.example ├── Dockerfile ├── docker-compose.yml └── package.json
## Podstawowe pliki do wygenerowania
1. **package.json** z naszymi standardowymi zależnościami2. **tsconfig.json** z naszymi ustawieniami TypeScript3. **Dockerfile** z wieloetapowym buildem4. **.env.example** z wymaganymi zmiennymi5. **src/index.ts** z kontrolą zdrowia i graceful shutdown6. Podstawowe przykłady kontrolera, serwisu i repozytorium7. Standardowe middleware (auth, logowanie, obsługa błędów)8. Konfiguracja testów z przykładami
// Skrypt generatora szablonówclass TemplateGenerator { async generateFromTemplate(templateName: string, variables: Record<string, any>) { const template = await this.loadTemplate(templateName);
// Przetwórz szablon ze zmiennymi const processed = this.processTemplate(template, variables);
// Wygeneruj pliki for (const file of processed.files) { await this.createFile(file.path, file.content); }
// Uruchom hooki post-generacji await this.runHooks(processed.hooks); }
private processTemplate(template: string, vars: Record<string, any>): ProcessedTemplate { // Zastąp zmienne jak {{serviceName}} let content = template;
for (const [key, value] of Object.entries(vars)) { const regex = new RegExp(`{{${key}}}`, 'g'); content = content.replace(regex, value); }
// Obsłuż warunki content = this.processConditionals(content, vars);
// Obsłuż pętle content = this.processLoops(content, vars);
return this.parseToFiles(content); }}
Ustanów własność reguł
Dokumentacja reguł
# Metadane reguły
- **Autor**: @teamlead- **Utworzone**: 2024-01-15- **Zmodyfikowane**: 2024-03-20- **Wersja**: 2.1- **Recenzenci**: @senior-dev, @architect- **Dotknięte zespoły**: Backend, Frontend
Testowanie reguł
// Testuj, że wygenerowany kod przestrzega regułdescribe('Zgodność reguł architektury', () => { test('Sprawdź, czy serwisy postępują zgodnie ze wzorcem dependency injection', () => { // Stwórz plik testowego promptu const testPrompt = ` Stwórz UserService zgodnie z tymi regułami: - Użyj dependency injection w konstruktorze - Wstrzyknij Repository jako zależność - Nie twórz instancji zależności z 'new' - Postępuj zgodnie z naszymi wzorcami architektury z @Cursor Rules `;
// Otwórz w Cursor i ręcznie zweryfikuj wygenerowany kod // Użyj trybu Agent (Ctrl+I) z powyższym promptem // Następnie uruchom ten test na wygenerowanym pliku:
const generatedCode = fs.readFileSync('src/services/UserService.ts', 'utf8');
expect(generatedCode).toMatch(/constructor\s*\(/); expect(generatedCode).toMatch(/private.*Repository/); expect(generatedCode).not.toMatch(/new.*Repository/); });});
Dystrybucja reguł
// Śledź zgodność z regułamiclass RuleComplianceTracker { async analyzeCodebase() { const violations = [];
// Sprawdź każdą regułę for (const rule of this.rules) { const ruleViolations = await this.checkRule(rule); violations.push(...ruleViolations); }
// Wygeneruj raport return { totalFiles: this.fileCount, violations: violations, complianceRate: this.calculateCompliance(violations), byRule: this.groupByRule(violations), byTeam: this.groupByTeam(violations), }; }}
Bądź konkretny
Niejasne reguły prowadzą do niespójnego kodu. Uwzględnij konkretne przykłady.
Wyjaśnij dlaczego
Zawsze uwzględnij uzasadnienie. Deweloperzy przestrzegają reguł, które rozumieją.
Pokaż przykłady
Dobre i złe przykłady czynią reguły krystalicznie jasnymi.
Aktualizuj regularnie
Przeglądaj reguły kwartalnie. Usuwaj przestarzałe, dodawaj nowe wnioski.
Nadmierne ograniczanie
❌ Źle: "Nigdy nie używaj pętli forEach"✅ Dobrze: "Preferuj map/filter/reduce do transformacji. Używaj forEach tylko do efektów ubocznych."
Sprzeczne reguły
❌ Źle: Posiadanie zarówno "Zawsze używaj async/await" i "Używaj callbacków dla wydajności"✅ Dobrze: Jasne wytyczne kiedy używać każdego podejścia
Uzależnienie od technologii
❌ Źle: "Zawsze używaj biblioteki X do wszystkiego"✅ Dobrze: "Używaj biblioteki X do przypadku użycia Y z powodu Z"
Cursor może generować reguły z twoich sesji rozwoju:
/generate-rules
Cursor przeanalizuje tę konwersację i stworzy reguły na podstawie:- Wzorców, które ustanowiłeś- Poprawek, które wprowadziłeś- Preferencji, które wyraziłeś- Standardów, które egzekwowałeś
# Wygenerowana reguła: obsługa błędów API
Na podstawie konwersacji z 2024-03-20
## Wykryty wzorzec
Konsekwentnie poprawiasz punkty końcowe API, aby:
1. Używać bloków try-catch2. Zwracać standardowe odpowiedzi błędów3. Logować błędy z kontekstem4. Używać odpowiednich kodów statusu HTTP
## Zalecana reguła
Wszystkie punkty końcowe API muszą implementować obsługę błędów, która:
- Przechwytuje wszystkie możliwe błędy- Zwraca instancje AppError- Loguje z ID korelacji- Nigdy nie ujawnia wewnętrznych błędów klientom
## Szablon kodu
[Wygenerowany szablon na podstawie twoich poprawek]
name: Kontrola zgodności reguł
on: [push, pull_request]
jobs: check-rules: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3
- name: Uruchom kontrolę reguł Cursor run: | npx @company/cursor-rule-checker \ --rules .cursor/rules \ --source src \ --report compliance-report.json
- name: Komentarz PR if: github.event_name == 'pull_request' uses: actions/github-script@v6 with: script: | const report = require('./compliance-report.json'); const comment = generateComplianceComment(report); github.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: comment });
Opanuj niestandardowe reguły i szablony:
Reguły i szablony to żywe dokumenty. Powinny ewoluować wraz z nauką twojego zespołu i rozwojem projektu. Opanuj to, a będziesz miał asystę AI, która naprawdę rozumie twoje konkretne potrzeby.