{"id":25318,"date":"2026-06-14T02:14:27","date_gmt":"2026-06-14T02:14:27","guid":{"rendered":"https:\/\/umang.pk\/2026\/06\/14\/node-js-%d9%85%db%8c%da%ba-%d8%b3%d8%a7%da%af%d8%a7-%d9%be%db%8c%d9%b9%d8%b1%d9%86-%d9%85%d8%a7%d8%a6%db%8c%da%a9%d8%b1%d9%88-%d8%b3%d8%b1%d9%88%d8%b3%d8%b2-%d9%85%db%8c%da%ba-%d8%aa%d9%82%d8%b3\/"},"modified":"2026-06-14T02:14:27","modified_gmt":"2026-06-14T02:14:27","slug":"node-js-%d9%85%db%8c%da%ba-%d8%b3%d8%a7%da%af%d8%a7-%d9%be%db%8c%d9%b9%d8%b1%d9%86-%d9%85%d8%a7%d8%a6%db%8c%da%a9%d8%b1%d9%88-%d8%b3%d8%b1%d9%88%d8%b3%d8%b2-%d9%85%db%8c%da%ba-%d8%aa%d9%82%d8%b3","status":"publish","type":"post","link":"https:\/\/umang.pk\/ur\/2026\/06\/14\/node-js-%d9%85%db%8c%da%ba-%d8%b3%d8%a7%da%af%d8%a7-%d9%be%db%8c%d9%b9%d8%b1%d9%86-%d9%85%d8%a7%d8%a6%db%8c%da%a9%d8%b1%d9%88-%d8%b3%d8%b1%d9%88%d8%b3%d8%b2-%d9%85%db%8c%da%ba-%d8%aa%d9%82%d8%b3\/","title":{"rendered":"Node.js \u0645\u06cc\u06ba \u0633\u0627\u06af\u0627 \u067e\u06cc\u0679\u0631\u0646: \u0645\u0627\u0626\u06cc\u06a9\u0631\u0648 \u0633\u0631\u0648\u0633\u0632 \u0645\u06cc\u06ba \u062a\u0642\u0633\u06cc\u0645 \u0634\u062f\u06c1 \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u06a9\u0648 \u06a9\u06cc\u0633\u06d2 \u0648\u0627\u067e\u0633 \u06a9\u06cc\u0627 \u062c\u0627\u0626\u06d2\u06d4"},"content":{"rendered":"\n<div id=\"\">\n<p>\u0645\u062a\u0639\u062f\u062f \u0645\u0627\u0626\u06cc\u06a9\u0631\u0648 \u0633\u0631\u0648\u0633\u0632 \u0645\u06cc\u06ba \u0642\u0627\u0628\u0644 \u0627\u0639\u062a\u0645\u0627\u062f \u0648\u0631\u06a9 \u0641\u0644\u0648 \u0628\u0646\u0627\u0646\u0627 \u0645\u0634\u06a9\u0644 \u06c1\u06d2\u06d4 \u06cc\u06a9 \u0633\u0646\u06af\u06cc \u0645\u06cc\u06ba\u060c \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u06a9\u06d2 \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u0627\u0633 \u0628\u0627\u062a \u06a9\u0648 \u06cc\u0642\u06cc\u0646\u06cc \u0628\u0646\u0627 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba \u06a9\u06c1 \u0645\u062a\u0639\u062f\u062f \u0622\u067e\u0631\u06cc\u0634\u0646\u0632 \u0627\u06cc\u06a9 \u0633\u0627\u062a\u06be \u06a9\u0627\u0645\u06cc\u0627\u0628 \u06c1\u0648\u06ba \u06cc\u0627 \u0646\u0627\u06a9\u0627\u0645 \u06c1\u0648\u06ba\u06d4 \u062a\u0627\u06c1\u0645\u060c \u062c\u0628 \u0688\u06cc\u0679\u0627 \u0645\u062a\u0639\u062f\u062f \u0633\u0631\u0648\u0633\u0632 \u0627\u0648\u0631 \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u0645\u06cc\u06ba \u067e\u06be\u06cc\u0644 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u060c \u062a\u0648 \u06cc\u06c1 \u06af\u0627\u0631\u0646\u0679\u06cc \u063a\u0627\u0626\u0628 \u06c1\u0648 \u062c\u0627\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<p>\u06cc\u06c1 \u0648\u06c1 \u062c\u06af\u06c1 \u06c1\u06d2 \u062c\u06c1\u0627\u06ba \u0633\u0627\u06af\u0627 \u067e\u06cc\u0679\u0631\u0646 \u06a9\u06be\u06cc\u0644 \u0645\u06cc\u06ba \u0622\u062a\u0627 \u06c1\u06d2\u06d4 \u062a\u0642\u0633\u06cc\u0645 \u0634\u062f\u06c1 \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u06a9\u0648 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2\u060c Saga \u0645\u0642\u0627\u0645\u06cc \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u06a9\u06cc \u0627\u06cc\u06a9 \u0633\u06cc\u0631\u06cc\u0632 \u06a9\u0648 \u0645\u0631\u0628\u0648\u0637 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u062c\u0628 \u06a9\u0686\u06be \u063a\u0644\u0637 \u06c1\u0648 \u062c\u0627\u062a\u0627 \u06c1\u06d2 \u062a\u0648 \u0645\u0639\u0627\u0648\u0636\u06c1 \u06a9\u06cc \u06a9\u0627\u0631\u0631\u0648\u0627\u0626\u06cc\u0627\u06ba \u0627\u0646\u062c\u0627\u0645 \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0627\u0633 \u0645\u0636\u0645\u0648\u0646 \u0645\u06cc\u06ba\u060c \u06c1\u0645 NestJS\u060c gRPC\u060c PostgreSQL\u060c \u0627\u0648\u0631 Sequelize \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u0648\u0626\u06d2 \u0627\u06cc\u06a9 \u0645\u0631\u0628\u0648\u0637 \u0633\u0627\u06af\u0627 \u067e\u06cc\u0679\u0631\u0646 \u0628\u0646\u0627\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u0622\u067e \u06cc\u06c1 \u0633\u06cc\u06a9\u06be\u06cc\u06ba \u06af\u06d2 \u06a9\u06c1 \u06a9\u0633 \u0637\u0631\u062d \u062a\u0645\u0627\u0645 \u062e\u062f\u0645\u0627\u062a \u0645\u06cc\u06ba \u06a9\u0627\u0645 \u06a9\u0648 \u0645\u0631\u0628\u0648\u0637 \u06a9\u0631\u0646\u0627\u060c \u0627\u0646\u0639\u0627\u0645 \u067e\u0631 \u0645\u0628\u0646\u06cc \u0631\u0648\u0644 \u0628\u06cc\u06a9\u0633 \u06a9\u0648 \u0644\u0627\u06af\u0648 \u06a9\u0631\u0646\u0627\u060c \u0622\u0626\u06cc\u0688\u06cc\u0645\u067e\u0648\u0679\u06cc\u0646\u0633\u06cc \u06a9\u0648 \u06c1\u06cc\u0646\u0688\u0644 \u06a9\u0631\u0646\u0627\u060c \u0627\u0648\u0631 \u067e\u0631\u0648\u0688\u06a9\u0634\u0646 \u0637\u0631\u0632 \u06a9\u06d2 \u0645\u0627\u0626\u06cc\u06a9\u0631\u0648 \u0633\u0631\u0648\u0633 \u0622\u0631\u06a9\u06cc\u0679\u06cc\u06a9\u0686\u0631 \u0645\u06cc\u06ba \u0648\u0631\u06a9 \u0641\u0644\u0648 \u06a9\u06cc \u067e\u06cc\u0634\u0631\u0641\u062a \u06a9\u0648 \u0679\u0631\u06cc\u06a9 \u06a9\u0631\u0646\u0627 \u06c1\u06d2\u06d4<\/p>\n<h2 id=\"heading-table-of-contents\">\u0627\u0646\u0688\u06cc\u06a9\u0633<\/h2>\n<h2 id=\"heading-prerequisites\">\u0634\u0631\u0637\u06cc\u06ba<\/h2>\n<p>\u06cc\u06c1 \u0645\u0636\u0645\u0648\u0646 \u0641\u0631\u0636 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u06a9\u06c1 \u0622\u067e \u067e\u06c1\u0644\u06d2 \u0633\u06d2 \u06c1\u06cc \u06a9\u0686\u06be \u067e\u0633\u062f\u06cc\u062f \u062a\u0631\u0642\u06cc\u0627\u062a\u06cc \u062a\u0635\u0648\u0631\u0627\u062a \u0633\u06d2 \u0648\u0627\u0642\u0641 \u06c1\u06cc\u06ba\u06d4 \u0633\u0627\u06af\u0627 \u067e\u06cc\u0679\u0631\u0646 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u06a9\u0633\u06cc \u067e\u06cc\u0634\u06af\u06cc \u062a\u062c\u0631\u0628\u06d2 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u060c \u0644\u06cc\u06a9\u0646 \u0622\u067e \u06a9\u0648 \u062f\u0631\u062c \u0630\u06cc\u0644 \u0633\u06d2 \u0648\u0627\u0642\u0641 \u06c1\u0648\u0646\u0627 \u0686\u0627\u06c1\u06cc\u06d2:<\/p>\n<ul>\n<li>\n<p>JavaScript\u060c TypeScript\u060c Node.js<\/p>\n<\/li>\n<li>\n<p>NestJS \u0628\u0646\u06cc\u0627\u062f\u06cc \u0628\u0627\u062a\u06cc\u06ba (\u06a9\u0646\u0679\u0631\u0648\u0644\u0631\u0632\u060c \u062e\u062f\u0645\u0627\u062a\u060c \u0627\u0646\u062d\u0635\u0627\u0631 \u0627\u0646\u062c\u06a9\u0634\u0646)<\/p>\n<\/li>\n<li>\n<p>\u067e\u0648\u0633\u0679\u06af\u0631\u06cc \u0627\u06cc\u0633 \u06a9\u06cc\u0648 \u0627\u06cc\u0644 \u06a9\u06d2 \u0628\u0646\u06cc\u0627\u062f\u06cc \u062a\u0635\u0648\u0631\u0627\u062a<\/p>\n<\/li>\n<li>\n<p>\u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u0679\u0631\u0627\u0646\u0632\u06cc\u06a9\u0634\u0646<\/p>\n<\/li>\n<li>\n<p>\u0688\u0648\u06a9\u0631 (\u0645\u0642\u0627\u0645\u06cc \u062a\u0631\u0642\u06cc \u06a9\u06d2 \u0644\u06cc\u06d2 \u062a\u062c\u0648\u06cc\u0632 \u06a9\u0631\u062f\u06c1)<\/p>\n<\/li>\n<li>\n<p>\u0645\u0627\u0626\u06cc\u06a9\u0631\u0648 \u0633\u0631\u0648\u0633 \u0641\u0646 \u062a\u0639\u0645\u06cc\u0631 \u06a9\u06cc \u0628\u0646\u06cc\u0627\u062f\u06cc \u0628\u0627\u062a\u06cc\u06ba<\/p>\n<\/li>\n<li>\n<p>gRPC \u06a9\u06cc \u0628\u0646\u06cc\u0627\u062f\u06cc \u0628\u0627\u062a\u06cc\u06ba (\u0645\u0641\u06cc\u062f\u060c \u0644\u06cc\u06a9\u0646 \u0636\u0631\u0648\u0631\u06cc \u0646\u06c1\u06cc\u06ba)<\/p>\n<\/li>\n<\/ul>\n<p>\u0627\u06af\u0631 \u0622\u067e \u067e\u06c1\u0644\u06d2 \u06c1\u06cc NestJS \u0627\u0648\u0631 PostgreSQL \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u0648\u0626\u06d2 \u06a9\u0686\u06be \u0628\u06cc\u06a9 \u0627\u06cc\u0646\u0688 \u0633\u0631\u0648\u0633\u0632 \u0628\u0646\u0627 \u0686\u06a9\u06d2 \u06c1\u06cc\u06ba\u060c \u062a\u0648 \u0622\u067e \u06a9\u06d2 \u067e\u0627\u0633 \u0648\u06c1 \u0633\u0628 \u06a9\u0686\u06be \u06c1\u0648\u06af\u0627 \u062c\u0633 \u06a9\u06cc \u0622\u067e \u06a9\u0648 \u0627\u0633 \u06af\u0627\u0626\u06cc\u0688 \u067e\u0631 \u0639\u0645\u0644 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06c1\u06d2\u06d4<\/p>\n<h2 id=\"heading-1-introduction\">1. \u062a\u0639\u0627\u0631\u0641<\/h2>\n<p>\u06a9\u0648\u0626\u06cc \u0631\u0627\u0633\u062a\u06c1 \u0646\u06c1\u06cc\u06ba <strong>\u0645\u0648\u062a<\/strong> \u0645\u0642\u0627\u0645\u06cc \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u06a9\u0627 \u0627\u06cc\u06a9 \u0633\u0644\u0633\u0644\u06c1 \u062c\u0648 \u0645\u062a\u0639\u062f\u062f \u062e\u062f\u0645\u0627\u062a \u067e\u0631 \u0645\u062d\u06cc\u0637 \u06c1\u06d2\u06d4 \u06c1\u0631 \u0642\u062f\u0645 \u0627\u067e\u0646\u06d2 \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u06a9\u06d2 \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u06a9\u0627 \u0627\u0631\u062a\u06a9\u0627\u0628 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u0627\u06af\u0631 \u0627\u0633 \u06a9\u06d2 \u0628\u0639\u062f \u06a9\u06d2 \u0627\u0642\u062f\u0627\u0645\u0627\u062a \u0646\u0627\u06a9\u0627\u0645 \u06c1\u0648 \u062c\u0627\u062a\u06d2 \u06c1\u06cc\u06ba \u062a\u0648\u060c \u06a9\u06c1\u0627\u0646\u06cc \u0686\u0644 \u062c\u0627\u0626\u06d2 \u06af\u06cc\u06d4 <strong>\u0644\u06cc\u0646 \u062f\u06cc\u0646 \u06a9\u06d2 \u0627\u0646\u0639\u0627\u0645\u0627\u062a<\/strong> \u0645\u0639\u0646\u0648\u06cc \u0637\u0648\u0631 \u067e\u0631 \u067e\u06c1\u0644\u06d2 \u0633\u06d2 \u0637\u06d2 \u0634\u062f\u06c1 \u06a9\u0627\u0645 \u06a9\u0648 \u0645\u0646\u0633\u0648\u062e \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0627\u0633 \u067e\u06cc\u0679\u0631\u0646 \u06a9\u0648 \u067e\u06c1\u0644\u06cc \u0628\u0627\u0631 \u06c1\u06cc\u06a9\u0679\u0631 \u06af\u0627\u0631\u0633\u06cc\u0627-\u0645\u0648\u0644\u06cc\u0646\u0627 \u0627\u0648\u0631 \u06a9\u06cc\u0646\u062a\u06be \u0633\u06cc\u0644\u0645 \u0646\u06d2 1987 \u0645\u06cc\u06ba \u0637\u0648\u06cc\u0644 \u0645\u062f\u062a\u06cc \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u06a9\u06d2 \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0628\u06cc\u0627\u0646 \u06a9\u06cc\u0627 \u062a\u06be\u0627\u06d4 \u06cc\u06c1 10 \u0633\u0627\u0644 \u067e\u06c1\u0644\u06d2 \u0627\u0633 \u0648\u0642\u062a \u062f\u0648\u0628\u0627\u0631\u06c1 \u062f\u0631\u06cc\u0627\u0641\u062a \u06c1\u0648\u0627 \u062c\u0628 \u06a9\u0645\u067e\u0646\u06cc\u0648\u06ba \u0646\u06d2 \u0645\u0627\u0626\u06cc\u06a9\u0631\u0648 \u0633\u0631\u0648\u0633\u0632 \u0645\u06cc\u06ba \u06cc\u06a9 \u0633\u0646\u06af\u06cc \u06a9\u0648 \u062a\u0648\u0691\u0646\u0627 \u0634\u0631\u0648\u0639 \u06a9\u06cc\u0627 \u0627\u0648\u0631 \u0645\u062d\u0633\u0648\u0633 \u06a9\u06cc\u0627 \u06a9\u06c1 \u0627\u0646 \u06a9\u06d2 \u0628\u06cc\u06a9 \u0627\u06cc\u0646\u0688 \u0688\u0648\u06cc\u0644\u067e\u0631 \u0628\u06cc\u0644\u0679 \u0645\u06cc\u06ba \u0648\u0627\u062d\u062f \u0633\u0628 \u0633\u06d2 \u0637\u0627\u0642\u062a\u0648\u0631 \u0679\u0648\u0644\u060c \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u0679\u0631\u0627\u0646\u0632\u06cc\u06a9\u0634\u0646\u060c \u0633\u0631\u0648\u0633 \u06a9\u06cc \u062d\u062f\u0648\u062f \u0645\u06cc\u06ba \u06a9\u0627\u0645 \u0646\u06c1\u06cc\u06ba \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u06cc\u06c1 \u0645\u0636\u0645\u0648\u0646 \u0622\u067e \u06a9\u0648 \u0627\u06cc\u062c\u0646\u0633\u06cc \u06a9\u06cc \u0622\u0646 \u0628\u0648\u0631\u0688\u0646\u06af \u06a9\u06d2 \u0644\u06cc\u06d2 Node.js (NestJS + gRPC) \u0633\u06d2 \u0627\u062e\u0630 \u06a9\u0631\u062f\u06c1 \u06a9\u06c1\u0627\u0646\u06cc \u06a9\u06d2 \u0628\u0627\u0631\u06d2 \u0645\u06cc\u06ba \u0628\u062a\u0627\u062a\u0627 \u06c1\u06d2\u06d4 \u06cc\u06c1\u0627\u06ba\u060c \u062f\u0648\u0646\u0648\u06ba \u0633\u0631\u0648\u0633\u0632 \u06a9\u0627 \u0627\u06cc\u06a9 \u06c1\u06cc \u06a9\u0627\u0631\u0648\u0628\u0627\u0631\u06cc \u0646\u062a\u06cc\u062c\u06c1 \u067e\u0631 \u0645\u062a\u0641\u0642 \u06c1\u0648\u0646\u0627 \u0636\u0631\u0648\u0631\u06cc \u06c1\u06d2\u06d4<\/p>\n<ul>\n<li>\n<p><code>agency-service<\/code>    &#8211; \u0627\u06cc\u062c\u0646\u0633\u06cc \u06a9\u06d2 \u0631\u06cc\u06a9\u0627\u0631\u0688 \u06a9\u0627 \u0645\u0627\u0644\u06a9 \u06c1\u06d2\u06d4<\/p>\n<\/li>\n<li>\n<p><code>auth-service<\/code>    &#8211; \u062a\u0646\u0638\u06cc\u0645\u0648\u06ba\u060c \u0635\u0627\u0631\u0641\u06cc\u0646 \u0627\u0648\u0631 \u06a9\u0631\u062f\u0627\u0631\u0648\u06ba \u06a9\u0627 \u0645\u0627\u0644\u06a9 \u06c1\u06d2\u06d4<\/p>\n<\/li>\n<\/ul>\n<p>\u0627\u06af\u0631 \u06cc\u0627 \u062a\u0648 \u0646\u0627\u06a9\u0627\u0645 \u06c1\u0648 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u060c \u062a\u0648 \u0633\u0633\u0679\u0645 \u06a9\u0648 \u0628\u0646\u062f \u06a9\u0631 \u062f\u06cc\u0646\u0627 \u0686\u0627\u06c1\u06cc\u06d2 \u062c\u06cc\u0633\u06d2 \u06a9\u0686\u06be \u06c1\u0648\u0627 \u06c1\u06cc \u0646\u06c1\u06cc\u06ba\u06d4 \u06a9\u0648\u0626\u06cc \u0622\u062f\u06be\u06d2 \u062a\u062e\u0644\u06cc\u0642 \u0634\u062f\u06c1 \u0635\u0627\u0631\u0641\u060c \u06cc\u062a\u06cc\u0645 \u062a\u0646\u0638\u06cc\u0645\u06cc\u06ba\u060c \u06cc\u0627 3am Slack \u062f\u06be\u0627\u06af\u06d2 \u0646\u06c1\u06cc\u06ba\u06d4<\/p>\n<h2 id=\"heading-2-the-problem-in-one-picture\">2. \u0627\u06cc\u06a9 \u062a\u0635\u0648\u06cc\u0631 \u0645\u06cc\u06ba \u0645\u0633\u0627\u0626\u0644<\/h2>\n<p>\u06a9\u06cc\u0691\u06d2 \u062c\u0648 \u0631\u0648\u06a9\u0646\u06d2 \u06a9\u06d2 \u0644\u0626\u06d2 \u0628\u0646\u0627\u0626\u06d2 \u06af\u0626\u06d2 \u06c1\u06cc\u06ba \u0648\u06c1 \u06c1\u06cc\u06ba:<\/p>\n<pre><code class=\"language-plaintext\">Step 1: auth-service     &#x2705; creates Organization #42\nStep 2: auth-service     &#x2705; creates User #99\nStep 3: agency-service   &#x274c; fails (DB down, validation, network blip\u2026)\n\nResult without a saga:\n   Organization #42 and User #99 still exist.\n   There is no Agency row.\n   The user can log in but has nothing to manage.\n   Support gets a ticket. Engineer writes a one-off SQL cleanup.\n   Repeat every week.\n<\/code><\/pre>\n<p>\u0633\u0627\u06af\u0627 \u06a9\u0627 \u0645\u0634\u0646 \u06cc\u06c1 \u067e\u062a\u06c1 \u0644\u06af\u0627\u0646\u0627 \u06c1\u06d2 \u06a9\u06c1 \u0641\u06cc\u0632 3 \u0646\u0627\u06a9\u0627\u0645 \u06c1\u0648 \u06af\u06cc\u0627 \u06c1\u06d2 \u0627\u0648\u0631 <strong>\u062a\u0646\u0638\u06cc\u0645 #42 \u0627\u0648\u0631 \u0635\u0627\u0631\u0641 #99 \u06a9\u0648 \u0648\u0627\u0636\u062d \u0637\u0648\u0631 \u067e\u0631 \u062d\u0630\u0641 \u06a9\u0631\u06cc\u06ba\u06d4<\/strong>\u0644\u06c1\u0630\u0627 \u0633\u0633\u0679\u0645 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0645\u0633\u062a\u0642\u0644 \u06c1\u06d2\u060c \u0686\u0627\u06c1\u06d2 \u0648\u06c1 \u0642\u0637\u0627\u0631 \u06a9\u0633\u06cc \u0627\u0648\u0631 \u0633\u0631\u0648\u0633 \u06a9\u06d2 \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u0645\u06cc\u06ba \u06c1\u0648\u06d4<\/p>\n<h2 id=\"heading-3-why-you-need-a-saga\">3. \u0622\u067e \u06a9\u0648 \u0627\u06cc\u06a9 \u06a9\u06c1\u0627\u0646\u06cc \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06a9\u06cc\u0648\u06ba \u06c1\u06d2\u06d4<\/h2>\n<p>\u06cc\u06a9 \u0633\u0646\u06af\u06cc \u0645\u06cc\u06ba\u060c \u0622\u067e \u06c1\u0631 \u0686\u06cc\u0632 \u06a9\u0648 \u0627\u06cc\u06a9 DB \u0679\u0631\u0627\u0646\u0632\u06cc\u06a9\u0634\u0646 \u0645\u06cc\u06ba \u0644\u067e\u06cc\u0679 \u062f\u06cc\u062a\u06d2 \u06c1\u06cc\u06ba \u0627\u0648\u0631 \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u06a9\u0648 \u0627\u06cc\u0679\u0645\u06cc\u0633\u06cc\u0679\u06cc \u06a9\u0648 \u0633\u0646\u0628\u06be\u0627\u0644\u0646\u06d2 \u062f\u06cc\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-ts\">await sequelize.transaction(async (tx) => {\n  await Organization.create({...}, { transaction: tx });\n  await User.create({...}, { transaction: tx });\n  await Agency.create({...}, { transaction: tx });\n});\n<\/code><\/pre>\n<p>\u0645\u0627\u0626\u06cc\u06a9\u0631\u0648 \u0633\u0631\u0648\u0633\u0632 \u0645\u06cc\u06ba\u060c \u06c1\u0631 \u0633\u0631\u0648\u0633 \u06a9\u0627 \u0627\u067e\u0646\u0627 \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u06c1\u0648\u062a\u0627 \u06c1\u06d2\u06d4 \u0622\u067e \u0627\u06cc\u06a9 ACID \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u0645\u06cc\u06ba \u062f\u0648 \u062e\u062f\u0645\u0627\u062a \u06a9\u0648 \u0644\u067e\u06cc\u0679 \u0646\u06c1\u06cc\u06ba \u0633\u06a9\u062a\u06d2\u06d4 \u06a9\u0644\u0627\u0633\u06a9 \u0645\u062a\u0628\u0627\u062f\u0644 \u0645\u06cc\u06ba \u062a\u0645\u0627\u0645 \u0645\u0633\u0627\u0626\u0644 \u06c1\u06cc\u06ba\u06d4<\/p>\n<table>\n<thead>\n<tr>\n<th>\u0627\u062e\u062a\u06cc\u0627\u0631\u0627\u062a<\/th>\n<th>\u0645\u0633\u0626\u0644\u06c1<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><strong>\u062f\u0648 \u0641\u06cc\u0632 \u06a9\u0645\u0679 (2PC)<\/strong><\/td>\n<td>\u0622\u067e \u067e\u0648\u0631\u06cc \u0633\u0631\u0648\u0633 \u0645\u06cc\u06ba \u0642\u0637\u0627\u0631\u0648\u06ba \u06a9\u0648 \u0645\u0642\u0641\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba \u0627\u0648\u0631 \u06a9\u0648\u0622\u0631\u0688\u06cc\u0646\u06cc\u0679\u0631 \u0646\u0627\u06a9\u0627\u0645\u06cc \u06a9\u0627 \u0648\u0627\u062d\u062f \u0646\u0642\u0637\u06c1 \u06c1\u06d2 \u0627\u0648\u0631 \u0627\u0633\u06a9\u06cc\u0644 \u0646\u06c1\u06cc\u06ba \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u0632\u06cc\u0627\u062f\u06c1 \u062a\u0631 \u062c\u062f\u06cc\u062f \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 HTTP\/gRPC \u06a9\u0648 \u0635\u062d\u06cc\u062d \u0637\u0631\u06cc\u0642\u06d2 \u0633\u06d2 \u0633\u067e\u0648\u0631\u0679 \u0646\u06c1\u06cc\u06ba \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/td>\n<\/tr>\n<tr>\n<td><strong>&quot;\u0645\u06cc\u06ba \u0635\u0631\u0641 \u0627\u0645\u06cc\u062f \u06a9\u0631\u062a\u0627 \u06c1\u0648\u06ba \u06a9\u06c1 \u06cc\u06c1 \u06a9\u0627\u0645 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4&#8221;<\/strong><\/td>\n<td>\u0627\u06af\u0631 \u0646\u0635\u0641 \u0628\u06c1\u0627\u0624 \u0646\u0627\u06a9\u0627\u0645 \u06c1\u0648\u062c\u0627\u062a\u0627 \u06c1\u06d2\u060c \u062a\u0648 \u06cc\u06c1 \u06cc\u062a\u06cc\u0645 \u0635\u0627\u0631\u0641\/\u0628\u0644\u0646\u06af \u0642\u0637\u0627\u0631\u0648\u06ba \u06a9\u0648 \u0686\u06be\u0648\u0691 \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u06d4 \u0627\u0635\u0644 \u0688\u06cc\u0679\u0627 \u06a9\u06cc \u0628\u062f\u0639\u0646\u0648\u0627\u0646\u06cc &#8211; \u062c\u062a\u0646\u0627 \u0637\u0648\u06cc\u0644 \u0646\u0638\u0627\u0645 \u0686\u0644\u062a\u0627 \u06c1\u06d2\u060c \u0627\u062a\u0646\u06d2 \u06c1\u06cc \u0632\u06cc\u0627\u062f\u06c1 \u06cc\u062a\u06cc\u0645 \u062c\u0645\u0639 \u06c1\u0648\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/td>\n<\/tr>\n<tr>\n<td><strong>\u062f\u0633\u062a\u06cc \u0635\u0641\u0627\u0626\u06cc \u06a9\u0627 \u0627\u0633\u06a9\u0631\u067e\u0679<\/strong><\/td>\n<td>\u06cc\u06c1 \u0627\u06cc\u06a9 \u06c1\u0641\u062a\u06d2 \u062a\u06a9 \u06a9\u0627\u0645 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u06a9\u06cc\u0691\u06d2 \u0645\u06c1\u06cc\u0646\u0648\u06ba \u062a\u06a9 \u0686\u06be\u067e \u062c\u0627\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u0646\u0626\u06d2 \u0627\u0646\u062c\u06cc\u0646\u0626\u0631 \u0646\u06c1\u06cc\u06ba \u062c\u0627\u0646\u062a\u06d2 \u06a9\u06c1 \u0648\u06c1 \u0645\u0648\u062c\u0648\u062f \u06c1\u06cc\u06ba\u06d4<\/td>\n<\/tr>\n<tr>\n<td><strong>\u0645\u0639\u0627\u0648\u0636\u06c1 \u06a9\u06d2 \u0628\u063a\u06cc\u0631 \u062d\u062a\u0645\u06cc \u0645\u0633\u062a\u0642\u0644 \u0645\u0632\u0627\u062c\u06cc<\/strong><\/td>\n<td>\u06cc\u06c1 \u06a9\u0686\u06be \u0688\u0648\u0645\u06cc\u0646\u0632 (\u062a\u062c\u0632\u06cc\u06c1) \u06a9\u06d2 \u0644\u06cc\u06d2 \u0679\u06be\u06cc\u06a9 \u06c1\u06d2\u060c \u0644\u06cc\u06a9\u0646 \u0628\u0644\u0646\u06af\u060c \u0634\u0646\u0627\u062e\u062a\u060c \u06cc\u0627 \u0631\u0642\u0645 \u0633\u06d2 \u0645\u062a\u0639\u0644\u0642 \u06a9\u0633\u06cc \u0628\u06be\u06cc \u0686\u06cc\u0632 \u06a9\u06d2 \u0644\u06cc\u06d2\u060c \u06cc\u06c1 \u0628\u0627\u0644\u06a9\u0644 \u063a\u0644\u0637 \u06c1\u06d2\u06d4<\/td>\n<\/tr>\n<tr>\n<td><strong>\u0633\u0627\u06af\u0627 \u067e\u06cc\u0679\u0631\u0646<\/strong><\/td>\n<td>\u06c1\u0631 \u062e\u062f\u0645\u062a \u0645\u0642\u0627\u0645\u06cc \u0637\u0648\u0631 \u067e\u0631 \u0627\u0646\u062c\u0627\u0645 \u062f\u06cc\u062a\u06cc \u06c1\u06d2\u06d4 \u0622\u0631\u06a9\u06cc\u0633\u0679\u0631\u06cc\u0679\u0631 \u0648\u0631\u06a9 \u0641\u0644\u0648 \u06a9\u0627 \u0645\u0627\u0644\u06a9 \u06c1\u06d2 \u0627\u0648\u0631 \u0646\u0627\u06a9\u0627\u0645\u06cc \u06a9\u06cc \u0635\u0648\u0631\u062a \u0645\u06cc\u06ba \u0648\u0627\u0636\u062d \u0627\u0646\u0639\u0627\u0645\u0627\u062a \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u06d4 \u06cc\u06c1 \u0642\u0627\u0628\u0644 \u0633\u0645\u0627\u0639\u062a\u060c \u062f\u0648\u0628\u0627\u0631\u06c1 \u0634\u0631\u0648\u0639 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0642\u0627\u0628\u0644\u060c \u0627\u0648\u0631 \u0645\u0639\u0642\u0648\u0644 \u06c1\u06d2\u06d4<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\u06cc\u06c1 \u0633\u0644\u0633\u0644\u06c1 \u062a\u0642\u0633\u06cc\u0645 \u0634\u062f\u06c1 \u0644\u0627\u06a9\u0646\u06af \u06a9\u06d2 \u0628\u063a\u06cc\u0631 \u0648\u0627\u0636\u062d\u060c \u0642\u0627\u0628\u0644 \u0633\u0645\u0627\u0639\u062a \u0631\u0648\u0644 \u0628\u06cc\u06a9 \u067e\u0627\u062a\u06be \u06a9\u06d2 \u0633\u0627\u062a\u06be \u062d\u062a\u0645\u06cc \u0645\u0633\u062a\u0642\u0644 \u0645\u0632\u0627\u062c\u06cc \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<h2 id=\"heading-4-choreography-vs-orchestration\">4. \u06a9\u0648\u0631\u06cc\u0648\u06af\u0631\u0627\u0641\u06cc \u0628\u0645\u0642\u0627\u0628\u0644\u06c1 \u0622\u0631\u06a9\u06cc\u0633\u0679\u0631\u06cc\u0634\u0646<\/h2>\n<p>\u0633\u0627\u06af\u0627 \u06a9\u0648 \u0646\u0627\u0641\u0630 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u062f\u0648 \u0637\u0631\u06cc\u0642\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<h3 id=\"heading-choreography\">\u06a9\u0648\u0631\u06cc\u0648\u06af\u0631\u0627\u0641\u06cc\u06d4<\/h3>\n<p>\u06a9\u0648\u0631\u06cc\u0648\u06af\u0631\u0627\u0641\u06cc \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2\u060c \u062e\u062f\u0645\u0627\u062a \u0648\u0627\u0642\u0639\u0627\u062a \u06a9\u0648 \u062e\u0627\u0631\u062c \u06a9\u0631\u062a\u06cc \u06c1\u06cc\u06ba \u0627\u0648\u0631 \u062f\u06cc\u06af\u0631 \u062e\u062f\u0645\u0627\u062a \u0633\u0628\u0633\u06a9\u0631\u0627\u0626\u0628 \u06a9\u0631\u062a\u06cc \u06c1\u06cc\u06ba \u0627\u0648\u0631 \u0631\u062f\u0639\u0645\u0644 \u0638\u0627\u06c1\u0631 \u06a9\u0631\u062a\u06cc \u06c1\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-plaintext\">auth-service \u2192 emits \"UserCreated\"\nagency-service \u2192 listens, creates agency, emits \"AgencyCreated\"\nbilling-service \u2192 listens, creates subscription\u2026\n<\/code><\/pre>\n<p>\u0634\u0631\u0648\u0639 \u0645\u06cc\u06ba \u0633\u0627\u062f\u06c1 \u0645\u06af\u0631 \u0628\u0639\u062f \u0645\u06cc\u06ba \u0646\u0627\u0632\u06a9\u06d4 \u0648\u0631\u06a9 \u0641\u0644\u0648 N \u06a9\u0648\u0688 \u0628\u06cc\u0633\u0632 \u0645\u06cc\u06ba \u062a\u0642\u0633\u06cc\u0645 \u06a9\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4 \u06a9\u0648\u0626\u06cc \u0628\u06be\u06cc \u0627\u0633 \u06a9\u0627 \u0645\u0627\u0644\u06a9 \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4 \u0688\u06cc\u0628\u06af\u0646\u06af \u06a9\u0627 \u0645\u0637\u0644\u0628 \u06c1\u06d2 \u067e\u0648\u0631\u06d2 \u0644\u0627\u06af \u0645\u06cc\u06ba \u0648\u0627\u0642\u0639\u0627\u062a \u06a9\u0627 \u0633\u0631\u0627\u063a \u0644\u06af\u0627\u0646\u0627\u06d4 \u0627\u0642\u062f\u0627\u0645\u0627\u062a \u0634\u0627\u0645\u0644 \u06a9\u0631\u0646\u06d2 \u06a9\u0627 \u0645\u0637\u0644\u0628 \u06c1\u06d2 \u0645\u062a\u0639\u062f\u062f \u062e\u062f\u0645\u0627\u062a \u06a9\u0648 \u062a\u0628\u062f\u06cc\u0644 \u06a9\u0631\u0646\u0627\u06d4<\/p>\n<h3 id=\"heading-orchestration\">\u0622\u0631\u06a9\u06cc\u0633\u0679\u0631\u06cc\u0634\u0646<\/h3>\n<p>\u0622\u0631\u06a9\u06cc\u0633\u0679\u0631\u06cc\u0634\u0646 \u0645\u06cc\u06ba\u060c \u0627\u06cc\u06a9 \u062e\u062f\u0645\u062a \u06a9\u0646\u0688\u06a9\u0679\u0631 \u06c1\u06d2\u06d4 \u0628\u0627\u0631\u06cc \u0628\u0627\u0631\u06cc \u062f\u0648\u0633\u0631\u0648\u06ba \u06a9\u0648 \u0628\u0644\u0627\u0626\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-plaintext\">orchestrator:\n   1. authClient.provisionAccount(...)\n   2. agencyRepo.create(...)\n   3. authClient.sendWelcomeEmail(...)\n<\/code><\/pre>\n<p>\u06cc\u06c1\u0627\u06ba \u06a9\u0686\u06be \u0627\u0648\u0631 \u062c\u0648\u0691\u06d2 \u06c1\u06cc\u06ba (\u0622\u0631\u06a9\u06cc\u0633\u0679\u0631\u06cc\u0679\u0631 \u06a9\u0648 \u06a9\u0644\u0627\u0626\u0646\u0679 \u0645\u0644 \u062c\u0627\u062a\u0627 \u06c1\u06d2)\u060c \u0644\u06cc\u06a9\u0646 \u067e\u0648\u0631\u0627 \u0648\u0631\u06a9 \u0641\u0644\u0648 \u0627\u06cc\u06a9 \u0641\u0627\u0626\u0644 \u0645\u06cc\u06ba \u06c1\u06d2\u06d4 \u0627\u06cc\u06a9 \u0646\u0626\u06d2 \u0627\u0646\u062c\u06cc\u0646\u0626\u0631 \u06a9\u0648 \u062c\u06c1\u0627\u0632 \u0645\u06cc\u06ba \u0644\u0627\u0646\u06d2 \u0645\u06cc\u06ba \u0627\u06cc\u06a9 \u06af\u06be\u0646\u0679\u06c1 \u0644\u06af\u062a\u0627 \u06c1\u06d2\u06d4 \u0627\u06cc\u06a9 \u0642\u062f\u0645 \u0634\u0627\u0645\u0644 \u06a9\u0631\u0646\u0627 \u0627\u06cc\u06a9 \u0648\u0627\u062d\u062f PR \u06c1\u06d2\u06d4<\/p>\n<p><strong>\u062c\u0628 \u062a\u06a9 \u06a9\u06c1 \u0622\u067e \u06a9\u06d2 \u067e\u0627\u0633 \u0646\u06c1 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0632\u0628\u0631\u062f\u0633\u062a \u0648\u062c\u06c1 \u0646\u06c1 \u06c1\u0648\u060c \u0622\u0631\u06a9\u06cc\u0633\u0679\u0631\u06cc\u0634\u0646 \u06a9\u0627 \u0627\u0646\u062a\u062e\u0627\u0628 \u06a9\u0631\u06cc\u06ba\u06d4<\/strong> \u06cc\u06c1 \u0645\u0636\u0645\u0648\u0646 \u0627\u0648\u0631 \u062d\u0648\u0627\u0644\u06c1 \u0639\u0645\u0644 \u0622\u0631\u06a9\u06cc\u0633\u0679\u0631\u06cc\u0634\u0646 \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<h2 id=\"heading-5-the-example-project\">5. \u0645\u062b\u0627\u0644 \u067e\u0631\u0648\u062c\u06cc\u06a9\u0679<\/h2>\n<p>\u06cc\u06c1\u0627\u06ba \u06c1\u0645\u0627\u0631\u0627 \u0645\u0642\u0635\u062f \u0633\u0633\u0679\u0645 \u0645\u06cc\u06ba \u0627\u06cc\u062c\u0646\u0633\u06cc \u0628\u0646\u0627\u0646\u0627 \u06c1\u06d2\u06d4 \u06cc\u06c1 \u0648\u06c1 \u0644\u0645\u062d\u06c1 \u06c1\u06d2 \u062c\u0628 \u0627\u06cc\u06a9 \u0646\u06cc\u0627 B2B \u06a9\u0633\u0679\u0645\u0631 \u0633\u0627\u0626\u0646 \u0627\u067e \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0627\u06cc\u06a9 \u0646\u062a\u06cc\u062c\u06c1 \u067e\u0631 \u0645\u062a\u0641\u0642 \u06c1\u0648\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u062f\u0648 \u062e\u062f\u0645\u0627\u062a \u062f\u0631\u06a9\u0627\u0631 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p><code>auth-service<\/code> <strong>\u0622\u067e \u06a9\u0648 \u062a\u062e\u0644\u06cc\u0642 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06c1\u0648\u06af\u06cc:<\/strong><\/p>\n<ul>\n<li>\n<p>\u0646\u06c1\u06cc\u06ba <code>Organization<\/code> \u0642\u0637\u0627\u0631 (\u06a9\u0631\u0627\u06cc\u06c1 \u062f\u0627\u0631)<\/p>\n<\/li>\n<li>\n<p>\u06a9\u0648\u0626\u06cc \u0631\u0627\u0633\u062a\u06c1 \u0646\u06c1\u06cc\u06ba <code>User<\/code> \u0642\u0637\u0627\u0631 (\u0644\u0627\u06af \u0627\u0646 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u06cc\u062c\u0646\u0633\u06cc \u0645\u06cc\u0646\u06cc\u062c\u0631)<\/p>\n<\/li>\n<li>\n<p>\u06a9\u0648\u0626\u06cc \u0631\u0627\u0633\u062a\u06c1 \u0646\u06c1\u06cc\u06ba <code>UserRole<\/code> \u0635\u0627\u0631\u0641 <code>AGENCY_ADMIN<\/code> \u06a9\u0631\u062f\u0627\u0631<\/p>\n<\/li>\n<\/ul>\n<p><code>agency-service<\/code> <strong>\u0622\u067e \u06a9\u0648 \u062a\u062e\u0644\u06cc\u0642 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06c1\u0648\u06af\u06cc:<\/strong><\/p>\n<ul>\n<li>\u0646\u06c1\u06cc\u06ba <code>Agency<\/code> \u06a9\u0627\u0631\u0648\u0628\u0627\u0631\u06cc \u062a\u0641\u0635\u06cc\u0644\u0627\u062a \u067e\u0631 \u0645\u0634\u062a\u0645\u0644 \u0642\u0637\u0627\u0631\u06cc\u06ba (\u0633\u0627\u0626\u0632\u060c \u0631\u062c\u0633\u0679\u0631\u06cc\u0634\u0646 \u0646\u0645\u0628\u0631\u060c \u0648\u06cc\u0628 \u0633\u0627\u0626\u0679\u060c \u0628\u0631\u0627\u0646\u0686\u2026) \u0627\u0648\u067e\u0631 \u0635\u0627\u0631\u0641\/\u062a\u0646\u0638\u06cc\u0645 \u0633\u06d2 \u0645\u0646\u0633\u0644\u06a9 \u06c1\u06cc\u06ba\u06d4<\/li>\n<\/ul>\n<p>\u0627\u0633 \u0642\u0637\u0627\u0631 \u06a9\u0627 \u0627\u06cc\u06a9 \u063a\u06cc\u0631 \u0645\u0644\u06a9\u06cc \u06a9\u0644\u06cc\u062f\u06cc \u062a\u0639\u0644\u0642 \u06c1\u06d2\u06d4 <em>\u06a9\u06d2 \u0627\u0646\u062f\u0631<\/em> \u0627\u06af\u0631\u0686\u06c1 \u06cc\u06c1 \u0627\u06cc\u06a9 \u062e\u062f\u0645\u062a \u06c1\u06d2\u060c <em>~ \u0646\u06c1\u06cc\u06ba<\/em> \u062a\u0645\u0627\u0645 \u062e\u062f\u0645\u0627\u062a &#8211; \u067e\u0648\u0633\u0679\u06af\u0631\u06cc\u0633 \u0627\u0633 \u0628\u0627\u062a \u06a9\u0648 \u06cc\u0642\u06cc\u0646\u06cc \u0628\u0646\u0627\u062a\u0627 \u06c1\u06d2 \u06a9\u06c1 \u062a\u0635\u062f\u06cc\u0642 \u0634\u062f\u06c1 DB \u0645\u06cc\u06ba \u0635\u0627\u0631\u0641\u06cc\u0646 <code>authUserId<\/code> \u06cc\u06c1 \u0627\u06cc\u062c\u0646\u0633\u06cc DB \u0645\u06cc\u06ba \u06c1\u06d2\u06d4 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u0648 \u06cc\u06c1 \u06a9\u0631\u0646\u0627 \u06c1\u0648\u06af\u0627\u06d4<\/p>\n<pre><code class=\"language-plaintext\">auth-service DB                    agency-service DB\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500                  \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\norganizations  \u25c4\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n   \u2502                    \u2502\n   \u2502 (1:1)              \u2502   foreign reference (no FK)\n   \u25bc                    \u2502           agencies\nusers  \u2500\u2500\u2500\u2500\u2500\u2500\u25ba user_roles                     \u2500 authUserId\n                                              \u2514 authOrganizationId\n<\/code><\/pre>\n<p>\u0627\u06af\u0631 \u0645\u0631\u062d\u0644\u06c1 2 \u0646\u0627\u06a9\u0627\u0645 \u06c1\u0648\u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4 <em>~ \u0628\u0639\u062f<\/em> \u0627\u06af\u0631 \u0645\u0631\u062d\u0644\u06c1 1 \u06a9\u0627\u0645\u06cc\u0627\u0628 \u06c1\u0648 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u060c \u062a\u0648 \u0622\u067e \u06a9\u06d2 \u067e\u0627\u0633 \u0627\u06cc\u06a9 \u0635\u0627\u0631\u0641 \u0631\u06c1 \u062c\u0627\u0626\u06d2 \u06af\u0627 \u062c\u0648 \u062a\u0635\u062f\u06cc\u0642 \u06a9\u0631 \u0633\u06a9\u062a\u0627 \u06c1\u06d2 \u0644\u06cc\u06a9\u0646 \u0627\u0633 \u06a9\u06cc \u06a9\u0648\u0626\u06cc \u0627\u06cc\u062c\u0646\u0633\u06cc \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4 \u0645\u0631\u062d\u0644\u06c1 2 \u0645\u06cc\u06ba \u0628\u0627\u0644\u06a9\u0644 \u06cc\u06c1\u06cc \u0628\u06af \u06c1\u06d2\u06d4 \u06cc\u06c1 \u0628\u0627\u0644\u06a9\u0644 \u0648\u06c1\u06cc \u06c1\u06d2 \u062c\u0633\u06d2 \u06cc\u06c1 \u06a9\u06c1\u0627\u0646\u06cc \u0631\u0648\u06a9\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<h2 id=\"heading-6-architecture\">6. \u0641\u0646 \u062a\u0639\u0645\u06cc\u0631<\/h2>\n<pre><code class=\"language-plaintext\">                     \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n                     \u2502        API Gateway            \u2502\n                     \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                                    \u2502 HTTP\n                                    \u25bc\n   \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n   \u2502              agency-service                      \u2502\n   \u2502   \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u2502\n   \u2502   \u2502   AgencyOnboardingOrchestrator (SAGA)   \u2502    \u2502\n   \u2502   \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2502\n   \u2502                   \u2502 writes state                 \u2502\n   \u2502                   \u25bc                              \u2502\n   \u2502      agency_onboarding_sagas  (Postgres)         \u2502\n   \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                   \u2502 gRPC            \u2502 gRPC\n       provisionAgencyAccount   compensateAgencyAccount\n                   \u2502                 \u2502\n                   \u25bc                 \u25bc\n   \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n   \u2502              auth-service                        \u2502\n   \u2502   AgencyProvisioningService  (Participant)       \u2502\n   \u2502                                                  \u2502\n   \u2502   organizations \u00b7 users \u00b7 user_roles             \u2502\n   \u2502   agency_provision_records  \u2190 idempotency log    \u2502\n   \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n<\/code><\/pre>\n<p>\u062a\u06cc\u0646 \u0627\u062c\u0632\u0627\u0621 \u062a\u0645\u0627\u0645 \u06a9\u0627\u0645 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<ol>\n<li>\n<p><code>AgencyOnboardingOrchestrator<\/code>    \u06a9\u0648 <code>agency-service<\/code> &#8211; \u0648\u0631\u06a9 \u0641\u0644\u0648 \u06a9\u0648 \u0686\u0644\u0627\u0626\u06cc\u06ba\u06d4<\/p>\n<\/li>\n<li>\n<p><code>agency_onboarding_sagas<\/code>    \u0645\u06cc\u06ba \u0645\u06cc\u0632 <code>agency-service<\/code> &#8211; \u06a9\u06c1\u0627\u0646\u06cc \u06a9\u06cc \u062a\u0631\u0642\u06cc \u06a9\u0627 \u0627\u06cc\u06a9 \u067e\u0627\u0626\u06cc\u062f\u0627\u0631 \u0644\u0627\u06af\u06d4<\/p>\n<\/li>\n<li>\n<p><code>AgencyProvisioningService<\/code>    \u06a9\u0648 <code>auth-service<\/code> &#8211; \u0627\u06cc\u06a9\u0633\u067e\u0648\u0698\u0631 <code>do<\/code> \u06a9\u0627\u0645 (<code>provisionAgencyAccount<\/code>) \u0627\u0648\u0631 <code>undo<\/code> \u06a9\u0627\u0645 (<code>compensateAgencyAccount<\/code>)\u06d4 \u06cc\u06c1 \u062e\u0648\u062f \u0645\u0639\u0627\u0648\u0646 \u06c1\u06d2\u06d4 <code>agency_provision_records<\/code> \u0628\u06d2 \u062d\u0633 \u0679\u06cc\u0628\u0644\u06d4<\/p>\n<\/li>\n<\/ol>\n<p>\u0622\u0631\u06a9\u06cc\u0633\u0679\u0631\u06cc\u0679\u0631 \u062a\u0648\u062b\u06cc\u0642 \u06a9\u06d2 \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u062a\u06a9 \u0628\u0631\u0627\u06c1 \u0631\u0627\u0633\u062a \u0631\u0633\u0627\u0626\u06cc \u0646\u06c1\u06cc\u06ba \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u062d\u062f\u0648\u062f gRPC \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u0646\u0627\u0641\u0630 \u06a9\u06cc \u062c\u0627\u062a\u06cc \u06c1\u06cc\u06ba\u06d4<\/p>\n<h2 id=\"heading-7-the-saga-flow-step-by-step\">7. \u0633\u0627\u06af\u0627 \u0641\u0644\u0648\u060c \u0642\u062f\u0645 \u0628\u06c1 \u0642\u062f\u0645<\/h2>\n<p>\u06cc\u06c1 \u062a\u0631\u062a\u06cc\u0628 \u06a9\u0627 \u062e\u0627\u06a9\u06c1 \u0622\u0646 \u0628\u0648\u0631\u0688\u0646\u06af \u0633\u0627\u06af\u0627 \u06a9\u0627 \u0645\u06a9\u0645\u0644 \u0644\u0627\u0626\u0641 \u0633\u0627\u0626\u06cc\u06a9\u0644 \u062f\u06a9\u06be\u0627\u062a\u0627 \u06c1\u06d2\u06d4 \u0648\u0631\u06a9 \u0641\u0644\u0648 \u0627\u0633 \u0648\u0642\u062a \u0634\u0631\u0648\u0639 \u06c1\u0648\u062a\u0627 \u06c1\u06d2 \u062c\u0628 \u06a9\u0648\u0626\u06cc \u06a9\u0644\u0627\u0626\u0646\u0679 \u0627\u06cc\u06a9 \u0646\u0626\u06cc \u0627\u06cc\u062c\u0646\u0633\u06cc \u0628\u0646\u0627\u0646\u06d2 \u06a9\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u0628\u06be\u06cc\u062c\u062a\u0627 \u06c1\u06d2\u06d4 \u0622\u0631\u06a9\u06cc\u0633\u0679\u0631\u06cc\u0679\u0631 \u0633\u0628 \u0633\u06d2 \u067e\u06c1\u0644\u06d2 \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u0645\u06cc\u06ba \u0633\u0627\u06af\u0627 \u0631\u06cc\u06a9\u0627\u0631\u0688 \u0628\u0646\u0627\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0627\u0633\u06d2 \u0627\u0633 \u0637\u0631\u062d \u062f\u06a9\u06be\u0627\u062a\u0627 \u06c1\u06d2: <code>STARTED<\/code>\u06a9\u0627\u0631\u0648\u0628\u0627\u0631\u06cc \u06a9\u0627\u0645\u0648\u06ba \u06a9\u0648 \u0627\u0646\u062c\u0627\u0645 \u062f\u06cc\u0646\u06d2 \u0633\u06d2 \u067e\u06c1\u0644\u06d2 \u0648\u0631\u06a9 \u0641\u0644\u0648 \u06a9\u0627 \u0645\u0633\u0644\u0633\u0644 \u0631\u06cc\u06a9\u0627\u0631\u0688 \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0627\u0639\u0644\u06cc\u0670 \u0633\u0637\u062d \u067e\u0631\u060c \u0622\u0631\u06a9\u06cc\u0633\u0679\u0631\u06cc\u0679\u0631 \u0627\u06cc\u06a9 \u0633\u0627\u06af\u0627 \u0631\u06cc\u06a9\u0627\u0631\u0688 \u0628\u0646\u0627 \u06a9\u0631 \u0634\u0631\u0648\u0639 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u067e\u06be\u0631 \u067e\u0648\u0686\u06be\u062a\u0627 \u06c1\u06d2: <code>auth-service<\/code> \u062a\u0646\u0638\u06cc\u0645\u0648\u06ba\u060c \u0635\u0627\u0631\u0641\u06cc\u0646\u060c \u0627\u0648\u0631 \u06a9\u0631\u062f\u0627\u0631\u0648\u06ba \u06a9\u06cc \u0641\u0631\u0627\u06c1\u0645\u06cc\u06d4 \u0627\u06af\u0631 \u06a9\u0627\u0645\u06cc\u0627\u0628 \u06c1\u0648 \u062a\u0648 \u0622\u0631\u06a9\u06cc\u0633\u0679\u0631\u06cc\u0679\u0631 \u0627\u067e\u0646\u06d2 \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u0645\u06cc\u06ba \u0627\u06cc\u062c\u0646\u0633\u06cc \u06a9\u0627 \u0631\u06cc\u06a9\u0627\u0631\u0688 \u0628\u0646\u0627\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0627\u06af\u0631 \u062a\u0645\u0627\u0645 \u0627\u0642\u062f\u0627\u0645\u0627\u062a \u06a9\u0627\u0645\u06cc\u0627\u0628 \u06c1\u06cc\u06ba \u062a\u0648\u060c \u06a9\u06c1\u0627\u0646\u06cc \u06c1\u06d2 <code>COMPLETED<\/code> \u0635\u0648\u0631\u062a \u062d\u0627\u0644 \u0627\u06af\u0631 \u062a\u0635\u062f\u06cc\u0642\u06cc \u0648\u0633\u06cc\u0644\u06c1 \u067e\u06c1\u0644\u06d2 \u0633\u06d2 \u06c1\u06cc \u062a\u062e\u0644\u06cc\u0642 \u06c1\u0648\u0646\u06d2 \u06a9\u06d2 \u0628\u0639\u062f \u0627\u06cc\u062c\u0646\u0633\u06cc \u06a9\u06cc \u062a\u062e\u0644\u06cc\u0642 \u0646\u0627\u06a9\u0627\u0645 \u06c1\u0648 \u062c\u0627\u062a\u06cc \u06c1\u06d2\u060c \u062a\u0648 \u0622\u0631\u06a9\u06cc\u0633\u0679\u0631\u06cc\u0679\u0631 \u0645\u0639\u0627\u0648\u0636\u06d2 \u06a9\u0627 \u0627\u06cc\u06a9 \u0645\u0631\u062d\u0644\u06c1 \u0634\u0631\u0648\u0639 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u062c\u0648 \u06a9\u06c1 \u06c1\u062f\u0627\u06cc\u0627\u062a \u062f\u06cc\u062a\u0627 \u06c1\u06d2: <code>auth-service<\/code> \u067e\u06c1\u0644\u06d2 \u0633\u06d2 \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0631\u062f\u06c1 \u06a9\u0633\u06cc \u0628\u06be\u06cc \u0686\u06cc\u0632 \u06a9\u0648 \u06c1\u0679\u0627 \u062f\u06cc\u06ba\u06d4<\/p>\n<p>\u0628\u0646\u06cc\u0627\u062f\u06cc \u062e\u06cc\u0627\u0644 \u06cc\u06c1 \u06c1\u06d2 \u06a9\u06c1 \u062c\u0628 \u06a9\u06c1 \u06c1\u0631 \u0633\u0631\u0648\u0633 \u0627\u067e\u0646\u06d2 \u0645\u0642\u0627\u0645\u06cc \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u06a9\u0627 \u0627\u0631\u062a\u06a9\u0627\u0628 \u06a9\u0631\u062a\u06cc \u06c1\u06d2\u060c \u06cc\u06c1 \u0633\u0644\u0633\u0644\u06c1 \u067e\u0648\u0631\u06d2 \u06a9\u0627\u0631\u0648\u0628\u0627\u0631\u06cc \u0648\u0631\u06a9 \u0641\u0644\u0648 \u06a9\u0648 \u0645\u0631\u0628\u0648\u0637 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0627\u0633 \u0628\u0627\u062a \u06a9\u0648 \u06cc\u0642\u06cc\u0646\u06cc \u0628\u0646\u0627\u062a\u0627 \u06c1\u06d2 \u06a9\u06c1 \u062e\u0631\u0627\u0628\u06cc\u0627\u06ba \u06c1\u0648\u0646\u06d2 \u067e\u0631 \u0633\u0633\u0679\u0645 \u0645\u0633\u062a\u0642\u0644 \u062d\u0627\u0644\u062a \u0645\u06cc\u06ba \u0648\u0627\u067e\u0633 \u0622 \u0633\u06a9\u06d2\u06d4<\/p>\n<pre><code class=\"language-mermaid\">sequenceDiagram\n    autonumber\n    participant C as Client\n    participant AS as agency-service<br\/>Orchestrator\n    participant DB1 as saga store\n    participant AU as auth-service\n    participant DB2 as auth DB\n\n    C->>AS: POST \/agencies\n    AS->>DB1: INSERT saga (STARTED, payload)\n    AS->>AU: provisionAgencyAccount(sagaId, \u2026)\n    AU->>DB2: BEGIN TX\n    AU->>DB2: create org + user + role + provision_record\n    AU->>DB2: COMMIT\n    AU-->>AS: { userId, organizationId, roleId }\n    AS->>DB1: UPDATE saga (AUTH_PROVISIONED)\n    AS->>AS: create Agency row\n    alt Agency row OK\n        AS->>DB1: UPDATE saga (AGENCY_CREATED \u2192 COMPLETED)\n        AS->>AU: sendAgencyWelcomeEmail (non-critical)\n        AS-->>C: 200 OK + sagaId\n    else Agency row fails\n        AS->>DB1: UPDATE saga (COMPENSATING)\n        AS->>AU: compensateAgencyAccount(sagaId)\n        AU->>DB2: BEGIN TX\n        AU->>DB2: delete role + token + user + org + record\n        AU->>DB2: COMMIT\n        AS->>DB1: UPDATE saga (COMPENSATED \u2192 FAILED)\n        AS-->>C: 5xx + error code\n    end\n<\/code><\/pre>\n<p>\u0627\u06cc\u06a9 \u0628\u0627\u0631 \u062c\u0628 \u0622\u067e \u0627\u0633\u06d2 \u06a9\u0648\u0631 \u0633\u06d2 \u06a9\u0648\u0631 \u062a\u06a9 \u067e\u0691\u06be \u0644\u06cc\u06ba \u06af\u06d2\u060c \u062a\u0648 \u0622\u067e \u067e\u0648\u0631\u06d2 \u0622\u0646 \u0628\u0648\u0631\u0688\u0646\u06af \u0648\u0631\u06a9 \u0641\u0644\u0648 \u06a9\u0648 \u0633\u0645\u062c\u06be \u062c\u0627\u0626\u06cc\u06ba \u06af\u06d2\u06d4 \u06cc\u06c1 \u0622\u0631\u06a9\u06cc\u0633\u0679\u0631\u06cc\u0634\u0646 \u06a9\u06cc \u0642\u062f\u0631 \u06c1\u06d2\u06d4 \u062a\u0631\u062a\u06cc\u0628 \u06a9\u0627 \u062e\u0627\u06a9\u06c1 <em>\u06c1\u06d2<\/em> \u0639\u0645\u0627\u0631\u062a<\/p>\n<h2 id=\"heading-8-the-state-machine\">8. \u0631\u06cc\u0627\u0633\u062a\u06cc \u0645\u0634\u06cc\u0646<\/h2>\n<p>\u062a\u0645\u0627\u0645 \u062a\u0628\u062f\u06cc\u0644\u06cc\u0627\u06ba \u0644\u0627\u06af \u0627\u0646 \u06c1\u06cc\u06ba: <code>agency_onboarding_sagas<\/code> <strong>\u067e\u06c1\u0644\u06d2<\/strong> \u0645\u0646\u062f\u0631\u062c\u06c1 \u0630\u06cc\u0644 \u0645\u0631\u0627\u062d\u0644 \u067e\u0631 \u0639\u0645\u0644 \u06a9\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2: \u06cc\u06c1 \u0648\u06c1\u06cc \u06c1\u06d2 \u062c\u0648 \u0627\u0633 \u06a9\u06c1\u0627\u0646\u06cc \u06a9\u0648 \u0642\u0627\u0628\u0644 \u0645\u0634\u0627\u06c1\u062f\u06c1 \u0627\u0648\u0631 \u0628\u0627\u0632\u06cc\u0627\u0641\u062a \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-ts\">export enum AgencyOnboardingSagaStatus {\n  STARTED            = 'STARTED',            \/\/ Row exists, no side effects yet\n  AUTH_PROVISIONED   = 'AUTH_PROVISIONED',   \/\/ Auth side committed\n  AGENCY_CREATED     = 'AGENCY_CREATED',     \/\/ Agency row committed\n  COMPLETED          = 'COMPLETED',          \/\/ Happy-path terminal state\n  COMPENSATING       = 'COMPENSATING',       \/\/ Rollback in progress\n  COMPENSATED        = 'COMPENSATED',        \/\/ Rollback finished\n  FAILED             = 'FAILED',             \/\/ Terminal failure (with or without compensation)\n}\n<\/code><\/pre>\n<p>\u0627\u062a\u0646\u06cc \u0631\u06cc\u0627\u0633\u062a\u06cc\u06ba \u06a9\u06cc\u0648\u06ba \u06c1\u06cc\u06ba\u061f \u06a9\u06cc\u0648\u0646\u06a9\u06c1 <em>\u2019\u2019\u06cc\u06c1\u0627\u06ba \u06a9\u06cc\u0627 \u06c1\u0648\u0627\u061f\u2018\u2018<\/em> \u06cc\u06c1 \u0627\u06cc\u06a9 \u0633\u0648\u0627\u0644 \u06c1\u06d2 \u062c\u0648 \u06a9\u0648\u0626\u06cc \u0635\u0628\u062d 2 \u0628\u062c\u06d2 \u067e\u0648\u0686\u06be\u06d2 \u06af\u0627\u06d4 \u0627\u06cc\u06a9 \u06a9\u06c1\u0627\u0646\u06cc \u062c\u0648 \u0635\u0631\u0641 \u0628\u0686\u0627\u062a\u06cc \u06c1\u06d2\u06d4 <code>success | failure<\/code> \u06cc\u06c1 \u0641\u0631\u0627\u0646\u0632\u06a9 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0628\u06cc\u06a9\u0627\u0631 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-plaintext\">                \u250c\u2500\u2500 auth fails \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25ba FAILED  (nothing to compensate)\n                \u2502\nSTARTED \u2500\u2500\u25ba AUTH_PROVISIONED \u2500\u2500\u25ba AGENCY_CREATED \u2500\u2500\u25ba COMPLETED  (happy path)\n                                       \u2502\n                       agency fails \u2500\u2500\u2500\u2518\n                                       \u25bc\n                                COMPENSATING\n                                       \u2502\n                                       \u25bc\n                                COMPENSATED \u2500\u2500\u25ba FAILED  (consistent again)\n<\/code><\/pre>\n<p>&#8216;\u067e\u0648\u0627\u0626\u0646\u0679 \u0622\u0641 \u0646\u0648 \u0631\u06cc\u0679\u0631\u0646&#8217; <code>AUTH_PROVISIONED<\/code>. \u0627\u0633 \u0633\u06d2 \u067e\u06c1\u0644\u06d2 \u06a9\u06c1 \u0622\u067e \u062a\u06cc\u0632\u06cc \u0633\u06d2 \u0646\u0627\u06a9\u0627\u0645 \u06c1\u0648 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u06a9\u0648\u0626\u06cc \u06a9\u0627\u0644\u0639\u062f\u0645 \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4 \u0627\u0633 \u06a9\u06d2 \u0628\u0639\u062f \u0646\u0627\u06a9\u0627\u0645\u06cc \u06a9\u06d2 \u062a\u0645\u0627\u0645 \u0631\u0627\u0633\u062a\u06d2 <em>~ \u06a9\u0631\u0646\u0627 \u06c1\u06d2\u06d4<\/em> \u0627\u0646\u0639\u0627\u0645\u0627\u062a \u0633\u06d2 \u06af\u0632\u0631\u06cc\u06ba\u06d4<\/p>\n<h2 id=\"heading-9-implementing-the-orchestrator\">9. \u0622\u0631\u06a9\u06cc\u0633\u0679\u0631\u06cc\u0679\u0631 \u06a9\u0627 \u0646\u0641\u0627\u0630<\/h2>\n<p>\u0622\u0631\u06a9\u06cc\u0633\u0679\u0631\u06cc\u0679\u0631 \u06c1\u06d2\u06d4 <em>\u0635\u0631\u0641<\/em> \u062c\u06c1\u0627\u06ba \u0622\u067e \u0648\u0631\u06a9 \u0641\u0644\u0648 \u06a9\u0648 \u062c\u0627\u0646\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u06c1\u0631 \u0642\u062f\u0645 \u0627\u06cc\u06a9 \u0646\u062c\u06cc \u0637\u0631\u06cc\u0642\u06c1 \u06c1\u06d2\u060c \u0627\u0648\u0631 \u06c1\u0631 \u0642\u062f\u0645 \u0648\u0627\u067e\u0633 \u0622\u0646\u06d2 \u0633\u06d2 \u067e\u06c1\u0644\u06d2 \u0646\u062a\u06cc\u062c\u06c1 \u0631\u06a9\u06be\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<h3 id=\"heading-creating-the-saga-record\">\u0633\u0627\u06af\u0627 \u0631\u06cc\u06a9\u0627\u0631\u0688 \u0628\u0646\u0627\u0626\u06cc\u06ba<\/h3>\n<pre><code class=\"language-ts\">\/\/ agency-onboarding.saga.repository.ts\nasync createSaga(payload: CreateAgencyOrchestrationInput) {\n  return this.sagaModel.create({\n    sagaId: randomUUID(),                          \/\/ correlation id for everything\n    status: AgencyOnboardingSagaStatus.STARTED,\n    currentStep: 'STARTED',\n    payload,                                       \/\/ full input snapshot for replay\n  });\n}\n<\/code><\/pre>\n<p>\u06a9\u06c1 <code>sagaId<\/code> \u06cc\u06c1 \u0627\u06cc\u06a9 UUID \u06c1\u06d2 \u062c\u0648 \u0627\u06cc\u06a9 \u0628\u0627\u0631 \u0628\u0646\u0627\u06cc\u0627 \u06af\u06cc\u0627 \u062a\u06be\u0627\u06d4 <strong>\u062a\u0645\u0627\u0645 \u0688\u0627\u0648\u0646 \u0627\u0633\u0679\u0631\u06cc\u0645 \u06a9\u0627\u0644\u0632 \u067e\u0631 \u067e\u0631\u0648\u067e\u06cc\u06af\u0646\u0688\u06c1 \u06a9\u06cc\u0627 \u06af\u06cc\u0627\u06d4<\/strong>. \u0627\u06cc\u06a9 \u0648\u0627\u062d\u062f \u0634\u0646\u0627\u062e\u062a \u06a9\u0646\u0646\u062f\u06c1 \u062c\u0648 \u0622\u0631\u06a9\u06cc\u0633\u0679\u0631\u06cc\u0679\u0631 \u0633\u0627\u0626\u06cc\u0688 \u067e\u0631 \u0633\u0627\u06af\u0627 \u0644\u0627\u06af \u06a9\u0648 \u0634\u0631\u06cc\u06a9 \u06a9\u06cc \u0637\u0631\u0641 \u0633\u06d2 \u067e\u0631\u0648\u0648\u06cc\u0698\u0646\u0646\u06af \u0631\u06cc\u06a9\u0627\u0631\u0688 \u0633\u06d2 \u062c\u0648\u0691\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<h3 id=\"heading-the-main-loop\">\u0645\u0631\u06a9\u0632\u06cc \u0644\u0648\u067e<\/h3>\n<pre><code class=\"language-ts\">\/\/ agency-onboarding.orchestrator.ts (trimmed for the article)\nasync execute(input: CreateAgencyOrchestrationInput) {\n  const saga = await this.sagaRepository.createSaga(input); \/\/ STARTED\n\n  try {\n    \/\/ Step 1 \u2014 auth-service work\n    const authStep = await this.provisionAuth(saga, input);\n    if (!authStep.ok) {\n      await this.markFailed(saga, authStep.failure); \/\/ nothing to compensate\n      return authStep.failure;\n    }\n\n    \/\/ Step 2 \u2014 agency-service work\n    let activeSaga = authStep.saga; \/\/ status: AUTH_PROVISIONED\n    try {\n      activeSaga = await this.createAgencyRow(activeSaga, input, authStep.authIds);\n    } catch (err) {\n      \/\/ The expensive case: undo what auth-service did\n      await this.compensateAuth(activeSaga, 'SAGA_FAILED');\n      const failure = mapSagaFailure(err.message, 'SAGA_FAILED', 'CREATE_AGENCY');\n      await this.markFailed(activeSaga, failure);\n      return failure;\n    }\n\n    \/\/ Step 3 \u2014 mark done and run non-critical side effects\n    activeSaga = await this.sagaRepository.updateSaga(activeSaga, {\n      status: AgencyOnboardingSagaStatus.COMPLETED,\n    });\n    await this.sendWelcomeEmail(input, activeSaga); \/\/ best-effort\n\n    return mapSagaSuccess(activeSaga, await this.agencyModel.findByPk(activeSaga.agencyId!));\n  } catch (error) {\n    \/\/ Defensive catch-all (lost DB connection, unexpected throw)\n    await this.compensateAuth(saga, 'SAGA_FAILED');\n    const failure = mapSagaFailure(error.message, 'SAGA_FAILED', 'SAGA');\n    await this.markFailed(saga, failure);\n    return failure;\n  }\n}\n<\/code><\/pre>\n<h3 id=\"heading-a-single-step-in-detail\">\u062a\u0641\u0635\u06cc\u0644\u06cc \u0648\u0627\u062d\u062f \u0642\u062f\u0645<\/h3>\n<pre><code class=\"language-ts\">private async provisionAuth(saga: AgencyOnboardingSaga, input: ...) {\n  this.logger.log(`[${saga.sagaId}] PROVISION_AUTH`);\n\n  const auth = await firstValueFrom(\n    this.authClient.provisionAgencyAccount({\n      sagaId: saga.sagaId,                  \/\/ <-- correlation\n      organizationName: input.agencyName.trim(),\n      email: input.email.trim().toLowerCase(),\n      \/\/ \u2026\n    }),\n  );\n\n  if (!auth.status || !auth.data) {\n    return { ok: false, failure: mapAuthProvisionFailure(auth) };\n  }\n\n  \/\/ Persist the IDs we will need if we have to compensate later\n  const updated = await this.sagaRepository.updateSaga(saga, {\n    authOrganizationId: Number(auth.data.organizationId),\n    authUserId: Number(auth.data.userId),\n    authUserRoleId: Number(auth.data.userRoleId),\n    status: AgencyOnboardingSagaStatus.AUTH_PROVISIONED,\n  });\n\n  return { ok: true, saga: updated, authIds: auth.data };\n}\n<\/code><\/pre>\n<p>\u0648\u06c1 \u0644\u0627\u0626\u0646 \u062c\u0648 \u0632\u06cc\u0627\u062f\u06c1 \u062a\u0631 \u06a9\u0627\u0645 \u06a9\u0631\u062a\u06cc \u06c1\u06d2\u06d4 <code>updateSaga<\/code> \u06a9\u0627\u0644 \u0648\u0627\u067e\u0633 \u06a9\u06cc \u06af\u0626\u06cc \u063a\u06cc\u0631 \u0645\u0644\u06a9\u06cc ID \u06a9\u0648 \u0627\u0633\u0679\u0648\u0631 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 <code>auth-service<\/code> \u0644\u06c1\u0630\u0627 \u06cc\u06c1\u0627\u06ba \u062a\u06a9 \u06a9\u06c1 \u0627\u06af\u0631 \u0622\u0631\u06a9\u06cc\u0633\u0679\u0631\u06cc\u0679\u0631 \u06a9\u0627 \u0639\u0645\u0644 \u06a9\u0631\u06cc\u0634 \u06c1\u0648 \u062c\u0627\u0626\u06d2 \u0627\u0648\u0631 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0634\u0631\u0648\u0639 \u06c1\u0648 \u062c\u0627\u0626\u06d2\u060c \u0628\u0627\u0632\u06cc\u0627\u0628\u06cc \u06a9\u0627 \u06a9\u0627\u0645 \u0627\u0633 \u0644\u0627\u0626\u0646 \u06a9\u0648 \u067e\u0691\u06be \u0633\u06a9\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u062c\u0627\u0646 \u0633\u06a9\u062a\u0627 \u06c1\u06d2 \u06a9\u06c1 \u06a9\u0633 \u0686\u06cc\u0632 \u06a9\u06cc \u062a\u0644\u0627\u0641\u06cc \u06a9\u0631\u0646\u06cc \u06c1\u06d2\u06d4<\/p>\n<h3 id=\"heading-habits-worth-copying\">\u0639\u0627\u062f\u0627\u062a \u06a9\u06cc \u067e\u06cc\u0631\u0648\u06cc \u06a9\u06d2 \u0642\u0627\u0628\u0644<\/h3>\n<ul>\n<li>\n<p><strong>\u062a\u0645\u0627\u0645 \u06a9\u0627\u0645\u06cc\u0627\u0628 \u0645\u0631\u0627\u062d\u0644 \u06a9\u06d2 \u0628\u0639\u062f \u062c\u0627\u0631\u06cc \u06c1\u06d2\u06d4<\/strong>\u06a9\u0627\u0644\u0639\u062f\u0645 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u062f\u0631\u06a9\u0627\u0631 ID \u067e\u0631 \u0645\u0634\u062a\u0645\u0644 \u06c1\u06d2\u06d4<\/p>\n<\/li>\n<li>\n<p><strong>\u0627\u06c1\u0645 \u0627\u0648\u0631 \u063a\u06cc\u0631 \u0627\u06c1\u0645 \u0627\u0642\u062f\u0627\u0645\u0627\u062a \u0645\u06cc\u06ba \u0641\u0631\u0642 \u06a9\u0631\u06cc\u06ba\u06d4<\/strong> \u062e\u0648\u0634 \u0622\u0645\u062f\u06cc\u062f \u0627\u06cc \u0645\u06cc\u0644\u0632\u060c \u0622\u0688\u0679 \u0644\u0627\u06af\u0632\u060c \u0627\u0648\u0631 \u062a\u062c\u0632\u06cc\u0627\u062a\u06cc \u0627\u06cc\u0648\u0646\u0679\u0633 \u0645\u06cc\u06ba \u0634\u0627\u0645\u0644 \u06c1\u06cc\u06ba: <em>~ \u0646\u06c1\u06cc\u06ba<\/em> \u06cc\u06c1 \u06a9\u06c1\u0627\u0646\u06cc \u06a9\u0648 \u062f\u0648\u0628\u0627\u0631\u06c1 \u062a\u0644\u0627\u0634 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0642\u0627\u0628\u0644 \u06c1\u06d2\u06d4 \u0648\u06c1 \u0627\u067e\u0646\u06cc \u067e\u0648\u0631\u06cc \u06a9\u0648\u0634\u0634 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<\/li>\n<li>\n<p><strong>\u0627\u06cc\u06a9 \u0644\u0627\u06af \u0644\u0627\u0626\u0646 \u0641\u06cc \u062a\u0628\u062f\u06cc\u0644\u06cc<\/strong>\u0633\u0627\u0628\u0642\u06c1 <code>[${sagaId}]<\/code>. \u06af\u0631\u06cc\u067e \u0627\u06cc\u06a9 \u0688\u06cc\u0628\u06af\u0631 \u06c1\u06d2\u06d4<\/p>\n<\/li>\n<\/ul>\n<h2 id=\"heading-10-implementing-the-participant\">10. \u0634\u0631\u06cc\u06a9 \u0639\u0645\u0644 \u062f\u0631\u0622\u0645\u062f<\/h2>\n<p>\u0634\u0631\u06cc\u06a9 (<code>auth-service<\/code>) \u0627\u067e\u0646\u06d2 \u062a\u0645\u0627\u0645 \u0622\u067e\u0631\u06cc\u0634\u0646\u0632 \u06a9\u0648 \u0645\u0642\u0627\u0645\u06cc DB \u0679\u0631\u0627\u0646\u0632\u06cc\u06a9\u0634\u0646 \u0645\u06cc\u06ba \u0633\u0645\u06cc\u0679\u062a\u0627 \u06c1\u06d2\u06d4 \u0627\u0633 \u062d\u062f \u06a9\u06d2 \u0627\u0646\u062f\u0631 \u0622\u067e \u06a9\u06d2 \u067e\u0627\u0633 \u0627\u0628 \u0628\u06be\u06cc ACID \u06c1\u06d2\u06d4 \u06cc\u06c1 \u0633\u0644\u0633\u0644\u06c1 \u0635\u0631\u0641 \u0627\u0646\u0679\u0631 \u0633\u0631\u0648\u0633 \u06a9\u06d2 \u0645\u0633\u0627\u0626\u0644 \u06a9\u0648 \u062d\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-ts\">\/\/ agency-provisioning.service.ts (trimmed)\nasync provisionAgencyAccount(req: ProvisionAgencyAccountInput) {\n\n  \/\/ 1. Idempotency \u2014 return the previous result if this sagaId already provisioned.\n  const existing = await this.provisionRecordModel.findOne({\n    where: { sagaId: req.sagaId },\n  });\n  if (existing) {\n    return serviceSuccess('Agency admin already onboarded', {\n      userId: Number(existing.userId),\n      organizationId: Number(existing.organizationId),\n      userRoleId: Number(existing.roleId),\n    });\n  }\n\n  \/\/ 2. Domain validation BEFORE the transaction (fail fast).\n  if (await this.emailExists(req.email)) {\n    return serviceFailure('Email already exists', { code: 'EMAIL_EXISTS' });\n  }\n  if (await this.organizationExists(req.organizationName)) {\n    return serviceFailure('Organization already exists', { code: 'ORGANIZATION_EXISTS' });\n  }\n\n  \/\/ 3. The actual work \u2014 atomic at the auth-service boundary.\n  return withSequelizeTransaction(this.sequelize, async (tx) => {\n    const org = await this.organizationModel.create({ ... }, { transaction: tx });\n    const user = await this.userModel.create({ ..., organizationId: org.id }, { transaction: tx });\n    await this.userRoleModel.create({ userId: user.id, roleId: agencyAdminRole.id }, { transaction: tx });\n\n    \/\/ The audit record that makes compensation possible later.\n    await this.provisionRecordModel.create(\n      { sagaId: req.sagaId, organizationId: org.id, userId: user.id, roleId: agencyAdminRole.id },\n      { transaction: tx },\n    );\n\n    return serviceSuccess('Provisioned', {\n      userId: user.id, organizationId: org.id, userRoleId: agencyAdminRole.id,\n    });\n  });\n}\n<\/code><\/pre>\n<p>\u0627\u0633 \u0637\u0631\u06cc\u0642\u06c1 \u06a9\u0627\u0631 \u06a9\u0648 \"\u0633\u0627\u06af\u0627 \u0633\u06cc\u0641\" \u0628\u0646\u0627\u0646\u06d2 \u06a9\u06cc \u062a\u06cc\u0646 \u0648\u062c\u0648\u06c1\u0627\u062a \u06c1\u06cc\u06ba:<\/p>\n<ol>\n<li>\n<p><strong>\u0633\u0628 \u0633\u06d2 \u067e\u06c1\u0644\u06d2 \u06a9\u0645\u0632\u0648\u0631\u06cc \u06a9\u06cc \u062c\u0627\u0646\u0686 \u06a9\u0631\u06cc\u06ba:<\/strong> \u0627\u06af\u0631 \u0622\u0631\u06a9\u06cc\u0633\u0679\u0631\u06cc\u0679\u0631 \u062f\u0648\u0628\u0627\u0631\u06c1 \u06a9\u0648\u0634\u0634 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 (\u0646\u06cc\u0679 \u0648\u0631\u06a9 \u0628\u0644\u067e\u060c \u062c\u06cc \u0622\u0631 \u067e\u06cc \u0633\u06cc \u0679\u0627\u0626\u0645 \u0622\u0624\u0679)\u060c \u062a\u0648 \u062f\u0648\u0633\u0631\u06cc \u06a9\u0627\u0644 \u0627\u06cc\u06a9 \u06c1\u06cc ID \u06a9\u0648 \u0648\u0627\u067e\u0633 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u06cc\u06a9 \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4 \u06a9\u0648\u0626\u06cc \u0688\u067e\u0644\u06cc\u06a9\u06cc\u0679 \u0635\u0627\u0631\u0641 \u0646\u06c1\u06cc\u06ba \u06c1\u06cc\u06ba\u06d4<\/p>\n<\/li>\n<li>\n<p><strong>\u0644\u06cc\u0646 \u062f\u06cc\u0646 \u06a9\u06cc \u0628\u06cc\u0631\u0648\u0646\u06cc \u062a\u0635\u062f\u06cc\u0642:<\/strong> \u0633\u0633\u062a\u0627 \u067e\u0691\u06be\u062a\u0627 \u06c1\u06d2 \u067e\u06c1\u0644\u06d2\u060c \u0645\u06c1\u0646\u06af\u0627 \u0644\u06a9\u06be\u062a\u0627 \u06c1\u06d2 \u062f\u0648\u0633\u0631\u06d2\u06d4<\/p>\n<\/li>\n<li>\n<p><strong>\u0627\u06cc\u06a9 \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u062a\u0645\u0627\u0645 \u062a\u062d\u0631\u06cc\u0631\u0648\u06ba \u06a9\u0648 \u0644\u067e\u06cc\u0679 \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u06d4<\/strong> \u0627\u06af\u0631 \u062f\u0627\u062e\u0644 \u06a9\u0631\u0646\u06d2 \u0645\u06cc\u06ba \u0646\u0627\u06a9\u0627\u0645 \u06c1\u0648 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u060c \u062a\u0648 \u0633\u0628 \u06a9\u0686\u06be \u062e\u0648\u062f \u0628\u062e\u0648\u062f \u0648\u0627\u067e\u0633 \u0686\u0644\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4 \u0622\u0631\u06a9\u06cc\u0633\u0679\u0631\u06cc\u0679\u0631 \u0645\u06a9\u0645\u0644 \u0646\u0627\u06a9\u0627\u0645\u06cc \u06a9\u0627 \u062c\u0648\u0627\u0628 \u062f\u06cc\u06a9\u06be \u0633\u06a9\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u062c\u0627\u0646\u062a\u0627 \u06c1\u06d2 \u06a9\u06c1 \u06a9\u0686\u06be \u0628\u06be\u06cc \u0628\u0631\u0642\u0631\u0627\u0631 \u0646\u06c1\u06cc\u06ba \u0631\u06c1\u0627\u06d4<\/p>\n<\/li>\n<\/ol>\n<p>\u06a9\u06c1 <code>agency_provision_records<\/code> \u0645\u06cc\u0632 \u0634\u0631\u06cc\u06a9 \u06a9\u0627 \u0633\u0628 \u0633\u06d2 \u0627\u06c1\u0645 \u062d\u0635\u06c1 \u06c1\u06d2\u06d4 \u06a9\u06c1 <strong>\u062f\u0648\u0646\u0648\u06ba<\/strong> \u0628\u06d2 \u0636\u0645\u06cc\u0631 \u06a9\u0644\u06cc\u062f <em>\u0627\u0648\u0631<\/em> \u0645\u0639\u0627\u0648\u0636\u06d2 \u06a9\u06cc \u0627\u0646\u06a9\u0648\u0627\u0626\u0631\u06cc - \u0627\u06cc\u06a9 \u06c1\u06cc \u06a9\u0644\u06cc\u062f \u06a9\u06d2 \u0633\u0627\u062a\u06be \u062f\u0627\u062e\u0644 \u06a9\u06cc \u06af\u0626\u06cc\u06d4 <code>sagaId<\/code> \u0622\u0631\u06a9\u06cc\u0633\u0679\u0631\u06cc\u0679\u0631 \u0627\u0633\u06d2 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<h2 id=\"heading-11-rollback-compensation\">11. \u0631\u0648\u0644 \u0628\u06cc\u06a9 (\u0645\u0639\u0627\u0648\u0636\u06c1)<\/h2>\n<p>\u0627\u0646\u0639\u0627\u0645 \u0635\u0631\u0641 \u0627\u06cc\u06a9 \u0627\u0648\u0631 \u062c\u06cc \u0622\u0631 \u067e\u06cc \u0633\u06cc \u06a9\u0627\u0644 \u06c1\u06d2\u06d4 \u0622\u0631\u06a9\u06cc\u0633\u0679\u0631\u06cc\u0679\u0631 \u06c1\u06d2\u06d4 <code>sagaId<\/code> \u0627\u0648\u0631 \u06cc\u0627\u062f \u0631\u06a9\u06be\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u06cc\u06a9 ID\u06d4 \u0634\u0631\u06a9\u0627\u0621 \u0627\u067e\u0646\u06cc \u062a\u062e\u0644\u06cc\u0642 \u06a9\u0631\u062f\u06c1 \u06c1\u0631 \u0686\u06cc\u0632 \u06a9\u0648 \u062d\u0630\u0641 \u06a9\u0631 \u062f\u06cc\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 <strong>\u0627\u0644\u0679\u0627 \u0627\u0646\u062d\u0635\u0627\u0631 \u06a9\u06cc \u062a\u0631\u062a\u06cc\u0628 \u0645\u06cc\u06ba<\/strong>\u0627\u0633 \u06a9\u06d2 \u0627\u067e\u0646\u06d2 DB \u0679\u0631\u0627\u0646\u0632\u06cc\u06a9\u0634\u0646 \u06a9\u06d2 \u0627\u0646\u062f\u0631\u06d4<\/p>\n<h3 id=\"heading-on-the-orchestrator-side\">\u0622\u0631\u06a9\u06cc\u0633\u0679\u0631\u06cc\u0679\u0631 \u06a9\u06cc \u0637\u0631\u0641<\/h3>\n<pre><code class=\"language-ts\">private async compensateAuth(saga: AgencyOnboardingSaga, errorCode?: string) {\n  if (!saga.authUserId && !saga.authOrganizationId) {\n    \/\/ Nothing was provisioned \u2014 nothing to compensate.\n    return;\n  }\n\n  \/\/ Mark the saga as compensating BEFORE the call, so the row is consistent\n  \/\/ even if the compensating RPC times out.\n  await this.sagaRepository.updateSaga(saga, {\n    status: AgencyOnboardingSagaStatus.COMPENSATING,\n    currentStep: 'COMPENSATING',\n    errorCode,\n  });\n\n  try {\n    const rollback = await firstValueFrom(this.authClient.compensateAgencyAccount({\n      sagaId: saga.sagaId,\n      organizationId: saga.authOrganizationId,\n      userId: saga.authUserId,\n    }));\n    if (!rollback.status) {\n      this.logger.error(`[\\({saga.sagaId}] Auth compensation returned failure: \\){rollback.message}`);\n    }\n  } catch (err) {\n    this.logger.error(`[\\({saga.sagaId}] Auth compensation RPC failed: \\){err.message}`);\n  }\n\n  await this.sagaRepository.updateSaga(saga, {\n    status: AgencyOnboardingSagaStatus.COMPENSATED,\n    currentStep: 'COMPENSATED',\n  });\n}\n<\/code><\/pre>\n<h3 id=\"heading-on-the-participant-side\">\u0634\u0631\u06cc\u06a9 \u06a9\u06cc \u0637\u0631\u0641<\/h3>\n<pre><code class=\"language-ts\">private async rollbackProvisionedAuth(req, sagaId: string, tx: Transaction) {\n  \/\/ Use the saga log as the source of truth \u2014 even if the caller forgot IDs.\n  const record = await this.provisionRecordModel.findOne({\n    where: { sagaId }, transaction: tx,\n  });\n  const userId         = req.userId         ?? record?.userId;\n  const organizationId = req.organizationId ?? record?.organizationId;\n\n  if (userId) {\n    const user = await this.userModel.findByPk(userId, { transaction: tx, attributes: ['email'] });\n    await this.userRoleModel.destroy({ where: { userId }, transaction: tx });\n    if (user?.email) {\n      await this.passwordResetTokenModel.destroy({ where: { email: user.email }, transaction: tx });\n    }\n    await this.userModel.destroy({ where: { id: userId }, transaction: tx });\n  }\n  if (organizationId) {\n    await this.organizationModel.destroy({ where: { id: organizationId }, transaction: tx });\n  }\n  if (record) {\n    await record.destroy({ transaction: tx });\n  }\n}\n<\/code><\/pre>\n<h3 id=\"heading-rules-of-a-good-compensation\">\u0627\u0686\u06be\u06d2 \u0645\u0639\u0627\u0648\u0636\u06d2 \u06a9\u06d2 \u0642\u0648\u0627\u0646\u06cc\u0646<\/h3>\n<ol>\n<li>\n<p><strong>\u062a\u062e\u0644\u06cc\u0642 \u06a9\u06cc \u062a\u0631\u062a\u06cc\u0628 \u06a9\u0648 \u0627\u0644\u0679 \u062f\u06cc\u06ba\u06d4<\/strong> \u067e\u06c1\u0644\u06d2 \u0628\u0686\u06d2 (user_roles\u060c tokens)\u060c \u067e\u06be\u0631 \u0648\u0627\u0644\u062f\u06cc\u0646 (\u0635\u0627\u0631\u0641\u06cc\u0646\u060c \u062a\u0646\u0638\u06cc\u0645\u06cc\u06ba)\u06d4 \u0648\u06c1\u06cc \u0642\u0648\u0627\u0646\u06cc\u0646 \u062c\u0648 \u0622\u067e \u067e\u06cc\u0631\u0648\u06cc \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 <code>DROP TABLE<\/code> \u0627\u0639\u0644\u0627\u0646<\/p>\n<\/li>\n<li>\n<p><strong>\u0628\u06d2 \u062d\u0633\u06cc \u06c1\u0648\u0646\u06cc \u0686\u0627\u06c1\u06cc\u06d2\u06d4<\/strong> \u0627\u06cc\u06a9 \u06c1\u06cc \u0648\u0635\u0648\u0644 \u06a9\u0631\u06cc\u06ba <code>sagaId<\/code> \u06c1\u0631 \u0628\u0627\u0631 - \u062f\u0648 \u0628\u0627\u0631 \u0645\u062d\u0641\u0648\u0638 \u0631\u06c1\u06cc\u06ba\u06d4 <code>destroy<\/code> \u0627\u06af\u0631 \u0642\u0637\u0627\u0631 \u067e\u06c1\u0644\u06d2 \u06c1\u06cc \u062e\u062a\u0645 \u06c1\u0648 \u062c\u0627\u0626\u06d2 \u062a\u0648 \u06cc\u06c1 \u06a9\u0627\u0645 \u0646\u06c1\u06cc\u06ba \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<\/li>\n<li>\n<p><strong>\u0633\u0627\u06af\u0627 \u0644\u0627\u06af\u0632 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0633\u0627\u062a\u06be \u062f\u0631\u062e\u0648\u0627\u0633\u062a\u0648\u06ba \u06a9\u0627 \u0628\u06be\u06cc \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u06cc\u06ba\u06d4<\/strong> \u0627\u06af\u0631 \u0628\u06be\u06cc\u062c\u0646\u06d2 \u0648\u0627\u0644\u0627 \u0627\u067e\u0646\u06cc ID \u0628\u06be\u0648\u0644 \u06af\u06cc\u0627 \u06c1\u06d2 \u06cc\u0627 \u062c\u0632\u0648\u06cc \u067e\u06d2 \u0644\u0648\u0688 \u0628\u06be\u06cc\u062c\u0627 \u06c1\u06d2\u060c \u062a\u0648 \u0622\u067e \u0627\u0633\u06d2 \u06cc\u06c1\u0627\u06ba \u062a\u0644\u0627\u0634 \u06a9\u0631 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba: <code>sagaId<\/code>. \u06af\u06c1\u0631\u0627\u0626\u06cc \u0645\u06cc\u06ba \u062f\u0641\u0627\u0639\u06d4<\/p>\n<\/li>\n<li>\n<p><strong>\u0627\u0633\u06d2 \u0645\u0642\u0627\u0645\u06cc \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u0645\u06cc\u06ba \u0644\u067e\u06cc\u0679\u06cc\u06ba\u06d4<\/strong> \u0631\u0648\u0644 \u0628\u06cc\u06a9 \u062e\u0648\u062f \u062c\u0648\u06c1\u0631\u06cc \u06c1\u0648\u0646\u0627 \u0636\u0631\u0648\u0631\u06cc \u06c1\u06d2\u06d4 \u06a9\u0648\u0626\u06cc \u0686\u06cc\u0632 \u062c\u0648 \u0622\u062f\u06be\u06cc \u062e\u062a\u0645 \u0646\u06c1\u06cc\u06ba \u06a9\u06cc \u06af\u0626\u06cc \u06c1\u06d2 \u0648\u06c1 \u06a9\u0686\u06be \u0646\u06c1 \u06a9\u0631\u0646\u06d2 \u0633\u06d2 \u0628\u062f\u062a\u0631 \u06c1\u06d2\u06d4<\/p>\n<\/li>\n<li>\n<p><strong>\u06c1\u0645\u06cc\u0634\u06c1 \u0622\u0631\u06a9\u06cc\u0633\u0679\u0631\u06cc\u0679\u0631 \u06a9\u06cc \u0637\u0631\u0641 \u0644\u0648\u067e \u0628\u0646\u062f \u06a9\u0631\u06cc\u06ba\u06d4<\/strong> \u0646\u0634\u0627\u0646 <code>COMPENSATED<\/code> \u0686\u0627\u06c1\u06d2 RPC \u0646\u0627\u06a9\u0627\u0645 \u06c1\u0648 \u062c\u0627\u0626\u06d2\u06d4 \u063a\u0644\u0637\u06cc\u0627\u06ba \u0628\u06be\u06cc \u0638\u0627\u06c1\u0631 \u06a9\u06cc \u062c\u0627\u0646\u06cc \u0686\u0627\u06c1\u0626\u06cc\u06ba (\u0646\u0648\u0634\u062a\u06c1 \u062c\u0627\u062a\u060c \u0645\u06cc\u0679\u0631\u06a9\u0633\u060c \u0627\u0646\u062a\u0628\u0627\u06c1\u0627\u062a)\u06d4 \u067e\u06be\u0646\u0633 \u06af\u06cc\u0627 <code>COMPENSATING<\/code> \u0635\u0641 \u0627\u06cc\u06a9 \u0622\u067e\u0631\u06cc\u0634\u0646\u0644 \u06a9\u0627\u0646 \u06c1\u06d2\u06d4<\/p>\n<\/li>\n<\/ol>\n<h3 id=\"heading-what-happens-if-the-compensation-itself-fails\">\u0627\u06af\u0631 \u0627\u0646\u0639\u0627\u0645 \u062e\u0648\u062f \u0646\u0627\u06a9\u0627\u0645 \u06c1\u0648 \u062c\u0627\u0626\u06d2 \u062a\u0648 \u06a9\u06cc\u0627 \u06c1\u0648\u06af\u0627\u061f<\/h3>\n<p>\u06cc\u06c1 \u06a9\u0633\u06cc \u0628\u06be\u06cc \u0633\u0627\u06af\u0627 \u0688\u06cc\u0632\u0627\u0626\u0646 \u0645\u06cc\u06ba \u0628\u062f\u062a\u0631\u06cc\u0646 \u0635\u0648\u0631\u062a \u062d\u0627\u0644 \u06c1\u06d2\u06d4 \u062a\u06cc\u0646 \u0645\u0639\u0642\u0648\u0644 \u062d\u06a9\u0645\u062a \u0639\u0645\u0644\u06cc \u06c1\u06cc\u06ba:<\/p>\n<p>\u0622\u067e \u067e\u06c1\u0644\u06d2 \u0627\u06cc\u06a9\u0633\u067e\u0648\u0646\u06cc\u0646\u0634\u0644 \u0628\u06cc\u06a9 \u0622\u0641 \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u06a9\u06d2 \u062f\u0648\u0628\u0627\u0631\u06c1 \u06a9\u0648\u0634\u0634 \u06a9\u0631 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u06cc\u06c1 \u0639\u0627\u0631\u0636\u06cc \u063a\u0644\u0637\u06cc\u0648\u06ba (\u0646\u06cc\u0679 \u0648\u0631\u06a9\u060c \u062a\u0639\u0637\u0644) \u06a9\u06d2 \u0644\u06cc\u06d2 \u06a9\u0627\u0645 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u062f\u0648\u0633\u0631\u0627\u060c \u0622\u067e \u06a9\u06c1\u0627\u0646\u06cc \u06a9\u0648 \u0645\u0631\u062f\u06c1 \u062e\u0637 \u06a9\u06d2 \u0637\u0648\u0631 \u067e\u0631 \u0628\u06be\u06cc\u062c \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u06c1\u0645 \u0627\u0633\u06d2 \"\u0627\u0646\u0633\u0627\u0646\u06cc \u062a\u0648\u062c\u06c1 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06c1\u06d2\" \u0642\u0637\u0627\u0631 \u0627\u0648\u0631 \u0627\u0644\u0631\u0679 \u0645\u06cc\u06ba \u0644\u0627\u06af \u0627\u0646 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u062a\u06cc\u0633\u0631\u0627\u060c \u0622\u067e \u062f\u0633\u062a\u06cc \u0631\u0648\u0644 \u0628\u06cc\u06a9 \u0627\u06cc\u0646\u0688 \u067e\u0648\u0627\u0626\u0646\u0679 \u06a9\u0648 \u0628\u06d2 \u0646\u0642\u0627\u0628 \u06a9\u0631 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u0627\u0633 \u062d\u0648\u0627\u0644\u06c1 \u067e\u0631 \u0639\u0645\u0644 \u062f\u0631\u0622\u0645\u062f \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u0645\u06a9\u0645\u0644 \u06a9\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2: <code>RollbackAgencyOnboarding<\/code> gRPC \u0622\u067e\u0631\u06cc\u0679\u0631\u0632 \u06a9\u0648 \u0648\u06c1\u06cc \u0627\u0646\u0639\u0627\u0645\u0627\u062a \u062f\u0648\u0628\u0627\u0631\u06c1 \u0686\u0644\u0627\u0646\u06d2 \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u06d4 <code>sagaId<\/code>.<\/p>\n<p>\u067e\u06cc\u062f\u0627\u0648\u0627\u0631\u06cc \u0646\u0638\u0627\u0645 \u06a9\u0648 \u062a\u06cc\u0646\u0648\u06ba \u06a9\u0648 \u06cc\u06a9\u062c\u0627 \u06a9\u0631\u0646\u0627 \u0686\u0627\u06c1\u06cc\u06d2\u06d4 \u0622\u067e \u06a9\u06d2 \u0644\u06cc\u06d2 \u067e\u06cc\u0679\u0631\u0646 \u06a9\u0627 \u0641\u06cc\u0635\u0644\u06c1 \u0646\u06c1\u06cc\u06ba \u06a9\u06cc\u0627 \u06af\u06cc\u0627 \u06c1\u06d2\u06d4 <em>\u0622\u067e<\/em> \u0627\u067e\u0646\u06d2 \u06a9\u0627\u0631\u0648\u0628\u0627\u0631\u06cc \u062e\u0637\u0631\u06d2 \u06a9\u06cc \u0628\u0646\u06cc\u0627\u062f \u067e\u0631 \u0641\u06cc\u0635\u0644\u06c1 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<h2 id=\"heading-12-tracking-idempotency-and-observability\">12. \u0679\u0631\u06cc\u06a9\u0646\u06af\u060c \u0622\u0626\u06cc\u0688\u06cc\u0645\u067e\u0648\u0679\u06cc\u0646\u0633\u06cc \u0627\u0648\u0631 \u0645\u0634\u0627\u06c1\u062f\u06c1<\/h2>\n<p>\u0627\u06cc\u06a9 \u06c1\u06cc UUID \u06a9\u06cc \u0637\u0631\u0641 \u0633\u06d2 \u06a9\u0644\u06cc\u062f \u06a9\u0631\u062f\u06c1 \u062f\u0648 \u0645\u06cc\u0632\u06cc\u06ba\u06d4 <code>sagaId<\/code>\u06c1\u0645 \u0627\u067e\u0646\u06cc \u062a\u0645\u0627\u0645 \u0633\u0631\u0648\u0633\u0632 \u0645\u06cc\u06ba \u0645\u06a9\u0645\u0644 \u0679\u0631\u06cc\u0633 \u0627\u06cc\u0628\u0644\u0679\u06cc \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<h3 id=\"heading-orchestrator-side-agencyonboardingsagas\">\u0622\u0631\u06a9\u06cc\u0633\u0679\u0631\u06cc\u0679\u0631 \u06a9\u06cc \u0637\u0631\u0641 - <code>agency_onboarding_sagas<\/code><\/h3>\n<table>\n<thead>\n<tr>\n<th>\u06af\u0631\u0645\u06cc<\/th>\n<th>\u0645\u0642\u0635\u062f<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>sagaId<\/code>    (UUID\u060c \u0645\u0646\u0641\u0631\u062f)<\/td>\n<td>\u062a\u0645\u0627\u0645 RPCs \u0645\u06cc\u06ba \u067e\u0631\u0648\u067e\u06cc\u06af\u0646\u0688\u06c1\u06d4 \u06cc\u06c1 \u0633\u0631\u0648\u0633 \u0648\u0627\u0626\u06cc\u0688 \u062c\u0648\u0627\u0626\u0646 \u06a9\u06cc \u06a9\u0644\u06cc\u062f \u06c1\u06d2\u06d4<\/td>\n<\/tr>\n<tr>\n<td><code>status<\/code><\/td>\n<td>\u0631\u06cc\u0627\u0633\u062a\u06cc \u0645\u0634\u06cc\u0646 \u06a9\u06cc \u0645\u0648\u062c\u0648\u062f\u06c1 \u062d\u0627\u0644\u062a\u06d4<\/td>\n<\/tr>\n<tr>\n<td><code>currentStep<\/code><\/td>\n<td>\u0627\u0646\u0633\u0627\u0646\u06cc \u067e\u0691\u06be\u0646\u06d2 \u06a9\u06d2 \u0642\u0627\u0628\u0644 \u0688\u06cc\u0634 \u0628\u0648\u0631\u0688 \u0644\u06cc\u0628\u0644\u0632 (<code>PROVISION_AUTH<\/code>\u060c <code>CREATE_AGENCY<\/code>\u2026)\u06d4<\/td>\n<\/tr>\n<tr>\n<td><code>payload<\/code>    (JSONB)<\/td>\n<td>\u0627\u0646 \u067e\u0679 \u0633\u0646\u06cc\u067e \u0634\u0627\u0679 \u2014 \u067e\u0644\u06d2 \u0628\u06cc\u06a9\u060c \u0688\u06cc\u0628\u06af \u0627\u0648\u0631 \u0633\u067e\u0648\u0631\u0679 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4<\/td>\n<\/tr>\n<tr>\n<td><code>authOrganizationId<\/code>\u060c <code>authUserId<\/code>\u060c <code>authUserRoleId<\/code><\/td>\n<td>\u0645\u0639\u0627\u0648\u0636\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u063a\u06cc\u0631 \u0645\u0644\u06a9\u06cc \u0634\u0646\u0627\u062e\u062a \u062f\u0631\u06a9\u0627\u0631 \u06c1\u06d2\u06d4<\/td>\n<\/tr>\n<tr>\n<td><code>agencyId<\/code><\/td>\n<td>\u0627\u06af\u0631 \u0627\u06cc\u062c\u0646\u0633\u06cc \u06a9\u06cc \u0642\u0637\u0627\u0631 \u0645\u0648\u062c\u0648\u062f \u06c1\u06d2 \u062a\u0648 \u0633\u06cc\u0679 \u06a9\u0631\u06cc\u06ba\u06d4<\/td>\n<\/tr>\n<tr>\n<td><code>errorCode<\/code>\u060c <code>errorMessage<\/code><\/td>\n<td>\u0627\u06af\u0631 \u06cc\u06c1 \u0646\u0627\u06a9\u0627\u0645 \u06c1\u0648 \u062c\u0627\u0626\u06d2 \u062a\u0648 \u0627\u0633\u06d2 \u0628\u06be\u0631 \u062f\u06cc\u0627 \u062c\u0627\u0626\u06d2 \u06af\u0627\u06d4<\/td>\n<\/tr>\n<tr>\n<td><code>createdAt<\/code>\u060c <code>updatedAt<\/code><\/td>\n<td>\u06a9\u06c1\u0627\u0646\u06cc \u06a9\u06cc \u0679\u0627\u0626\u0645 \u0644\u0627\u0626\u0646\u06d4<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\u062d\u0642\u06cc\u0642\u06cc \u0642\u0637\u0627\u0631 <code>COMPLETED<\/code> \u062d\u06cc\u062b\u06cc\u062a \u062a\u0642\u0631\u06cc\u0628\u0627\u064b \u0627\u0633 \u0637\u0631\u062d \u06c1\u06d2:<\/p>\n<pre><code class=\"language-json\">{\n  \"sagaId\": \"0a4f3e2c-7b11-4f8d-9a2c-90b6f5f5b8a1\",\n  \"status\": \"COMPLETED\",\n  \"currentStep\": \"COMPLETED\",\n  \"agencyId\": 17,\n  \"authOrganizationId\": 42,\n  \"authUserId\": 99,\n  \"authUserRoleId\": 3,\n  \"errorCode\": null,\n  \"errorMessage\": null,\n  \"payload\": { \"agencyName\": \"Acme Education\", \"email\": \"admin@acme.com\", \"...\": \"...\" },\n  \"createdAt\": \"2026-05-22T10:14:32.118Z\",\n  \"updatedAt\": \"2026-05-22T10:14:33.412Z\"\n}\n<\/code><\/pre>\n<h3 id=\"heading-participant-side-agencyprovisionrecords\">\u0634\u0631\u06cc\u06a9 \u06a9\u06cc \u0637\u0631\u0641 - <code>agency_provision_records<\/code><\/h3>\n<table>\n<thead>\n<tr>\n<th>\u06af\u0631\u0645\u06cc<\/th>\n<th>\u0645\u0642\u0635\u062f<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>sagaId<\/code>    (\u0645\u0646\u0641\u0631\u062f)<\/td>\n<td>\u063a\u06cc\u0631\u062a \u0645\u0646\u062f \u06a9\u0644\u06cc\u062f\u06d4 \u0627\u06cc\u06a9 \u06c1\u06cc <code>sagaId<\/code> \u0622\u0631\u06a9\u06cc\u0633\u0679\u0631\u06cc\u0679\u0631 \u0633\u06d2\u06d4<\/td>\n<\/tr>\n<tr>\n<td><code>userId<\/code>\u060c <code>organizationId<\/code>\u060c <code>roleId<\/code><\/td>\n<td>\u0645\u0639\u0627\u0648\u0636\u06d2 \u067e\u0631 \u062d\u0630\u0641 \u06a9\u0631\u0646\u06d2 \u0648\u0627\u0644\u06cc \u0627\u0634\u06cc\u0627\u0621\u06d4<\/td>\n<\/tr>\n<tr>\n<td><code>createdAt<\/code>\u060c <code>updatedAt<\/code><\/td>\n<td>\u0679\u0627\u0626\u0645 \u0627\u0633\u0679\u06cc\u0645\u067e \u06a9\u06d2 \u0644\u06cc\u06d2 \u0622\u067e \u06a9\u0627 \u0634\u06a9\u0631\u06cc\u06c1\u06d4<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3 id=\"heading-observability-for-free\">\u0645\u0641\u062a \u0645\u0634\u0627\u06c1\u062f\u06c1<\/h3>\n<p>\u06a9\u06cc\u0648\u0646\u06a9\u06c1 \u06c1\u0631 \u0644\u0627\u06af \u0644\u0627\u0626\u0646 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0633\u0627\u0628\u0642\u06c1 \u200b\u200b\u0644\u06af\u0627 \u06c1\u0648\u0627 \u06c1\u06d2\u06d4 <code>[${sagaId}]<\/code>\u062f\u0648\u0646\u0648\u06ba \u062e\u062f\u0645\u0627\u062a \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u06cc\u06a9 \u06c1\u06cc \u06af\u0631\u06cc\u067e \u0622\u067e \u06a9\u0648 \u0645\u06a9\u0645\u0644 \u0679\u0627\u0626\u0645 \u0644\u0627\u0626\u0646 \u062f\u06d2 \u06af\u0627\u06d4<\/p>\n<pre><code class=\"language-plaintext\">[0a4f3e2c\u2026] PROVISION_AUTH                  agency-service\n[0a4f3e2c\u2026] provisionAgencyAccount: ok      auth-service\n[0a4f3e2c\u2026] CREATE_AGENCY                   agency-service\n[0a4f3e2c\u2026] Agency step failed: ...         agency-service\n[0a4f3e2c\u2026] Auth compensation completed     auth-service\n<\/code><\/pre>\n<p>\u0633\u0679\u0631\u06a9\u0686\u0631\u0688 \u0644\u0627\u06af\u0646\u06af \u0633\u06cc\u0679 \u0627\u067e (\u0644\u0648\u06a9\u06cc\u060c \u0627\u06cc\u0644\u0633\u0679\u06a9 \u0633\u0631\u0686\u060c \u0688\u06cc\u0679\u0627 \u0688\u0648\u06af) \u0645\u06cc\u06ba \u06cc\u06c1 \u0627\u06cc\u06a9 \u06a9\u0644\u06a9 \u0641\u0644\u0679\u0631 \u0628\u0646 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4 <strong>\u06a9\u06c1<\/strong> <code>sagaId<\/code> <strong>\u062a\u0642\u0633\u06cc\u0645 \u0634\u062f\u06c1 \u0679\u0631\u06cc\u0633\u0646\u06af\u06d4<\/strong><\/p>\n<h2 id=\"heading-13-testing-a-saga\">13. \u0633\u0627\u06af\u0627 \u06a9\u06cc \u062c\u0627\u0646\u0686 \u06a9\u0631\u06cc\u06ba\u06d4<\/h2>\n<p>\u0633\u0627\u06af\u0627 \u0635\u0631\u0641 \u0627\u06cc\u06a9 \u0631\u06cc\u0627\u0633\u062a\u06cc \u0645\u0634\u06cc\u0646 \u06c1\u06d2\u060c \u0644\u06c1\u0630\u0627 \u0679\u06cc\u0633\u0679 \u0645\u06cc\u0679\u0631\u06a9\u0633 \u0645\u062d\u062f\u0648\u062f \u0627\u0648\u0631 \u0686\u06be\u0648\u0679\u0627 \u06c1\u06d2\u06d4 \u06a9\u0645 \u0627\u0632 \u06a9\u0645\u060c \u062f\u0631\u062c \u0630\u06cc\u0644 \u0645\u0639\u0627\u0645\u0644\u0627\u062a \u06a9\u0627 \u0627\u062d\u0627\u0637\u06c1 \u06a9\u0631\u06cc\u06ba:<\/p>\n<table>\n<thead>\n<tr>\n<th>#<\/th>\n<th>\u0633\u06a9\u0631\u067e\u0679<\/th>\n<th>\u0645\u062a\u0648\u0642\u0639 \u062d\u062a\u0645\u06cc \u062d\u0627\u0644\u062a<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>1<\/td>\n<td>\u062e\u0648\u0634 \u0633\u0691\u06a9<\/td>\n<td><code>COMPLETED<\/code>\u0627\u06cc\u062c\u0646\u0633\u06cc \u06a9\u06cc \u0645\u0648\u062c\u0648\u062f\u06af\u06cc\u060c \u0635\u0627\u0631\u0641 \u06a9\u06cc \u0645\u0648\u062c\u0648\u062f\u06af\u06cc<\/td>\n<\/tr>\n<tr>\n<td>2<\/td>\n<td>\u062a\u0648\u062b\u06cc\u0642 \u06a9\u0627 \u0645\u0631\u062d\u0644\u06c1 \u0646\u0627\u06a9\u0627\u0645 \u06c1\u0648 \u06af\u06cc\u0627 (\u062c\u06cc\u0633\u06d2 \u0627\u06cc \u0645\u06cc\u0644 \u0645\u0648\u062c\u0648\u062f \u06c1\u06d2)<\/td>\n<td><code>FAILED<\/code>\u062f\u0648\u0646\u0648\u06ba \u0637\u0631\u0641 \u06a9\u0648\u0626\u06cc \u0642\u0637\u0627\u0631 \u0646\u06c1\u06cc\u06ba<\/td>\n<\/tr>\n<tr>\n<td>3<\/td>\n<td>\u0627\u06cc\u062c\u0646\u0633\u06cc \u06a9\u06cc \u0646\u0627\u06a9\u0627\u0645\u06cc<\/td>\n<td><code>COMPENSATED<\/code>\u0645\u0646\u0638\u0648\u0631\u06cc \u06a9\u06cc \u0644\u0627\u0626\u0646 \u062e\u062a\u0645 \u06c1\u0648 \u0686\u06a9\u06cc \u06c1\u06d2 \u0627\u0648\u0631 \u06a9\u0648\u0626\u06cc \u0627\u06cc\u062c\u0646\u0633\u06cc \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4<\/td>\n<\/tr>\n<tr>\n<td>4<\/td>\n<td>\u0627\u0646\u0639\u0627\u0645 \u06a9\u0627 RPC \u0679\u0627\u0626\u0645 \u0622\u0624\u0679<\/td>\n<td><code>COMPENSATING<\/code>    \u2192 \u0622\u067e\u0631\u06cc\u0679\u0631 \u0633\u06d2 \u0686\u0644\u0646\u06d2 \u0648\u0627\u0644\u06cc \u0628\u062d\u0627\u0644\u06cc<\/td>\n<\/tr>\n<tr>\n<td>5<\/td>\n<td>\u0628\u06be\u06cc\u062c\u0646\u06d2 \u0648\u0627\u0644\u0627 \u0627\u0633\u06cc \u0645\u0648\u0627\u062f \u06a9\u06d2 \u0633\u0627\u062a\u06be \u062f\u0648\u0628\u0627\u0631\u06c1 \u06a9\u0648\u0634\u0634 \u06a9\u0631\u06d2 \u06af\u0627\u06d4 <code>sagaId<\/code><\/td>\n<td>\u062f\u0648\u0633\u0631\u06cc \u06a9\u0627\u0644 \u067e\u06c1\u0644\u06cc \u06a9\u0627\u0644 \u06a9\u0627 \u0646\u062a\u06cc\u062c\u06c1 \u0644\u0648\u0679\u0627\u062a\u06cc \u06c1\u06d2\u06d4 \u06a9\u0648\u0626\u06cc \u0688\u067e\u0644\u06cc\u06a9\u06cc\u0679 \u0642\u0637\u0627\u0631\u06cc\u06ba \u0646\u06c1\u06cc\u06ba \u06c1\u06cc\u06ba\u06d4<\/td>\n<\/tr>\n<tr>\n<td>6<\/td>\n<td>\u062e\u0648\u0634 \u0622\u0645\u062f\u06cc\u062f \u0627\u06cc \u0645\u06cc\u0644 \u0646\u0627\u06a9\u0627\u0645 \u06c1\u0648 \u06af\u0626\u06cc\u06d4<\/td>\n<td><code>COMPLETED<\/code>    \u067e\u06be\u0631 \u0628\u06be\u06cc - \u0645\u0639\u0645\u0648\u0644\u06cc \u0627\u0642\u062f\u0627\u0645\u0627\u062a \u06a9\u06cc \u06a9\u0648\u0626\u06cc \u062c\u06be\u0644\u06a9 \u0646\u06c1\u06cc\u06ba \u062a\u06be\u06cc\u06d4<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\u062c\u0627\u0646\u0686 \u06a9\u06d2 \u0644\u06cc\u06d2 \u062f\u0648 \u0639\u0645\u0644\u06cc \u0646\u06a9\u0627\u062a:<\/p>\n<p>\u0633\u0628 \u0633\u06d2 \u067e\u06c1\u0644\u06d2\u060c \u06c1\u0645 \u0646\u06cc\u0679 \u0648\u0631\u06a9 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2 \u0622\u0631\u06a9\u06cc\u0633\u0679\u0631\u06cc\u0679\u0631 \u06a9\u06cc \u0633\u0637\u062d \u067e\u0631 \u062c\u06cc \u0622\u0631 \u067e\u06cc \u0633\u06cc \u06a9\u0644\u0627\u0626\u0646\u0679 \u06a9\u0627 \u0645\u0630\u0627\u0642 \u0627\u0691\u0627\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u0622\u067e \u0627\u0633 \u06a9\u0627 \u062f\u0639\u0648\u06cc \u06a9\u0631\u0646\u0627 \u0686\u0627\u06c1\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 <code>compensateAgencyAccount<\/code> <em>\u062f\u0627\u0626\u06cc\u06ba \u0637\u0631\u0641 \u0628\u0644\u0627\u06cc\u0627<\/em> <code>sagaId<\/code>\u0627\u0633 \u0628\u0627\u062a \u06a9\u06cc \u0636\u0645\u0627\u0646\u062a \u0646\u06c1\u06cc\u06ba \u06c1\u06d2 \u06a9\u06c1 \u0648\u06c1 \u0628\u0627\u0626\u0679\u0633 \u06a9\u0628\u06be\u06cc \u0633\u0627\u06a9\u0679 \u062a\u06a9 \u067e\u06c1\u0646\u0686 \u062c\u0627\u0626\u06cc\u06ba \u06af\u06d2\u06d4<\/p>\n<p>\u062f\u0648\u0633\u0631\u0627\u060c \u0627\u067e\u0646\u06d2 \u0627\u0646\u0679\u06cc\u06af\u0631\u06cc\u0634\u0646 \u0679\u06cc\u0633\u0679\u0648\u06ba (\u0679\u06cc\u0633\u0679 \u06a9\u0646\u0679\u06cc\u0646\u0631\u0632 \u06cc\u0627 \u0688\u0648\u06a9\u0631 \u06a9\u0645\u067e\u0648\u0632) \u0645\u06cc\u06ba \u0627\u0635\u0644\u06cc \u067e\u0648\u0633\u0679\u06af\u0631\u06cc\u0633 \u06a9\u0648 \u06af\u06be\u0645\u0627\u0624\u06d4 <code>postgres<\/code> \u0633\u0631\u0648\u0633)\u06d4 \u0633\u0627\u06af\u0627 \u0627\u0633\u0679\u06cc\u0679 \u0645\u0634\u06cc\u0646 \u0641\u0631\u0636\u06cc \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u06a9\u06d2 \u062e\u0644\u0627\u0641 \"\u0679\u06cc\u0633\u0679\" \u06a9\u0631\u0646\u0627 \u0628\u06c1\u062a \u0622\u0633\u0627\u0646 \u06c1\u06d2 \u0627\u0648\u0631 \u062d\u0642\u06cc\u0642\u06cc DB \u06a9\u06d2 \u062e\u0644\u0627\u0641 \u062a\u0648\u0691\u0646\u0627 \u0628\u06c1\u062a \u0622\u0633\u0627\u0646 \u06c1\u06d2\u06d4<\/p>\n<h2 id=\"heading-14-when-not-to-use-a-saga\">14. \u06a9\u0628 \u0633\u0627\u06af\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u0646\u06c1 \u06a9\u0631\u06cc\u06ba\u06d4<\/h2>\n<p>\u0633\u0627\u06af\u0627 \u0622\u0632\u0627\u062f \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4 \u062f\u0631\u062c \u0630\u06cc\u0644 \u0635\u0648\u0631\u062a\u0648\u06ba \u0645\u06cc\u06ba \u0686\u06be\u0648\u0691\u06cc\u06ba:<\/p>\n<ul>\n<li>\n<p><strong>\u0627\u06cc\u06a9 \u062e\u062f\u0645\u062a \u062a\u0645\u0627\u0645 \u062a\u062d\u0631\u06cc\u0631\u06cc\u06ba \u0627\u0646\u062c\u0627\u0645 \u062f\u06cc\u062a\u06cc \u06c1\u06d2\u06d4<\/strong> \u0628\u0627\u0642\u0627\u0639\u062f\u06c1 DB \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u06cc\u06ba\u06d4 \u067e\u06c1\u06cc\u06d2 \u06a9\u0648 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0627\u06cc\u062c\u0627\u062f \u0646\u06c1 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<\/li>\n<li>\n<p><strong>\u0648\u0631\u06a9 \u0641\u0644\u0648 \u06cc\u0627 \u062a\u0648 \u0635\u0631\u0641 \u067e\u0691\u06be\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u06c1\u06cc\u06ba \u06cc\u0627 \u062a\u062c\u0632\u06cc\u0627\u062a\u06cc\u06d4<\/strong> SELECT \u0645\u06cc\u06ba \u06a9\u0648\u0626\u06cc \u0631\u0648\u0644 \u0628\u06cc\u06a9 \u0633\u06cc\u0645\u0646\u0679\u06a9\u0633 \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4<\/p>\n<\/li>\n<li>\n<p><strong>\"\u0631\u0648\u0644 \u0628\u06cc\u06a9\" \u0645\u0645\u06a9\u0646 \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4<\/strong> \u0645\u06cc\u06ba \u0646\u06d2 \u0622\u067e \u06a9\u0648 \u0627\u06cc\u06a9 \u062d\u0642\u06cc\u0642\u06cc \u0627\u06cc \u0645\u06cc\u0644 \u0628\u06be\u06cc\u062c\u0627 \u06c1\u06d2\u06d4 \u0645\u06cc\u06ba \u0646\u06d2 \u0627\u067e\u0646\u06d2 \u06a9\u0631\u06cc\u0688\u0679 \u06a9\u0627\u0631\u0688 \u0633\u06d2 \u0641\u06cc\u0633 \u0644\u06cc\u060c \u0644\u06cc\u06a9\u0646 \u06af\u06cc\u0679 \u0648\u06d2 \u0631\u0642\u0645 \u06a9\u06cc \u0648\u0627\u067e\u0633\u06cc \u06a9\u06cc \u062d\u0645\u0627\u06cc\u062a \u0646\u06c1\u06cc\u06ba \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u0627\u0646 \u0635\u0648\u0631\u062a\u0648\u06ba \u0645\u06cc\u06ba\u060c \u0645\u0639\u0627\u0641\u06cc \u06a9\u0627 \u0627\u06cc \u0645\u06cc\u0644 \u0628\u06be\u06cc\u062c\u0646\u06d2 \u0627\u0648\u0631 \u062f\u0633\u062a\u06cc \u0631\u0642\u0645 \u06a9\u06cc \u0648\u0627\u067e\u0633\u06cc \u06a9\u06cc \u0642\u0637\u0627\u0631 \u0628\u0646\u0627\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0688\u06cc\u0632\u0627\u0626\u0646 \u06a9\u0631\u06cc\u06ba\u06d4 \u0633\u0627\u06af\u0627\u0633 \u062c\u0633\u0645\u0627\u0646\u06cc \u0627\u0639\u0645\u0627\u0644 \u06a9\u0648 \u06a9\u0627\u0644\u0639\u062f\u0645 \u0646\u06c1\u06cc\u06ba \u06a9\u0631 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<\/li>\n<li>\n<p><strong>\u062f\u0631\u062d\u0642\u06cc\u0642\u062a\u060c \u0627\u0628\u06be\u06cc \u062a\u06a9 \u0648\u06c1\u0627\u06ba \u0628\u06c1\u062a \u0633\u0627\u0631\u06cc \u062e\u062f\u0645\u0627\u062a \u0645\u0648\u062c\u0648\u062f \u0646\u06c1\u06cc\u06ba \u06c1\u06cc\u06ba\u06d4<\/strong> \u06cc\u06a9 \u0633\u0646\u06af\u06cc \u06a9\u06cc \u06a9\u06c1\u0627\u0646\u06cc \u0627\u0648\u0648\u0631 \u0627\u0646\u062c\u06cc\u0646\u0626\u0631\u0646\u06af \u0645\u06cc\u06ba \u0633\u06d2 \u0627\u06cc\u06a9 \u06c1\u06d2\u06d4 \u0633\u0631\u0648\u0633 \u0628\u0627\u0624\u0646\u0688\u0631\u06cc \u062d\u0642\u06cc\u0642\u06cc \u06c1\u0648\u0646\u06d2 \u062a\u06a9 \u0627\u0646\u062a\u0638\u0627\u0631 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<\/li>\n<\/ul>\n<p>Saga \u0631\u06cc\u0627\u0633\u062a\u06cc \u0645\u06cc\u0632\u06cc\u06ba\u060c \u0645\u0631\u062d\u0644\u06c1 \u0648\u0627\u0631 \u0627\u0646\u0639\u0627\u0645 \u06a9\u06d2 \u0637\u0631\u06cc\u0642\u06d2\u060c \u0627\u0648\u0631 \u06a9\u0627\u0645 \u06a9\u06cc \u0639\u0627\u062f\u0627\u062a \u06a9\u0627 \u0633\u0631\u0627\u063a \u0644\u06af\u0627\u062a\u0627 \u06c1\u06d2\u06d4 <code>sagaId<\/code>. \u06cc\u06c1 \u0642\u06cc\u0645\u062a \u0627\u062f\u0627 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0642\u0627\u0628\u0644 \u06c1\u06d2 \u062c\u0628 \u0645\u062a\u0628\u0627\u062f\u0644 \u06cc\u062a\u06cc\u0645 \u0688\u06cc\u0679\u0627 \u06c1\u0648\u060c \u062c\u0648 \u067e\u06c1\u0644\u06d2 \u0646\u06c1\u06cc\u06ba \u062a\u06be\u0627\u06d4<\/p>\n<h2 id=\"heading-15-trade-offs-and-lessons-learned\">15. \u062a\u062c\u0627\u0631\u062a \u0627\u0648\u0631 \u0627\u0633\u0628\u0627\u0642<\/h2>\n<p>\u0627\u0633 \u0688\u06cc\u0632\u0627\u0626\u0646 \u0645\u06cc\u06ba \u06a9\u06cc\u0627 \u0627\u0686\u06be\u0627 \u06a9\u0627\u0645 \u06c1\u0648\u0627:<\/p>\n<ul>\n<li>\n<p>\u06c1\u0645 \u0648\u0642\u062a \u0633\u0627\u0632 \u0622\u0631\u06a9\u06cc\u0633\u0679\u0631\u06cc\u0634\u0646 \u06a9\u0648\u0631\u06cc\u0648\u06af\u0631\u0627\u0641\u06cc \u0633\u06d2 \u0688\u06cc\u0628\u06af \u06a9\u0631\u0646\u0627 \u0622\u0633\u0627\u0646 \u06c1\u06d2\u06d4 \u0627\u06cc\u06a9 \u0646\u06cc\u0627 \u0627\u0646\u062c\u06cc\u0646\u0626\u0631 \u0627\u06cc\u06a9 \u0641\u0627\u0626\u0644 \u067e\u0691\u06be\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u067e\u0648\u0631\u06d2 \u0628\u06c1\u0627\u0624 \u06a9\u0648 \u0633\u0645\u062c\u06be\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<\/li>\n<li>\n<p>\u0634\u0631\u06a9\u0627\u0621 \u06a9\u06cc \u0634\u0646\u0627\u062e\u062a \u0646\u0627\u0642\u0627\u0628\u0644 \u0633\u0645\u062c\u06be\u0648\u062a\u06c1 \u06c1\u06d2\u06d4 \u0622\u0631\u06a9\u06cc\u0633\u0679\u0631\u06cc\u0679\u0631 \u06a9\u06cc \u06a9\u0648\u0634\u0634\u06cc\u06ba \u0645\u062d\u0641\u0648\u0638 \u06c1\u0648\u0646\u06cc \u0686\u0627\u06c1\u0626\u06cc\u06ba\u06d4 \u067e\u06c1\u0644\u06d2 \u062f\u0646 \u0633\u06d2 \u062a\u0639\u0645\u06cc\u0631 \u06a9\u0631\u06cc\u06ba\u06d4 \u062a\u0628\u062f\u06cc\u0644\u06cc\u0627\u06ba \u062a\u06a9\u0644\u06cc\u0641 \u062f\u06c1 \u06c1\u06cc\u06ba\u06d4<\/p>\n<\/li>\n<li>\n<p>\u0633\u0627\u06af\u0627 \u0679\u06cc\u0628\u0644 \u0642\u0628\u0627\u0626\u0644\u06cc \u0639\u0644\u0645 \u06a9\u06cc \u062c\u06af\u06c1 \u0644\u06d2 \u0644\u06cc\u062a\u0627 \u06c1\u06d2\u06d4 \u0627\u0646\u062a\u0638\u0627\u0645\u06cc\u06c1 \u062c\u0648\u0627\u0628 \u062f\u06d2 \u0633\u06a9\u062a\u06cc \u06c1\u06d2\u06d4 <em>\"\u0627\u0633 \u0633\u0627\u0626\u0646 \u0627\u067e \u06a9\u0627 \u06a9\u06cc\u0627 \u06c1\u0648\u0627\u061f\"<\/em> \u0627\u06cc\u06a9 \u0648\u0627\u062d\u062f SQL \u0627\u0633\u062a\u0641\u0633\u0627\u0631 \u06a9\u06d2 \u0633\u0627\u062a\u06be\u06d4 \u06a9\u0633\u06cc \u0648\u0627\u0642\u0639\u06d2 \u06a9\u06cc \u0635\u0648\u0631\u062a \u0645\u06cc\u06ba\u060c \u067e\u06d2 \u0644\u0648\u0688 JSONB \u0633\u0648\u0646\u0627 \u06c1\u06d2\u06d4<\/p>\n<\/li>\n<li>\n<p><code>sagaId<\/code>    \u0679\u0631\u06cc\u06a9\u0646\u06af \u06a9\u06cc\u0632 OpenTelemetry\/Datadog\/Loki \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0627\u0686\u06be\u06cc \u0637\u0631\u062d \u06a9\u0627\u0645 \u06a9\u0631\u062a\u06cc \u06c1\u06cc\u06ba\u060c \u0644\u06c1\u0630\u0627 \u0622\u067e \u06a9\u0648 \u06a9\u0648\u0626\u06cc \u0627\u0636\u0627\u0641\u06cc \u0627\u0646\u0641\u0631\u0627\u0633\u0679\u0631\u06a9\u0686\u0631 \u062a\u0631\u062a\u06cc\u0628 \u062f\u06cc\u0646\u06d2 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4<\/p>\n<\/li>\n<\/ul>\n<p>\u0627\u0633 \u067e\u06cc\u0679\u0631\u0646 \u06a9\u0648 \u06a9\u0627\u067e\u06cc \u06a9\u0631\u0646\u06d2 \u0633\u06d2 \u067e\u06c1\u0644\u06d2 \u0622\u067e \u06a9\u0648 \u062c\u0627\u0646\u0646\u06d2 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06c1\u06d2:<\/p>\n<ul>\n<li>\n<p>\u0645\u0639\u0627\u0648\u0636\u06c1 \u062f\u06cc\u0646\u06d2 \u0645\u06cc\u06ba \u0646\u0627\u06a9\u0627\u0645\u06cc \u0628\u062f\u062a\u0631\u06cc\u0646 \u0635\u0648\u0631\u062a \u062d\u0627\u0644 \u06c1\u06d2\u06d4 \u0627\u06af\u0631 <code>compensateAgencyAccount<\/code> \u0627\u06af\u0631 \u062e\u0648\u062f \u06c1\u06cc \u06a9\u0648\u0626\u06cc \u062e\u0631\u0627\u0628\u06cc \u06c1\u0648 \u062c\u0627\u0626\u06d2 \u062a\u0648 \u0631\u06cc\u0627\u0633\u062a \u0645\u062a\u0636\u0627\u062f \u06c1\u0648 \u062c\u0627\u0626\u06d2 \u06af\u06cc\u06d4 \u062f\u0648\u0628\u0627\u0631\u06c1 \u06a9\u0648\u0634\u0634\u06cc\u06ba + \u0645\u0631\u062f\u06c1 \u062d\u0631\u0648\u0641 + \u0645\u06cc\u0646\u0648\u0626\u0644 \u0631\u0648\u0644 \u0628\u06cc\u06a9 \u0627\u06cc\u0646\u0688 \u067e\u0648\u0627\u0626\u0646\u0679\u0633 \u06a9\u06d2 \u0644\u0626\u06d2 \u0634\u0631\u0648\u0639 \u0633\u06d2 \u0645\u0646\u0635\u0648\u0628\u06c1 \u0628\u0646\u0627\u0626\u06cc\u06ba\u06d4<\/p>\n<\/li>\n<li>\n<p>\u063a\u06cc\u0631 \u0627\u06c1\u0645 \u0627\u0642\u062f\u0627\u0645\u0627\u062a \u06a9\u0648 \u0648\u0627\u0636\u062d \u0637\u0648\u0631 \u067e\u0631 \u0646\u0634\u0627\u0646 \u0632\u062f \u06a9\u06cc\u0627 \u062c\u0627\u0646\u0627 \u0686\u0627\u06c1\u0626\u06d2\u06d4 \u06cc\u06c1\u0627\u06ba \u062e\u0648\u0634 \u0622\u0645\u062f\u06cc\u062f \u0627\u06cc \u0645\u06cc\u0644 \u06a9\u0648 \u0627\u06cc\u062c\u0646\u0633\u06cc \u06a9\u06d2 \u0631\u0648\u0644 \u0628\u06cc\u06a9 \u06a9\u06d2 \u0628\u063a\u06cc\u0631 \u0646\u0627\u06a9\u0627\u0645 \u06c1\u0648\u0646\u06d2 \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u06c1\u06d2\u06d4 \u063a\u06cc\u0631 \u0645\u0633\u062a\u062d\u06a9\u0645 SMTP \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0646\u0646\u062f\u06c1 \u06a9\u0648 \u063a\u0644\u0637\u06cc \u0633\u06d2 \u0645\u0639\u0627\u0648\u0636\u06c1 \u0646\u06c1 \u062f\u06cc\u06ba\u06d4<\/p>\n<\/li>\n<li>\n<p>\u0633\u0627\u06af\u0627\u0633 \u0645\u0642\u0627\u0645\u06cc \u062a\u062c\u0627\u0631\u062a \u06a9\u06cc \u062c\u06af\u06c1 \u0646\u06c1\u06cc\u06ba \u0644\u06cc\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u06c1\u0631 \u0633\u0631\u0648\u0633 \u06a9\u06d2 \u0627\u0646\u062f\u0631 \u06c1\u0645 \u0627\u0628 \u0628\u06be\u06cc \u0627\u0635\u0644 DB \u0679\u0631\u0627\u0646\u0632\u06cc\u06a9\u0634\u0646 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u06cc\u06c1 \u06a9\u06c1\u0627\u0646\u06cc \u0635\u0631\u0641 \u06a9\u0631\u0627\u0633 \u0633\u0631\u0648\u0633 \u0633\u06cc\u0648\u0646 \u06a9\u0648 \u06c1\u06cc\u0646\u0688\u0644 \u06a9\u0631\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<\/li>\n<li>\n<p>\u06c1\u0645 \u0648\u0642\u062a \u0633\u0627\u0632 gRPC \u0622\u0633\u0627\u0646 \u06c1\u06d2 \u0644\u06cc\u06a9\u0646 \u062f\u0633\u062a\u06cc\u0627\u0628\u06cc \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0645\u0644 \u06a9\u0631 \u06c1\u06d2\u06d4 \u0627\u06af\u0631 <code>auth-service<\/code> \u06cc\u06c1 \u0646\u06cc\u0686\u06d2 \u06c1\u06d2 \u0627\u0648\u0631 \u0627\u06cc\u062c\u0646\u0633\u06cc \u06a9\u06cc \u062a\u062e\u0644\u06cc\u0642 \u0646\u0627\u06a9\u0627\u0645 \u06c1\u0648\u062c\u0627\u062a\u06cc \u06c1\u06d2\u06d4 \u062c\u06cc \u0622\u0631 \u067e\u06cc \u0633\u06cc \u06a9\u0627\u0644\u0632 \u06a9\u0648 \u0627\u06cc\u06a9 \u067e\u0627\u0626\u06cc\u062f\u0627\u0631 \u0645\u06cc\u0633\u062c \u0628\u0633 (RabbitMQ\/Kafka) \u0633\u06d2 \u0628\u062f\u0644\u06cc\u06ba \u0627\u0648\u0631 \u062c\u0628 \u0632\u06cc\u0627\u062f\u06c1 \u0644\u0686\u06a9 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06c1\u0648 \u062a\u0648 \u06c1\u0631 \u0642\u062f\u0645 \u06a9\u0648 \u06a9\u0645\u0627\u0646\u0688 + \u0631\u0633\u067e\u0627\u0646\u0633 \u06a9\u06d2 \u0637\u0648\u0631 \u067e\u0631 \u062f\u06cc\u06a9\u06be\u06cc\u06ba\u06d4<\/p>\n<\/li>\n<li>\n<p>\u0622\u0631\u06a9\u06cc\u0633\u0679\u0631\u06cc\u0679\u0631 \u0627\u06cc\u06a9 \u0627\u06c1\u0645 \u062e\u062f\u0645\u062a \u0628\u0646 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4 \u06c1\u0645 \u0627\u0633\u06cc \u06a9\u06d2 \u0645\u0637\u0627\u0628\u0642 \u0627\u067e \u0679\u0627\u0626\u0645 \u0633\u0646\u0628\u06be\u0627\u0644\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u0627\u06af\u0631 \u062e\u0644\u0644 \u067e\u0691\u062a\u0627 \u06c1\u06d2 \u062a\u0648 \u0633\u0627\u06af\u0627 \u06a9\u06cc \u0645\u062f\u062a \u0627\u0648\u0631 \u0627\u0646\u062a\u0628\u0627\u06c1\u0627\u062a \u06a9\u06cc \u0646\u06af\u0631\u0627\u0646\u06cc \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 <code>COMPENSATING<\/code> \u0627\u06cc\u06a9 \u0642\u0637\u0627\u0631 \u0645\u0646\u062a\u062e\u0628 \u06a9\u0631\u06cc\u06ba \u0627\u0648\u0631 \u0627\u06cc\u06a9 \u0633\u06d2 \u0632\u06cc\u0627\u062f\u06c1 \u0646\u0642\u0644 \u0686\u0644\u0627\u0626\u06cc\u06ba\u06d4<\/p>\n<\/li>\n<\/ul>\n<h2 id=\"heading-16-conclusion\">16. \u0646\u062a\u06cc\u062c\u06c1<\/h2>\n<p>\u0633\u0627\u06af\u0627 \u067e\u06cc\u0679\u0631\u0646 \u062c\u0627\u062f\u0648 \u0646\u06c1\u06cc\u06ba \u06c1\u06cc\u06ba. \u06cc\u06c1 \u0627\u0633 \u06a9\u0627 \u0627\u06cc\u06a9 \u0633\u062e\u062a \u0648\u0631\u0698\u0646 \u06c1\u06d2 \u062c\u0648 \u06c1\u0646\u0631 \u0645\u0646\u062f \u0627\u0646\u062c\u06cc\u0646\u0626\u0631 \u067e\u06c1\u0644\u06d2 \u06c1\u06cc \u06c1\u0627\u062a\u06be \u0633\u06d2 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 <em>\u0645\u0642\u0627\u0645\u06cc \u0637\u0648\u0631 \u067e\u0631 \u0627\u0631\u062a\u06a9\u0627\u0628 \u06a9\u0631\u0646\u06d2 \u06a9\u0627 \u0637\u0631\u06cc\u0642\u06c1 \u0633\u06cc\u06a9\u06be\u06cc\u06ba\u060c \u0622\u067e \u0646\u06d2 \u06a9\u06cc\u0627 \u06a9\u06cc\u0627 \u06c1\u06d2 \u0627\u0633 \u067e\u0631 \u0644\u0627\u06af \u0627\u0646 \u06a9\u0631\u06cc\u06ba\u060c \u0627\u0648\u0631 \u0627\u0633\u06d2 \u06a9\u0627\u0644\u0639\u062f\u0645 \u06a9\u0631\u06cc\u06ba\u06d4<\/em><\/p>\n<p>NestJS \u06a9\u06d2 \u0633\u0627\u062a\u06be Node.js \u06a9\u0648 \u0635\u0631\u0641 \u062a\u06cc\u0646 \u0639\u0646\u0627\u0635\u0631 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06c1\u06d2:<\/p>\n<ol>\n<li>\n<p><strong>\u0631\u06cc\u0627\u0633\u062a\u06cc \u0645\u06cc\u0632<\/strong> \u06a9\u06c1\u0627\u0646\u06cc \u06a9\u0648 \u0679\u0631\u06cc\u06a9 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<\/li>\n<li>\n<p><strong>\u0622\u0631\u06a9\u06cc\u0633\u0679\u0631\u06cc\u0679\u0631<\/strong> \u0648\u0631\u06a9 \u0641\u0644\u0648 \u06a9\u0648 \u0686\u0644\u0627\u0626\u06cc\u06ba \u0627\u0648\u0631 \u0627\u0633 \u06a9\u06cc \u062d\u06cc\u062b\u06cc\u062a \u0644\u06a9\u06be\u06cc\u06ba\u06d4<\/p>\n<\/li>\n<li>\n<p><strong>\u0634\u0631\u06cc\u06a9<\/strong> \u06cc\u06c1 \u06c1\u06d2 <code>do<\/code> \u0627\u0648\u0631 <code>undo<\/code> \u0686\u0627\u0628\u06cc\u0627\u06ba \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06c1 \u0628\u06d2 \u062d\u0633\u06cc \u0627\u0648\u0631 \u0622\u067e\u0631\u06cc\u0634\u0646 <code>sagaId<\/code>.<\/p>\n<\/li>\n<\/ol>\n<p>\u0627\u0646 \u062a\u06cc\u0646\u0648\u06ba \u0686\u06cc\u0632\u0648\u06ba \u06a9\u0648 \u062f\u0631\u0633\u062a \u06a9\u0631\u0646\u06d2 \u0633\u06d2 \u0645\u0627\u0626\u06cc\u06a9\u0631\u0648 \u0633\u0631\u0648\u0633\u0632 \u06a9\u0648 \u062a\u0642\u0633\u06cc\u0645 \u0634\u062f\u06c1 \u062a\u0627\u0644\u06d2 \u06a9\u06cc \u0648\u062c\u06c1 \u0633\u06d2 \u067e\u06cc\u062f\u0627 \u06c1\u0648\u0646\u06d2 \u0648\u0627\u0644\u06cc \u0622\u067e\u0631\u06cc\u0634\u0646\u0644 \u0645\u0634\u06a9\u0644\u0627\u062a \u06a9\u06d2 \u0628\u063a\u06cc\u0631\u060c \u06cc\u06a9 \u0633\u0646\u06af\u06cc \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u06a9\u06cc \u0637\u0631\u062d \"\u0633\u0628 \u06cc\u0627 \u06a9\u0686\u06be \u0646\u06c1\u06cc\u06ba\" \u06a9\u0627 \u0627\u062d\u0633\u0627\u0633 \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u0645\u0644\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<p>\u0633\u0627\u062f\u06c1 \u0634\u0631\u0648\u0639 \u06a9\u0631\u06cc\u06ba\u060c \u0622\u0631\u06a9\u06cc\u0633\u0679\u0631\u06cc\u0634\u0646 \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u06cc\u06ba\u060c \u062a\u0645\u0627\u0645 \u0627\u0642\u062f\u0627\u0645\u0627\u062a \u06a9\u0648 \u063a\u06cc\u0631\u0645\u0639\u0645\u0648\u0644\u06cc \u0628\u0646\u0627\u0626\u06cc\u06ba\u060c \u06a9\u0627\u0644 \u06a9\u0631\u0646\u06d2 \u0633\u06d2 \u067e\u06c1\u0644\u06d2 \u0688\u0679\u06d2 \u0631\u06c1\u06cc\u06ba\u060c \u0627\u0648\u0631 \u06c1\u0645\u06cc\u0634\u06c1 \u062c\u0627\u0646\u06cc\u06ba \u06a9\u06c1 \u06a9\u06cc\u0633\u06d2 \u06a9\u0627\u0644\u0639\u062f\u0645 \u06a9\u0631\u0646\u0627 \u06c1\u06d2\u06d4 \u06cc\u06c1 \u0633\u0627\u0631\u0627 \u0646\u0645\u0648\u0646\u06c1 \u06c1\u06d2\u06d4<\/p>\n<\/p><\/div>\n","protected":false},"excerpt":{"rendered":"<p>\u0645\u062a\u0639\u062f\u062f \u0645\u0627\u0626\u06cc\u06a9\u0631\u0648 \u0633\u0631\u0648\u0633\u0632 \u0645\u06cc\u06ba \u0642\u0627\u0628\u0644 \u0627\u0639\u062a\u0645\u0627\u062f \u0648\u0631\u06a9 \u0641\u0644\u0648 \u0628\u0646\u0627\u0646\u0627 \u0645\u0634\u06a9\u0644 \u06c1\u06d2\u06d4 \u06cc\u06a9 \u0633\u0646\u06af\u06cc \u0645\u06cc\u06ba\u060c \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u06a9\u06d2 \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u0627\u0633 \u0628\u0627\u062a \u06a9\u0648 \u06cc\u0642\u06cc\u0646\u06cc \u0628\u0646\u0627 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba \u06a9\u06c1 \u0645\u062a\u0639\u062f\u062f \u0622\u067e\u0631\u06cc\u0634\u0646\u0632 \u0627\u06cc\u06a9 \u0633\u0627\u062a\u06be \u06a9\u0627\u0645\u06cc\u0627\u0628 \u06c1\u0648\u06ba \u06cc\u0627 \u0646\u0627\u06a9\u0627\u0645 \u06c1\u0648\u06ba\u06d4 \u062a\u0627\u06c1\u0645\u060c \u062c\u0628 \u0688\u06cc\u0679\u0627 \u0645\u062a\u0639\u062f\u062f \u0633\u0631\u0648\u0633\u0632 \u0627\u0648\u0631 \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u0645\u06cc\u06ba \u067e\u06be\u06cc\u0644 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u060c \u062a\u0648 \u06cc\u06c1 \u06af\u0627\u0631\u0646\u0679\u06cc \u063a\u0627\u0626\u0628 \u06c1\u0648 \u062c\u0627\u062a\u06cc \u06c1\u06d2\u06d4 [&hellip;]<\/p>\n","protected":false},"author":7,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[1],"tags":[],"class_list":["post-25318","post","type-post","status-publish","format-standard","hentry","category-blog"],"_links":{"self":[{"href":"https:\/\/umang.pk\/ur\/wp-json\/wp\/v2\/posts\/25318","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/umang.pk\/ur\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/umang.pk\/ur\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/umang.pk\/ur\/wp-json\/wp\/v2\/users\/7"}],"replies":[{"embeddable":true,"href":"https:\/\/umang.pk\/ur\/wp-json\/wp\/v2\/comments?post=25318"}],"version-history":[{"count":0,"href":"https:\/\/umang.pk\/ur\/wp-json\/wp\/v2\/posts\/25318\/revisions"}],"wp:attachment":[{"href":"https:\/\/umang.pk\/ur\/wp-json\/wp\/v2\/media?parent=25318"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/umang.pk\/ur\/wp-json\/wp\/v2\/categories?post=25318"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/umang.pk\/ur\/wp-json\/wp\/v2\/tags?post=25318"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}