Przejdź do głównej zawartości

Mikroserwisy w Cursorze

Tworzenie mikroserwisów w Cursorze działa wtedy, gdy Agent Cursora widzi topologię serwisów i kontrakty, zanim zacznie pisać kod. Reguły projektu opisują, który serwis czym zarządza, Plan Mode ustala granicę, a kontrakt OpenAPI lub AsyncAPI powstaje i przechodzi bramkę jako pierwszy. Każdy serwis przyjmuje się na podstawie wyników poleceń: lint, diff zmian łamiących, testy kontraktowe, health check.

Ta strona jest dla programisty albo tech leada, który na co dzień buduje serwisy w Cursorze. Sytuacja jest znajoma: prosisz Agenta o serwis płatności i dostajesz schludną aplikację w Expressie, która czyta prosto z bazy zamówień, wymyśla własne nazwy zdarzeń i publikuje paymentComplete, podczas gdy dwaj konsumenci nasłuchują payment.completed. Nic nie pada aż do stagingu. Rozwiązaniem nie jest lepszy prompt, tylko kontekst, który Agent ładuje zawsze, i bramki, których nie da się obejść argumentacją.

Źródła tej strony sprawdzono 26 września 2026 r.: funkcje Cursora, z których korzysta (Rules, Plan Mode, Worktrees), pochodzą z dokumentacji Cursora zweryfikowanej 28 sierpnia 2026 r., a format plików reguł jest zgodny ze stroną reguły projektu w Cursorze. Nazwy w interfejsie mogą się różnić między wersjami Cursora 3.x, więc sprawdź je we własnej instalacji. Polecenia oasdiff, @redocly/cli, @asyncapi/cli i @pact-foundation/pact zweryfikowano 26 września 2026 r. w ich repozytoriach i w npm.

Co daje ci ten sposób pracy z mikroserwisami w Cursorze

Dział zatytułowany „Co daje ci ten sposób pracy z mikroserwisami w Cursorze”
  • Dwa rodzaje reguł projektu: regułę topologii ładowaną zawsze i po jednej regule na serwis, ładowanej dla jego plików, więc Agent wie, która baza i które zdarzenia należą do którego serwisu.
  • Prompt dla Plan Mode, który ustala granicę serwisu, własność danych i zdarzenia, zanim zmieni się jakikolwiek plik.
  • Pętlę „najpierw kontrakt”, w której plik OpenAPI lub AsyncAPI powstaje pierwszy, a CI blokuje go, gdy psuje konsumenta.
  • Prompt do tworzenia szkieletu, który kopiuje konwencje serwisu, któremu już ufasz, oraz polecenia, które rozstrzygają, czy szkielet jest gotowy.
  • Tabelę dowodów, która mówi recenzentowi, co sprawdzić zamiast czytania każdej wygenerowanej linii.
  • Kroki naprawcze dla awarii typowych dla pracy z wieloma serwisami: wspólnych baz, cykli, rozjazdu zdarzeń i sieci w Docker Compose.

Agent przestrzega tylko granic, które widzi. Sposób, w jaki mu je pokażesz, zależy od tego, jak przechowujesz serwisy.

Układ repozytoriówCo Agent widzi domyślnieCo dodać
Monorepo (orders-service/, payments-service/, …)Wszystkie serwisyJedną regułę topologii i po jednej regule na serwis ograniczonej do jego plików, żeby Agent nie pożyczał kodu przez granice
Polyrepo, kilka serwisów zmienianych razemJedno repozytoriumMulti-root workspace z serwisami, które zmieniasz, i te same reguły; konfigurację .code-workspace opisuje strona praca z wieloma repozytoriami w Cursorze
Polyrepo, wiele serwisów innych zespołówJedno repozytoriumSkopiuj opublikowane kontrakty innych zespołów do contracts/ i wskaż je w regułach zamiast otwierać ich kod

Niezależnie od układu opisz topologię raz, w pliku .cursor/rules/service-topology.mdc:

---
description: Service topology, data ownership and communication rules for every task
alwaysApply: true
---
# Services
- api-gateway (Node.js, Express): routing, rate limiting, auth. No database.
- orders-service (Node.js, Express): orders. Owns the `orders` Postgres database.
- payments-service (Node.js, Express): payments and refunds. Owns the `payments` database.
- users-service (Python, FastAPI): accounts and profiles. Owns the `users` database.
- inventory-service (Go): stock and reservations. Owns the `inventory` database.
# Hard boundaries
- Database per service. Never query another service's database; call its API or consume its events.
- Contracts live in <service>/docs/openapi.yml and contracts/events/asyncapi.yml. Change the contract first.
- Events are named <entity>.<past-tense-verb> (order.created, payment.completed) and carry event_id and correlation_id.
- Every service exposes GET /health and GET /ready and logs JSON with correlation_id.
# Done means
- `npx @redocly/cli lint <service>/docs/openapi.yml` passes
- the service's own tests pass: `npm test --workspace <service>` (Node services), `pytest` in users-service, `go test ./...` in inventory-service

Potem dodaj po jednej regule na serwis, która ładuje się tylko wtedy, gdy Agent dotyka plików tego serwisu. Zapisz ją jako .cursor/rules/payments-service.mdc:

---
description: Conventions for payments-service
globs: payments-service/**
alwaysApply: false
---
- Stripe webhook signatures are verified with the secret in STRIPE_WEBHOOK_SECRET; never log the payload.
- Consumes: order.created. Publishes: payment.initiated, payment.completed, payment.failed, payment.refunded.
- Every consumer is idempotent on event_id and sends failures to the dead-letter queue.

Regułę ładowaną zawsze trzymaj krótką, bo płaci za nią każda sesja. Zapisz oba pliki jako .mdc, w formacie ze strony reguły projektu w Cursorze, i nie zakładaj, że plik się ładuje tylko dlatego, że leży w .cursor/rules/: najpierw przeprowadź test kanarkowy z tej strony. Pokazuje on, czy plik w ogóle został wczytany.

Plan Mode według dokumentacji Cursora tworzy szczegółowy plan implementacji, zanim powstanie jakikolwiek kod. Tego potrzebuje decyzja o granicy: o własność danych spierasz się, kiedy nic jeszcze nie jest napisane. Otwórz nowy czat, przełącz go na Plan Mode i dołącz kod, który dziś wykonuje tę pracę.

Czytaj plan, a nie diff. Liczą się dwa pytania: czy któryś krok zostawia dwa serwisy zapisujące do tej samej tabeli i czy każdy krok ma polecenie, które dowodzi, że zadziałał. Jeśli granica wciąż budzi spór, rozmowa o architekturze należy do strony planowanie architektury w Cursorze, zanim zaczniesz budować.

Na kontrakcie polegają inne zespoły, więc to jego weryfikujesz najsurowiej. Wygeneruj go, zanim powstanie jakikolwiek handler, i trzymaj się nazewnictwa kontraktu, który już działa.

Zdarzenia zasługują na to samo. Jeśli trzymasz plik AsyncAPI dla exchange’y RabbitMQ albo tematów Kafki, poproś Agenta o dopisanie tam nowych komunikatów i zwaliduj plik poleceniem npx @asyncapi/cli validate contracts/events/asyncapi.yml (@asyncapi/cli 6.x wymaga Node 24 lub nowszego).

Dwa polecenia zamieniają kontrakt w bramkę, która działa przy każdym pull requeście, niezależnie od tego, czy zmienił go człowiek, czy Agent. Uruchom je w terminalu albo w CI:

Okno terminala
# 1. The contract is well formed and follows your lint rules
npx @redocly/cli lint payments-service/docs/openapi.yml
# 2. The change does not break an existing consumer (compare with the main branch)
# (skipped for a new service, which has no base on main yet)
if git cat-file -e origin/main:payments-service/docs/openapi.yml 2>/dev/null; then
git show origin/main:payments-service/docs/openapi.yml > /tmp/openapi-base.yml &&
oasdiff breaking --fail-on ERR /tmp/openapi-base.yml payments-service/docs/openapi.yml
fi

oasdiff breaking --fail-on ERR kończy się kodem 1, gdy znajdzie pewną zmianę łamiącą, na przykład usunięte pole albo nowy wymagany parametr. Zainstalujesz go przez brew install oasdiff, go install github.com/oasdiff/oasdiff@latest albo obraz Dockera tufin/oasdiff. Nowy serwis nie ma jeszcze wersji bazowej na main, więc if pomija diff i do pierwszego merge’a działa tylko lint.

Kiedy kontrakt przejdzie bramkę, implementacja staje się wąskim zadaniem: „implement the handlers in payments-service so they match @payments-service/docs/openapi.yml exactly, using the validation middleware from @orders-service/src/routes/orders.ts”. Powierzchnię API wyznacza teraz kontrakt, a nie prompt.

Zbuduj szkielet nowego serwisu na wzór takiego, któremu ufasz

Dział zatytułowany „Zbuduj szkielet nowego serwisu na wzór takiego, któremu ufasz”

Ogólny szablon pomija twoje konwencje. Kiedy wskażesz Agentowi serwis, który zespół już utrzymuje na produkcji, dostaje konkretne wzorce middleware’u, logowania i Dockera do skopiowania.

Port 3004 to przykład; użyj tego, który przydziela twój plik Compose. Szkielet jest gotowy, gdy te trzy polecenia przechodzą, lint Redocly przechodzi, a git diff --stat nie pokazuje żadnego pliku poza payments-service/ oprócz wpisu w Compose. To ostatnie sprawdzenie tanio wyłapuje sytuację, w której Agent „pomocnie” poprawił orders-service.

Wybieraj świadomie między wywołaniem synchronicznym a zdarzeniem

Dział zatytułowany „Wybieraj świadomie między wywołaniem synchronicznym a zdarzeniem”

Agent może wywnioskować styl komunikacji ze sformułowania promptu: „Powiadom użytkownika, gdy zamówienie zostanie złożone” brzmi jak wywołanie funkcji i może się skończyć bezpośrednim wywołaniem HTTP do serwisu powiadomień. Zdecyduj o stylu sam i wpisz go do promptu.

Wywołujący…UżyjNazwij to w prompcie tak
Potrzebuje odpowiedzi, zanim odpowie sam (sprawdzenie stanu magazynu przy zakupie)Synchronicznego REST lub gRPC z timeoutem i circuit breakerem„Call inventory-service GET /v1/stock with a 2-second timeout”
Musi tylko wiedzieć, że praca zostanie wykonana (wysłanie potwierdzenia)Zdarzenia„Publish order.created; notification-service consumes it”
Rozpoczyna wieloetapową transakcję biznesową (zamówienie, płatność, magazyn)Sagi zdarzeń z kompensacjąBuduj po jednym kroku; zobacz rozwój systemów rozproszonych z AI

Przy konsumencie zdarzeń proś o zachowanie w razie awarii i o test, który go dowodzi, a nie tylko o ścieżkę szczęśliwą.

Jak zweryfikować zmianę w wielu serwisach bez czytania każdej linii?

Dział zatytułowany „Jak zweryfikować zmianę w wielu serwisach bez czytania każdej linii?”

Recenzent pull requesta obejmującego kilka serwisów potrzebuje dowodów na granicach, bo to tam powstają błędy. Poniższa tabela to pakiet dowodów, którego należy wymagać; każdy wiersz to polecenie, do którego wyniku pull request prowadzi linkiem. Ideę stojącą za tym podejściem opisuje strona dowody zamiast czytania kodu.

DowódPolecenie lub źródłoCo dowodziKto zatwierdza
Kontrakt jest poprawnynpx @redocly/cli lint … i npx @asyncapi/cli validate …Kontrakt ma poprawną strukturęCI
Żaden konsument się nie psujeoasdiff breaking --fail-on ERR względem origin/mainNie ma usuniętych pól ani nowych wymaganych danych wejściowychCI; zamierzone złamanie zatwierdza zespół-właściciel
Konsumenci nadal się zgadzająTesty Pact gatewaya (npm test w api-gateway) zapisują plik paktu; build payments-service odtwarza go przez Verifier.verifyProvider() z Pacta i pada przy niezgodnościOczekiwania gatewaya odpowiadają temu, co zwraca payments-serviceCI po obu stronach
Serwis działa poprawnieWłasny zestaw testów serwisu, w tym powyższe testy idempotencjiHandlery i konsumenci są zgodni z kontraktem, także na ścieżkach błędówCI
Działa razem z sąsiadamidocker compose up -d --wait i jedno żądanie end-to-end przez gatewaySieć, konfiguracja i health checki współpracująAutor, z wynikiem wklejonym do PR
Zmiana nie wyszła poza swój serwisgit diff --stat origin/mainBrak zmian w serwisach, których zadanie nie wymieniałoRecenzent, w 10 sekund

Pact to jedna zależność deweloperska po obu stronach: npm install -D @pact-foundation/pact (w npm wersja 17.1.4, sprawdzono 26 września 2026 r.).

Przegląd przez człowieka skupia się wtedy na diffie kontraktu i kolejności migracji, które są krótkie i mają duże konsekwencje. Automatyczny przegląd pull requestów ponad tymi bramkami opisuje strona Bugbot, a podpięcie poleceń do pipeline’u — CI/CD z Cursorem.

Worktrees w Cursorze pozwalają Agentowi pracować w izolowanych checkoutach Gita, więc jeden agent może budować handlery payments-service, a drugi aktualizować klienta w gatewayu, każdy na własnej gałęzi. Daj każdemu agentowi jeden serwis, a wspólny kontrakt tylko do odczytu. Najpierw scal zmianę kontraktu, potem dostawcę, a na końcu konsumentów, i po każdym scaleniu ponownie przejdź tabelę dowodów. Uruchamianie i nadzorowanie takich agentów opisuje strona równoległe agenty w oknie Agents.

Debuguj żądanie, które przechodzi przez kilka serwisów

Dział zatytułowany „Debuguj żądanie, które przechodzi przez kilka serwisów”

Gdy żądanie pada gdzieś między gatewayem a bazą, zbierz logi jednego correlation ID z każdego serwisu i pozwól Agentowi je zestawić. Użyj czatu w Plan Mode, żeby Agent najpierw zbadał sprawę i zaproponował rozwiązanie, zanim cokolwiek zmieni.

Brak serwisu na osi czasu, jak tutaj payments-service, sam w sobie jest ustaleniem: albo wywołanie nigdy nie nastąpiło, albo identyfikator korelacji (correlation ID) po drodze zaginął. Śledzenie i dashboardy, które robią z tego rutynę, opisuje strona monitoring z Cursorem.

Agent odpytuje bazę innego serwisu. Reguła topologii się nie załadowała albo prompt dołączał plik schematu innego serwisu. Naprawa: przeprowadź test kanarkowy ze strony o regułach projektu, usuń obcy schemat z czatu i powtórz granicę: „payments-service reads user data only through GET /v1/users/{id}”. Dodaj regułę lintu, która pada na importach między katalogami serwisów, żeby następną próbę wyłapała maszyna. W płaskiej konfiguracji ESLinta ogranicz wbudowaną regułę no-restricted-imports do jednego serwisu (ESLint 10.11.0, sprawdzono 26 września 2026 r.):

eslint.config.js
export default [
{
files: ['orders-service/**'],
rules: {
'no-restricted-imports': ['error', {
patterns: [{ group: ['**/payments-service/**'], message: 'Call the payments API or consume its events.' }],
}],
},
},
];

Dwa serwisy wywołują się nawzajem. payments-service woła orders-service, który woła payments-service. Naprawa: w czacie w Plan Mode poproś Agenta o wypisanie z kodu wszystkich wywołań wychodzących każdego serwisu i o wskazanie cykli. Przerwij każdy cykl zdarzeniem albo przenieś wspólny krok do serwisu, który jest właścicielem danych.

Payloady zdarzeń rozjeżdżają się między wydawcą a konsumentem. Konsument przestaje działać, choć nigdzie nie pojawia się błąd, bo ktoś zmienił nazwę pola. Naprawa: niech plik AsyncAPI będzie jedyną definicją, dołączaj go do każdego promptu o zdarzeniach i dodaj do każdego konsumenta test odrzucania niezgodnego schematu z promptu powyżej.

Nowy kontener nie widzi sąsiadów. Agent napisał samodzielny Dockerfile i wpis Compose w domyślnej sieci. Naprawa: dołącz istniejący docker-compose.yml, nazwij sieć i wymagaj wyniku docker compose up -d --wait, zanim przyjmiesz szkielet.

Agent „naprawia” kontrakt, żeby pasował do jego kodu. Gdy Redocly albo oasdiff świeci na czerwono, Agent ma pokusę, by poprawić specyfikację. Naprawa: napisz w prompcie, że kontrakt jest ustalony i zmieniać wolno tylko handlery, a CI niech odrzuca każdy diff kontraktu bez zatwierdzenia przez zespół-właściciela.

Kontekst zapełnia się, zanim zacznie się właściwe zadanie. Cztery serwisy, ich schematy i plik Compose są dołączone do każdego czatu. Naprawa: dołączaj tylko serwisy wymienione w zadaniu, kontrakty innych zespołów trzymaj w contracts/, a resztę niech ładują reguły ograniczone do plików; strona zarządzanie kontekstem w Cursorze pokazuje, jak sprawdzić, co niesie sesja.

Pętla „najpierw kontrakt”, tabela dowodów i typowe awarie są takie same w każdym narzędziu; różni się tylko mechanizm kontekstu (CLAUDE.md w Claude Code, AGENTS.md w Codeksie). Wersję tego procesu dla wszystkich narzędzi, z sagami, propagacją śladu, migracjami schematów i odpowiednimi serwerami MCP, znajdziesz na stronie rozwój systemów rozproszonych z AI.